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

时间:2014-09-09 19:45:44

标签: c pointers tokenize

我正在编写字符串标记器而不使用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 <string.h>

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++;
   }
}

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

3 个答案:

答案 0 :(得分:3)

指针数组错误。看起来你想要:

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]);
}

答案 1 :(得分:1)

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

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[] = "a b c";
    myToc(test1);
    char test2[] = "hello world";
    myToc(test2);
    return 0;
}

答案 2 :(得分:0)

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

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

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

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, "a b c");
  myToc(text);
  printf("-----\n");
  strcpy(text, "hello world");
  myToc(text);
}

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

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

上一条评论:

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

char

该行之前的评论似乎也表明存在一些混淆。指针数组中没有终止null,并且您不需要为一个指针分配空间,因此char** ptr = (char**) calloc(spcCount+2, sizeof(char*)); 可能是spcCount+2

这也是可疑的:

spcCount + 1

看起来它会起作用,考虑到你使用while(ptr[k] != '\0') (你需要calloc来完成这项工作)的方式,但我觉得写一些东西更安全像这样:

spcCount+2

我不是导致段错误的原因,只是让指针(for (k = 0; k < ptrIndex; ++k) )与ptr[k](通常与{{1}进行比较)的比较让我感到有些不安})。