Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
自写C函数拆分字符串时出错_C_String_Loops - Fatal编程技术网

自写C函数拆分字符串时出错

自写C函数拆分字符串时出错,c,string,loops,C,String,Loops,几周前我刚刚学习了字符串,我对自己的函数很感兴趣。起初我试了一个短句,效果不错,但当我试了一个长句时遇到了一个问题 问题可能在“getSplitText”函数中,如何修复此错误 在这种情况下使用for循环是否不好 以前 之后 这是我的密码 #include <stdio.h> #include <stdlib.h> char *getSplitText(char *var_text, char split, int index); int getLengthSpli

几周前我刚刚学习了字符串,我对自己的函数很感兴趣。起初我试了一个短句,效果不错,但当我试了一个长句时遇到了一个问题

问题可能在“getSplitText”函数中,如何修复此错误

在这种情况下使用for循环是否不好

以前

之后

这是我的密码

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

char *getSplitText(char *var_text, char split, int index);
int getLengthSplitText(char *var_text, char split);
int getLengthString(char *var_text);

int main(){
    char var_text[100];
    fgets(var_text,100,stdin);
    int i;
    printf("Total Characters: %d\n",getLengthString(var_text));
    printf("Total Words: %d\n",getLengthSplitText(var_text,' '));
    printf("Split Result:\n");
    for(i=1;i<=getLengthSplitText(var_text,' ');i++){
        printf("#%d-%s\n",i,getSplitText(var_text,' ',i));
    }

   return 0;
}

int getLengthString(char *var_text){
    int len = 0, i = 0;
    while (var_text[i] != '\0'){
        len++;
        i++;
    }
    return len;
}

int getLengthSplitText(char *var_text, char split){

    int textlen = getLengthString(var_text);
    int lenKata=0;
    char *resultKata = malloc(sizeof(char) * textlen);
    resultKata[0]='\0';
    int i,j=0;
    for(i=0;i<textlen;i++){

        if(var_text[i]!=split){

            if(textlen-1==i){
                resultKata[j] = var_text[i];
                resultKata[j + 1] = '\0';
                lenKata ++;
            }else {
                resultKata[j] = var_text[i];
                j++;
                resultKata[j + 1] = '\0';
            }
            //printf("#1 %s\n",resultKata);

        }else if(var_text[i]==split){

            if(resultKata[0]!='\0'){
                lenKata ++;
                }else{
                    j = 0;
                    resultKata[0] = '\0';
                }
            }
            //printf("#2 %s\n",resultKata);
        }
    return lenKata;
    }

char *getSplitText(char *var_text,char split, int index){

    int textlen = getLengthString(var_text);
    char *resultKata = malloc(sizeof(char) * textlen);
    resultKata[0]='\0';

    if(index<=getLengthSplitText(var_text,split)) {
        int i,j=0;
        int lenKata=0;

        for (i = 0; i < textlen; i++) {

            if (var_text[i] != split) {

                if (textlen - 1 == i) {
                    resultKata[j] = var_text[i];
                    resultKata[j + 1] = '\0';
                    lenKata++;
                    break;
                } else {
                    resultKata[j] = var_text[i];
                    j++;
                    resultKata[j + 1] = '\0';
                }
                //printf("#1 %s\n",resultKata);

            } else if (var_text[i] == split) {

                if (resultKata[0] != '\0') {
                    lenKata++;
                    if (lenKata == index) {
                        resultKata[j] = '\0';
                        break;
                    } else {
                        j = 0;
                        resultKata[0] = '\0';
                    }
                }
                //printf("#2 %s\n",resultKata);
            }
        }
    }
    return resultKata;
}
#包括
#包括
char*getSplitText(char*var_text,char split,int index);
int getLengthSplitText(char*var_text,char split);
int getLengthString(字符*var_文本);
int main(){
char var_text[100];
fgets(变量文本,100,标准文本);
int i;
printf(“总字符数:%d\n”,getLengthString(var_text));
printf(“总字数:%d\n”,getLengthSplitText(var_text,”);
printf(“分割结果:\n”);

对于(i=1;i在OP的代码中出现了大量的
malloc()

关于已经提出的意见:

  • 将任何值乘以1都没有效果,只会使代码变得混乱。建议删除该表达式
  • 嗯,这是风格的问题。如果它提高或削弱代码的可读性是个人喜好的问题。我假设编译器足够聪明,可以忽略1的乘法,我也会忽略

  • 函数:
    malloc()
    需要类型为:
    size\u t
    的参数,但
    textlen
    声明为
    int
  • 虽然我同意,但只要提供的
    int
    值为正值,我不认为这是一个临界点

  • 始终检查(!=NULL)返回值以确保操作成功
  • 这也是我的建议

    我个人感到恼火的是,代码中有一些
    malloc()
    s,但没有一个
    free()
    。使用
    malloc()
    分配内存意味着,一些堆内存在内部堆内存管理器中被标记为“正在使用”。如果它不是
    free()
    d,它将被标记为“已使用”直到进程生命周期结束。丢失(例如重写)指向已分配内存的指针会使其丢失。(无法再次寻址)。这称为

    当然,在公开的示例代码中,这并不是一个关键问题,但在堆内存消耗较多的大型应用程序中,它可能会成为一个关键问题

    整个示例似乎类似于使用标准库函数可以完成的操作

    (并不是说你误解了我的意思。我不认为出于学习目的而与标准函数相似有什么不好的地方。)

    getLengthString()
    实际上没有什么问题。但是,它管理两个计数变量
    i
    len
    。OP可能忽略了它们在每个迭代步骤后始终具有相同的值。因此,其中一个是冗余的,可以消除:

    int getLengthString(char *var_text)
    {
      int len = 0;
      while (var_text[len]) ++len;
      return len;
    }
    
    关于
    getLengthSplitText()
    (负责计算单词数),我不明白为什么需要任何
    malloc()
    。因此,我编写了一个新函数
    getNumTokens()
    ,它计算由某个拆分字符分隔的非空单词(我称它们为“标记”):

    int getNumTokens(char *var_text, char split)
    {
      int n = 0;
      for (int inToken = 0; *var_text; ++var_text) {
        if (!inToken && *var_text != split) ++n; // count if new token starts
        inToken = *var_text != split; // update flag
      }
      return n;
    }
    
    它有点短,不需要任何
    malloc()

    请注意变量
    inToken
    ,它实际上用作(布尔)标志。它负责记住在对文本进行迭代时是否已对令牌进行计数。它在每个迭代步骤中都会通过指定当前字符(
    *var_text
    )和分隔符(
    split
    )的比较结果进行更新

    提供的
    var_text
    直接用于访问和进度–不使用额外的索引。由于只需要对文本进行一次迭代,因此更改指针不会造成任何影响。它是一个本地副本(按值传递),函数内部的生存时间有限

    关于strtok()
    ,我曾经写过一个变体作为答案

    有两个事实需要注意:

  • strtok()
    通过将分隔符替换为
    \0
    字节来修改输入字符串(以分隔找到的标记)

  • strtok()
    管理使其不可重入的内部全局状态

  • 通过使用
    malloc()
    (考虑到上面提到的所有问题),OP的解决方案似乎没有这些限制

    所以,我稍微改变了一些假设(实际上OPs问题中没有提到限制)。我认为对输入(1)的修改是可以接受的,并编写了一个新函数
    getNextToken()

    函数将返回
    var\u text
    中第一个标记的开头。如果它是空字符串(返回指针的内容是
    \0
    ),则找不到任何标记。 因此,找到标记的结尾用
    \0
    -字节(在给定的输入字符串中)表示,该字节可能是之前的拆分字符

    由于我不想要全局内部状态,我必须在
    getNextToken()
    之外从一个令牌移动到另一个令牌。我发现这是可以接受的,因为可以再次使用函数
    getLengthString()
    来完成。这样,指针就可以从令牌的开始移动到结束处(写入了
    \0
    -字节)。添加1,则到达下一个令牌的可能开始。当然,当到达文本结尾时,这可能会中断(终止符
    \0
    后面的地址可能超出范围)。幸运的是,令牌的数量已经已知

    完整样本:

    #include <stdio.h>
    
    int getLengthString(char *var_text);
    int getNumTokens(char *var_text, char split);
    char* getNextToken(char *var_text, char split);
    
    int main()
    {
      char var_text[100];
      if (!fgets(var_text, 100, stdin)) {
        fprintf(stderr, "Input failed!\n");
        return -1;
      }
      printf("Total Characters: %d\n", (int)getLengthString(var_text));
      const char split = ' ';
      const int nTokens = getNumTokens(var_text, split);
      printf("Total Words: %d\n", nTokens);
      printf("Split Result:\n");
      char *token = var_text;
      for (int i = 1; i <= nTokens; ++i) {
        token = getNextToken(token, split);
        printf("#%2d-%s\n", i, token);
        token += getLengthString(token) + 1;
      }
      return 0;
    }
    
    int getLengthString(char *var_text)
    {
      int len = 0;
      while (var_text[len]) ++len;
      return len;
    }
    
    int getNumTokens(char *var_text, char split)
    {
      int n = 0;
      for (int inToken = 0; *var_text; ++var_text) {
        if (!inToken && *var_text != split) ++n; // count if new token starts
        inToken = *var_text != split; // update flag
      }
      return n;
    }
    
    char* getNextToken(char *var_text, char split)
    {
      // skip space
      for (; *var_text && *var_text == split; ++var_text);
      // remember start of token
      char *token = var_text;
      // skip token
      for (; *var_text && *var_text != split; ++var_text);
      // remark end of token
      *var_text = '\0'; // doesn't hurt if there is already a '\0'
      // done
      return token;
    }
    
    的输出谢谢您的帮助。现在,代码可以工作了。我喜欢编程。

    字符总数:68
    字总数:13
    拆分结果:
    #1-谢谢
    #2-you
    #3人
    #4-1
    #5-help。
    #6-现在,
    #7-1
    #8码
    #9罐
    #10-w
    
    #include <stdio.h>
    
    int getLengthString(char *var_text);
    int getNumTokens(char *var_text, char split);
    char* getNextToken(char *var_text, char split);
    
    int main()
    {
      char var_text[100];
      if (!fgets(var_text, 100, stdin)) {
        fprintf(stderr, "Input failed!\n");
        return -1;
      }
      printf("Total Characters: %d\n", (int)getLengthString(var_text));
      const char split = ' ';
      const int nTokens = getNumTokens(var_text, split);
      printf("Total Words: %d\n", nTokens);
      printf("Split Result:\n");
      char *token = var_text;
      for (int i = 1; i <= nTokens; ++i) {
        token = getNextToken(token, split);
        printf("#%2d-%s\n", i, token);
        token += getLengthString(token) + 1;
      }
      return 0;
    }
    
    int getLengthString(char *var_text)
    {
      int len = 0;
      while (var_text[len]) ++len;
      return len;
    }
    
    int getNumTokens(char *var_text, char split)
    {
      int n = 0;
      for (int inToken = 0; *var_text; ++var_text) {
        if (!inToken && *var_text != split) ++n; // count if new token starts
        inToken = *var_text != split; // update flag
      }
      return n;
    }
    
    char* getNextToken(char *var_text, char split)
    {
      // skip space
      for (; *var_text && *var_text == split; ++var_text);
      // remember start of token
      char *token = var_text;
      // skip token
      for (; *var_text && *var_text != split; ++var_text);
      // remark end of token
      *var_text = '\0'; // doesn't hurt if there is already a '\0'
      // done
      return token;
    }