char** splitInput = malloc(255 * sizeof(char*));
...
while(token != NULL)
{
    splitInput[i] = token;
    token = strtok(NULL, " ");
    i++;
}


我不知道为什么这段代码有效。在我以前的版本中

while(token != NULL)
{
    *splitInput = token;
    token = strtok(NULL, " ");
    *splitInput++;
}


但是它什么也没存储。为什么?这两个代码有什么区别?

那就是我如何打印splitInput的内容:

for(; *splitInput != NULL; *splitInput++){
    printf("%s\n", *splitInput);
}


我可以在第一个代码中打印splitInput的内容,但在第二个代码中失败。为什么?

最佳答案

如果还没有整理出来,则其差异是由于使用数组索引和指针算法的差异。使用数组索引时,splitInput指向的地址永远不会更改。

但是,使用后递增运算符时,每次调用splitInput时都将更改*splitInput++的地址。它与调用*splitInput = token; splitInput += 1;相同,因此当完成对输入的标记化时,splitInput指向最后分配的token之后的下一个指针地址。

每当分配内存时,对于分配的任何内存块,您都有2个责任:(1)始终保留指向该内存块起始地址的指针,因此,(2)可以访问该指针,然后在不再需要它时将其释放。您违反了规则(1),该规则将阻止您访问分配的块的开头(并造成永久性的内存泄漏)

你怎么处理呢?要么对分配的令牌数量进行计数,然后通过该数量的指针重置(备份)到块的开头,或者更好,只需将一个单独的指针与后递增运算符一起使用,从而保留原始地址用于splitInput中的存储块。

一个简短的例子将说明:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX 4096

int main (void) {

    /* allocate & initialize */
    char **splitInput = calloc (255, sizeof *splitInput),
        **sp = splitInput,  /* create pointer to splitInput */
        buf[MAX] = "", *delim = " \n";
    int n = 0;

    if (!splitInput) {  /* validate all allocations */
        fprintf (stderr, "error: virtual memory exhausted.\n");
        return 1;
    }

    while (fgets (buf, MAX, stdin)) {
        for (char *p = strtok (buf, delim); p; p = strtok (NULL, delim)) {
            *sp++ = p;
            if (++n == MAX)  /* always protect against writing beyond bounds */
                goto full;
        }
    }
    full:

    for (int i = 0; i < n; i++)
        printf ("splitInput[%3d] : %s\n", i, splitInput[i]);

    free (splitInput);  /* you allocate it --> you free it */

    return 0;
}


输入示例

$ cat dat/fleas
my dog has fleas


使用/输出示例

$ ./bin/ptrinc < dat/fleas
splitInput[  0] : my
splitInput[  1] : dog
splitInput[  2] : has
splitInput[  3] : fleas


当然,使用数组索引,您可以完全删除sp并简单地使用:

    while (fgets (buf, MAX, stdin)) {
        for (char *p = strtok (buf, delim); p; p = strtok (NULL, delim)) {
            splitInput[n++] = p;
            if (n == MAX)
                goto full;
        }
    }


仔细检查一下,如果您还有其他问题,请告诉我。

10-04 20:21