为什么我不能重新分配这个字符串?

时间:2016-01-02 20:14:44

标签: c string pointers struct null-terminated

我有这样的结构:

typedef struct TEXT {
    char *text;
    struct TEXT *next;
} TEXT;

在某些功能中我有类似的东西:

TEXT *line = (TEXT *) malloc(sizeof(TEXT));
line->text = NULL; // was "\0" before
char current = getchar();
while (current != '\n') {
    AddChar(&(line->text), current); // Was AddChar(line->text, current);
    current = getchar();
}

并且AddChar函数是这样的:

void AddChar(char **text, char c) { //was char *text
    *text = (char *) realloc(*text, strlen(*text)+2); //was text = ...
    char char_array[2] = {c, '\0'); 
    strcat(*text, char_array); //was strcat(text, char_array);
}

不幸的是,程序崩溃了。

据我了解,事实证明strlen无法弄清楚如果text == NULL,则长度应为0 ...

无论如何,使用这个AddChar函数,一切正常:

void AddChar(char **text, char c) {
    if (*text == NULL) {
        *text = (char *) malloc(2);
        (*text)[0] = c;
        (*text)[1] = '\0';
    }
    else {
        *text= (char *) realloc(*text, sizeof(*text)+2);
        char char_array[2] = { c , '\0' };
        strcat(*text, char_array);
    }
}

我也遇到了问题

void AddChar(char *text, char c) {
    text = "something";
}

不更改line->文本,但将* text更改为**文本修复了该文本。

4 个答案:

答案 0 :(得分:4)

只有NULL初始化指针或malloc家庭函数(malloccallocrealloc)返回的指针才能传递给另一个{{} 1}}家庭功能。 malloc初始化时使用字符串文字line->text,因此"\0"无法传递给line->text函数。
另请注意,您无法修改字符串文字。

答案 1 :(得分:2)

其中一个问题是你试图重新分配你自己没有分配的东西。

另一个问题是你试图在AddChar函数中重新分配一个局部变量,并期望它对调用函数产生任何影响,而不是。

当一个参数传递给一个函数时,它通过值传递 ,这意味着该值被复制到函数中的局部参数变量中,该变量仅在函数内局部变化,并且不会更改更改调用函数时使用的原始变量。你需要的是通过引用传递参数,而C不支持,但你可以使用指针模拟它。在您的情况下,通过使用address-of运算符&来指向指针。

答案 2 :(得分:0)

  

据我了解,事实证明strlen无法弄清楚如果text == NULL,则长度应为0 ...

另一方面,section 7.1.4, paragraph 1 C标准声明NULL是strlen的无效值:

  

如果函数的参数具有无效值(例如函数域外的值,或程序地址空间外的指针,或空指针,或者当相应参数不是const限定时指向不可修改存储的指针)或者具有可变数量参数的函数不期望的类型(提升之后),行为是未定义的。

虽然我们关注的是无效值,但strcat会期望它的两个参数都包含字符串。这意味着它们必须包含一个终止于第一个'\0'字符的字符序列。您已通过在表示第二个参数的数组中添加'\0'字符来证明这一点,但是您能否证明数组中的'\0'字符代表您的第一个参数?

*text = (char *) realloc(*text, strlen(*text)+2);

除了空指针,模式x = realloc(x, ...);的任何内容都是错误的。有关详细信息,请参阅Proper usage of realloc

*text= (char *) realloc(*text, sizeof(*text)+2);

至于此,它起初似乎对你有用,但我可以向你保证它已经坏了。重要的是要意识到您打算分配字符而不是char * s,因此sizeof(*text)sizeof (char *)}在此处无效。

通常这会分配6到10个字符。如果溢出该缓冲区,则行为未定义。那是什么意思?嗯,定义未定义的行为是一个悖论,但未定义行为的典型后果包括"什么都没有"并且"它工作正常"对于某些系统来说,"段错误"和#34; heartbleed"对于其他系统;尽管如此,它仍然不便携。

  

我也遇到了问题

void AddChar(char *text, char c) {
    text = "something";
}
     

不更改line->文本,但将* text更改为**文本修复了该文本。

我很好奇你认为AddChar(NULL, 42);会做什么,当AddChar被定义为这样的时候......你认为它会分配空指针常量吗? NULL"something"的字符串文字?

C不支持传递引用。传递参数时(例如,指针,例如隐式转换为指针的数组表达式),幕后发生的事情是声明新变量(在本例中为参数{ {1}}是一个变量)并且该值的副本(在本例中为指针)被分配给该变量。这被称为"按值传递"。

当您传递指针并修改指针指向的东西时(例如,使用char *text*pointer = ...),您将模拟传递引用;您正在修改变量引用的对象,而不是修改变量本身。

哦,还有一件事,尽管链接到"正确使用pointer[x] = ...",you should not cast the return value of malloc (or `realloc) in C

答案 3 :(得分:0)

不同意OP的决赛"无论如何,使用这个AddChar功能,一切正常:"因为它没有分配足够的内存。

推荐

void AddChar(char **text, char c) {
    size_t length = strlen(*text); 
    *text = realloc(*text, length + 2);  // proper size calculation
    if (*text == NULL) {  // check if successful
      abort(-1);
    } 
    (*text)[length] = c;
    (*text)[length + 1] = '\0';
}