不使用strtok()的字符串标记生成器

我正在编写字符串标记器而不使用strtok()。 这主要是为了我自己的改进和对指针的更好理解。 我想我几乎拥有它,但我一直收到以下错误:

myToc.c:25 warning: assignment makes integer from pointer without a cast myToc.c:35 (same as above) myToc.c:44 error: invalid type argument of 'unary *' (have 'int') 

我正在做的是循环发送到方法的字符串,找到每个分隔符,并用’\ 0’替换它。 “ptr”数组应该具有指向分离的子串的指针。 这就是我到目前为止所拥有的。

 #include  void myToc(char * str){ int spcCount = 0; int ptrIndex = 0; int n = strlen(str); for(int i = 0; i < n; i++){ if(i != 0 && str[i] == ' ' && str[i-1] != ' '){ spcCount++; } } //Pointer array; +1 for \0 character, +1 for one word more than number of spaces int *ptr = (int *) calloc(spcCount+2, sizeof(char)); ptr[spcCount+1] = '\0'; //Used to differentiate separating spaces from unnecessary ones char temp; for(int j = 0; j < n; j++){ if(j == 0){ /*Line 25*/ ptr[ptrIndex] = &str[j]; temp = str[j]; ptrIndex++; } else{ if(str[j] == ' '){ temp = str[j]; str[j] = '\0'; } else if(str[j] != ' ' && str[j] != '\0' && temp == ' '){ /*Line 35*/ ptr[ptrIndex] = &str[j]; temp = str[j]; ptrIndex++; } } } int k = 0; while(ptr[k] != '\0'){ /*Line 44*/ printf("%s \n", *ptr[k]); k++; } } 

我可以看到错误发生的地方,但我不确定如何纠正它们。 我该怎么办? 我正确分配内存还是仅仅是我如何指定地址的问题?

你的指针数组是错误的。 它看起来像你想要的:

 char **ptr = calloc(spcCount+2, sizeof(char*)); 

此外,如果我正确读取您的代码,则不需要空字节,因为此数组不是字符串。

此外,您还需要修复:

 while(ptr[k] != '\0'){ /*Line 44*/ printf("%s \n", *ptr[k]); k++; } 

取消引用不是必需的,如果你删除null ptr,这应该工作:

 for ( k = 0; k < ptrIndex; k++ ){ /*Line 44*/ printf("%s \n", ptr[k]); } 
 #include  #include  #include  void myToc(char * str){ int spcCount = 0; int ptrIndex = 0; int n = strlen(str); for(int i = 0; i < n; i++){ if(i != 0 && str[i] == ' ' && str[i-1] != ' '){ spcCount++; } } char **ptr = calloc(spcCount+2, sizeof(char*)); //ptr[spcCount+1] = '\0';//0 initialized by calloc char temp = ' ';//can simplify the code for(int j = 0; j < n; j++){ if(str[j] == ' '){ temp = str[j]; str[j] = '\0'; } else if(str[j] != '\0' && temp == ' '){//can omit `str[j] != ' ' &&` ptr[ptrIndex++] = &str[j]; temp = str[j]; } } int k = 0; while(ptr[k] != NULL){//better use NULL printf("%s \n", ptr[k++]); } free(ptr); } int main(){ char test1[] = "abc"; myToc(test1); char test2[] = "hello world"; myToc(test2); return 0; } 

更新:我在http://www.compileonline.com/compile_c99_online.php尝试了第25,35和44行的修复程序,以及两次调用myToc()的main函数。 我在尝试将空字符写入str[]时最初遇到了段错误,但这只是因为我传递的字符串是(显然是不可修改的)文字。 当我分配文本缓冲区并在传入它们之前将字符串写入其中时,下面的代码按需工作。此版本也可以修改为返回指针数组,然后指向标记。

(即使字符串参数是不可修改的,下面的代码也可以工作,只要myToc()生成字符串的本地副本;但如果函数的目的是返回列表,那么这将不会产生预期的效果。令牌,而不仅仅是打印它们。)

 #include  #include  #include  void myToc(char * str){ int spcCount = 0; int ptrIndex = 0; int n = strlen(str); for(int i = 0; i < n; i++){ if(i != 0 && str[i] == ' ' && str[i-1] != ' '){ spcCount++; } } //Pointer array; +1 for one word more than number of spaces char** ptr = (char**) calloc(spcCount+2, sizeof(char*)); //Used to differentiate separating spaces from unnecessary ones char temp; for(int j = 0; j < n; j++){ if(j == 0){ ptr[ptrIndex] = &str[j]; temp = str[j]; ptrIndex++; } else{ if(str[j] == ' '){ temp = str[j]; str[j] = '\0'; } else if(str[j] != ' ' && str[j] != '\0' && temp == ' '){ ptr[ptrIndex] = &str[j]; temp = str[j]; ptrIndex++; } } } for (int k = 0; k < ptrIndex; ++k){ printf("%s \n", ptr[k]); } } int main (int n, char** v) { char text[256]; strcpy(text, "abc"); myToc(text); printf("-----\n"); strcpy(text, "hello world"); myToc(text); } 

不过,我更喜欢更简单的代码。 基本上你想要一个指向str[]第一个非空白字符的指针,然后指向一个空白前面的每个非空白(除了第一个)之外的指针。 你的第一个循环几乎得到了这个想法,除了它正在寻找非空白之前的空白。 (也可以在i = 1启动该循环,避免在每次迭代时测试i != 0

我可能只是分配一个大小为sizeof(char*) * (n + 1)/2char*数组来保存指针而不是循环遍历字符串两次(也就是说,我省略了第一个循环,这只是弄清楚数组的大小)。 在任何情况下,如果ptr[0]是非空白的,我会将其地址写入数组; 然后循环for (int j = 1; j < n; ++j) ,如果str[j]为非空并且str[j - 1]为空,则将str[j]的地址写入数组 - 基本上你正在做什么,但辅助变量越少越少。 只要代码干净且有意义,代码越少意味着引入错误的机会就越少。

以前的评论:

int *ptr =声明一个int数组。 对于char的指针数组,您需要

 char** ptr = (char**) calloc(spcCount+2, sizeof(char*)); 

该行之前的评论似乎也表明存在一些混淆。 指针数组中没有终止null,并且您不需要为一个指定空间,因此spcCount+2可能是spcCount + 1

这也是可疑的:

 while(ptr[k] != '\0') 

看起来它会起作用,考虑到你使用calloc的方式(你需要使用spcCount+2来完成这项工作),但是我会觉得写这样的东西会更安全:

 for (k = 0; k < ptrIndex; ++k) 

我不是导致segfault的原因,它只是让我有点不安地比较一个指针( ptr[k] )和\0 (通常你会比较一个char )。