编译器如何为C中的字符串数组分配内存?

时间:2019-03-06 19:16:31

标签: c

我输入了该代码块进行作业:

char *tokens[10];

void parse(char* input);

void main(void) 
{
    char input[] = "Parse this please.";
    parse(input);

    for(int i = 2; i >= 0; i--) {
        printf("%s ", tokens[i]);
    }
}

void parse(char* input)
{
    int i = 0;
    tokens[i] = strtok(input, " ");

    while(tokens[i] != NULL) {
        i++;
        tokens[i] = strtok(NULL, " ");
    }
}

但是,看着它,我不确定内存分配是如何工作的。据我所知,我没有定义单个字符串的长度,而是定义字符串数组标记(10)中有多少个字符串。我有这个倒退吗?如果不是,那么编译器是否动态分配每个字符串的长度?需要澄清。

2 个答案:

答案 0 :(得分:2)

strtok是坏公民。

一方面,它会保留状态,就像您在调用strtok(NULL,...)时所隐式使用的那样-该状态存储在Standard C库的私有内存中,这意味着仅单线程程序可以使用{ {1}}。请注意,某些库中有一个称为strtok的可重入版本。

要回答另一个问题,请strtok_r修改其输入。它不会为字符串分配空间。它会在输入字符串中写入NUL字符代替定界符,并在输入字符串中返回一个指针。

您正确的认为strtok可以返回10个以上的结果。您应该在代码中进行检查,以免超出strtok的结尾。可靠的程序可以设置上限,例如您的tokens,并检查上限,如果超出则报告错误,或者动态地将10数组与tokens和{{ 1}},如果它太大。当您的内存不足时,就会发生错误。

请注意,在将输入字符串传递给malloc之前,您还可以通过realloc来解决strtok修改输入字符串的问题。然后,在新字符串和指向它的strdup超出范围后,必须释放新字符串。

答案 1 :(得分:1)

tokens是一个指针数组。

字符串和指针之间的区别(如果经常模糊的话)。在某些情况下,最好将字符串视为数组,而在其他情况下,最好将其视为指针。

无论如何...在您的示例中,input是一个数组,而tokens是一个指向input中某个位置的指针的数组。

每次调用input都会更改strtok()中的数据

所以,一步一步

// input[] = "foo bar baz";
tokens[0] = strtok(input, " ");
// input[] = "foo\0bar baz";
//            ^-- tokens[0] points here
tokens[1] = strtok(NULL, " ");
// input[] = "foo\0bar\0baz";
//                 ^-- tokens[1] points here
tokens[2] = strtok(NULL, " ");
// input[] = "foo\0bar\0baz";
//                      ^-- tokens[2] points here
// next strtok returns NULL