2017-10-19 132 views
0

我正在尝试为用户输入重新创建一个简单的字符串分析器。我可以在没有问题的情况下获得输入字符串,并确定其中包含多少个单独的字符串,以便将正确的大小正确地赋予malloc。最初,我没有找到stdin中的字符串数量,只是重新分配我的字符串数组,以允许空间再多一个字符串,然后malloc新的字符串。现在我有尺寸,我相信这是没有必要的,因为我可以提供适当大小的malloc。Realloc影响fgets

我是什么混淆,是当我在我的代码留下的realloc没有问题(除了知道它可能会调整我的阵列中(用calloc(),在同一个地点segfaulted未遂)一种不受欢迎的方式)。但是,如果我删除了realloc,我的代码会错误地执行fgets()即时执行。

这就是我称之为解析器和我的#包含的地方。 “appserver.h” 保存所有原型和STD(LIB /布尔/ IO),串/ unistd/limits.h中

#include "appserver.h" 

int main(int argc, char *argv[]) 
{ 
    if(argc != 4) 
    { 
    exit(0); 
    } 
    struct userInput user = { parseInt(*argv[1]), parseInt(*argv[2]), argv[3] }; 

    printf("> "); 
    char **newArgs = stringParser(); 
    for (int i = 0; newArgs[i] != NULL; i++) 
    { 
    free(newArgs[i]); 
    } 
    free(newArgs); 
} 

下面是我的解析器代码。如果我离开realloc uncommented,我可以没有问题地穿过我的代码(在gdb显示“输入”与整个字符串从标准输入),但是,如果我注释掉我segfault正确,因为我尝试检索用户输入fgets( )。为什么注释掉realloc()甚至对fgets()有影响?

char **stringParser() 
{ 
    char *input; 
    fgets(input, INT_MAX, stdin); 
    int size = numberOfStrings(input); 
    char **inputArray = malloc((size)*(sizeof(char*))); 
    inputArray[0] = malloc(sizeof(char*)); 
    strcpy(inputArray[0], strtok(input, " ")); 
    for(int i = 1; i < size /*inputArray[i-1] != NULL*/; i++) 
    { 
    // inputArray = realloc(inputArray, (i+1)*sizeof(char*)); 
    inputArray[i] = malloc(sizeof(char*)); 
    strcpy(inputArray[i], strtok(NULL, " ")); 
    printf("Inside inputArray[%d]: %s\n", i-1, inputArray[i-1]); 
    } 
    return inputArray; 
} 

这里是我的numberOfStrings()方法,以及在这可能是值得探讨该事件的代码,但是,我通过它加强与广发行,以及,似乎很具体。

int numberOfStrings(char *input) 
{ 
    int count = 0; 
    char *tempCopy = malloc(sizeof(char*)); 
    strcpy(tempCopy, input); 
    char* token = strtok(tempCopy, " "); 
    while(token != NULL) 
    { 
    token = strtok(NULL, " "); 
    count++; 
    } 
    free(tempCopy); 
    return count; 
} 


编辑: 我想随动,以确保我已经避免了潜在的不确定行为的大部分地区。 我没有改变主任何东西,所以这里是我在 **stringParser()

char **stringParser() 
{ 
    char *input = nextLine(stdin); 
    int size = numberOfStrings(input, strlen(input)); 
    char **inputArray = calloc(size, sizeof(*inputArray)); 
    char *token = strtok(input, " "); 
    inputArray[0] = malloc(strlen(token)); 
    strcpy(inputArray[0], token); 
    for(int i = 1; i < size - 1; i++) 
    { 
    token = strtok(NULL, " "); 
    inputArray[i] = malloc(strlen(token)); 
    strcpy(inputArray[i], token); 
    } 
    free(input); 
    inputArray[size-1] = (char*)NULL; 
    return inputArray; 
} 

变化的主要方面的变化是:

  • 我用calloc()代替malloc(),但如果我的理解是正确的那么calloc(size, sizeof(*inputArray))表现为相同(忽略'0'或垃圾值初始化)malloc((size)*sizeof(*inputArray))
  • 我的一个朋友写了一个*nextLine(FILE *input),它允许我通过直到达到EOF'\n'。这有利于为用户输入准确分配我需要的内存量。
  • 我确保我的数组中的每个String都只分配了必要的内存量。 (与之前做过的sizeof(char*)相反)
  • 我已经确保在我的String数组的末尾包含一个空终止值。 (我在我刚刚返回语句前加上count++ numberOfStrings()只有一个变化。

这些变化刚才把我带到了一个地步,我不再有任何内存泄漏。我不敢想我已经避免了所有未定义行为的行为,但是,我想我现在在做的更好一些。我一定不会阻塞这个帖子,还有其他一些问题,但是如果有人可能会在这里留下这个更新发现它有用或相关。

+1

请解释'char * tempCopy = malloc(sizeof(char *));' –

+2

'fgets(input,INT_MAX,stdin);':'input'未初始化。 – BLUEPIXY

+0

@ M.M我只是不喜欢把原始整数值,并没有实现一种方式来分配字符串的确切长度。或者如果有任何方法可以做到这一点,我还没有发现它。出于无知,我只使用了sizeof(char *),因为它还没有给我带来任何麻烦。 – Drewzillawood

回答

1

realloc()的呼叫不影响fgets() - 至少,不是直接,可预测或可靠。

stringParser()中的fgets(input, INT_MAX, stdin)的第一个呼叫具有未定义的行为,因为指针input未初始化。

实际上,fgets()的调用可能会覆盖它不应该存储的某个区域。

通过添加(或注释掉)realloc()的调用,结果将会调整程序使用的内存布局(例如,更改代码或数据是否位于被内存位置覆盖的位置fgets())。

但这并不是因为realloc()直接影响fgets()。这只是调用realloc()改变程序中的某些内容的一个副作用。

注释掉realloc()调用或重新插入它的效果可能是任何事情。例如,如果您的代码是使用不同的编译器设置(如优化标志)或甚至不同的编译器构建的,则可能会得到不同的效果。

为了消除与fgets()传阵列

char input[some_positive_value]; 
    fgets(input, sizeof(input), stdin); 

问题或初始化指针在合适的缓冲液以指向。

char *input = malloc(some_positive_value); /* remember to `free()` when done */ 
    fgets(input, some_positive_value, stdin); 

注意循环,如上所述,确实需要realloc()呼叫

// inputArray = realloc(inputArray, (i+1)*sizeof(char*)); 
inputArray[i] = malloc(sizeof(char*)); 

没有realloc()通话,分配给inputArray[i]也会有不确定的行为。如果你没有看到这种症状,那么你就很幸运 - 再次,这是一种你不能依赖的影响。

检查各种功能(fgets()realloc()等)实际上是否成功也是一个好主意。您的代码正在进行基于假设这些函数都按预期工作的假设,但如果它们失败(例如,如果内存重新分配由realloc()失败),则行为将不确定。