【问题标题】:Iterating through a string and separating input by spaces in C遍历字符串并用 C 中的空格分隔输入
【发布时间】:2023-03-10 13:45:01
【问题描述】:

我有一个字符串,例如“first second”,我想要的结果就是这个输出:

first 
second

但我得到的输出是:

first
first second

我知道我的更新语句或创建子字符串时存在问题。如果有人可以帮助我,那就太好了。下面是我的代码:

int counter = 0; //counter used in loop
int index = test->current_index; //holds the current index of my string, it's initially 0
char *string = test->myString; //holds the whole string

char token_buffer = string[index];

   //before loop: index = 0, counter = 0

   while(test->current_index <= test->end_index) //test->end_index holds last index of string

    {
       while(token_buffer != ' ')
       {
         counter++;
         token_buffer = string[index + counter];

       }    

    char *output_token = malloc(counter+1);


   strncpy( output_token, string, counter );

  //printing token
  printf("%s \n", output_token);


 //update loop (possible problem area!)
  test->current_index += counter;
  index += counter;
  token_buffer+=string[counter];
  counter =0;
  }

return 0;
}

【问题讨论】:

  • 我猜,strncpy( output_token, string, counter ); 会出现错误,因为string 只会在第一个字符的地址处。使用strncpy( output_token, string[index], counter );
  • 另外,为什么要添加到 token_buffer? token_buffer+=string[counter];

标签: c string loops pointers


【解决方案1】:

有许多方法可以将字符串拆分为用空格分隔它们的标记。诀窍是让它尽可能高效和合理地健壮,而不会过度复杂化。两种基本方法是使用(1)“英寸蠕虫”方法(简单地使用 2 个指针,一个开始和结束指针,一次处理一个字符的字符串,或者(2)使用其中一个libc 提供的标记函数(例如strtokstrsep)。

使用 inch-worm 方法,您拥有完全的控制权和竞争灵活性,但是在您向下处理字符串时,由 跟踪每个指针指向的位置。 (熟悉这种方法的一个好方法是在 paper 上编写您要解析的字符串,并根据需要手动推进指针 - 随时编写您的例程)。一个例子:

char *string = test->myString; //holds the whole string
char *p = string;

while (*p)                      /* while not end of string */
{
    char *sp = p;                  /* set a start pointer */
    while (*p && *p != ' ') p++;   /* advance to space    */
    char *output_token = malloc (p - sp + 1); /* allocate */
    strncpy (output_token, sp, p - sp);         /* copy   */
    output_token[p - sp] = 0;   /* force null-termination */
    printf("   %s\n", output_token); 
    free (output_token);           /* free if not needed  */
    while (*p && *p == ' ') p++;   /* find next non-space */
}

第二种方法使用strtok 来做基本相同的事情。 注意:您可以随意在分隔符字符串中放置任意数量的字符,并且对于strtok 的每次调用,它们不要求使用相同的字符。这可以提供很大的灵活性。一个例子:

char *string = test->myString; //holds the whole string
char *p = string;   /* pointer to string */
char *tok = NULL;   /* pointer to token  */

for (tok = strtok (p, " "); tok; tok = strtok (NULL, " \n"))
{
    char *output_token = strdup (tok);  /* allocate & copy at once */
    printf("   %s\n", output_token);
    free (output_token);
}

如果您想通过一个示例来比较两者,一个简短的示例可能如下所示:

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

int main (int argc, char **argv) {

    // char *string = test->myString; //holds the whole string
    char *string = argc > 1 ? argv[1]: "some string with spaces";

    printf ("\n With pointer arithmetic:\n\n");

    char *p = string;
    while (*p)                     /* while not end of string */
    {
        char *sp = p;                  /* set a start pointer */
        while (*p && *p != ' ') p++;    /* advance to space   */
        char *output_token = malloc (p - sp + 1); /* allocate */
        strncpy (output_token, sp, p - sp);         /* copy   */
        output_token[p - sp] = 0;   /* force null-termination */
        printf("   %s\n", output_token); 
        free (output_token);           /* free if not needed  */
        while (*p && *p == ' ') p++;   /* find next non-space */
    }


    printf ("\n With strtok:\n\n");

    p = string;
    char *tok = NULL;      /* pointer to each token in string */

    /* using strtok to separate string into tokens at spaces  */
    for (tok = strtok (p, " "); tok; tok = strtok (NULL, " \n"))
    {
        char *output_token = strdup (tok);
        printf("   %s\n", output_token);
        free (output_token);
    }

    return 0;
}

示例/输出

$ ./bin/charbufsplit "This is a longer string with many more  spaces"

 With pointer arithmetic:

   This
   is
   a
   longer
   string
   with
   many
   more
   spaces

 With strtok:

   This
   is
   a
   longer
   string
   with
   many
   more
   spaces

【讨论】:

    【解决方案2】:

    问题似乎在于对strncpy 的调用。 与:

    strncpy( output_token, string, counter );
    

    您正在复制output_tokenstring 开头的第一个counter 字符。要调用strncpy,您最常将源字符串移动到current_index。比如:

    strncpy( output_token, (char*)(string+test->current_index), counter );
    

    在循环结束时。

    【讨论】:

      【解决方案3】:

      您的代码中有两个错误:

      1. strncpy中,每次复制到output_token时,都是从string的起始地址开始复制的。
      2. while 循环条件token_buffer != ' '。由于在字符串的末尾,您没有空格,因此您的计数器将继续增加并超过 test-&gt;end_index,直到它读取一个空格。

      更正:

      counter = 0;
      token_buffer = string[counter+index];
      while(token_buffer != ' ' && (index+counter)<=test->end_index) //since counter is always set to zero before this loop executes.
      {
          counter++;
          token_buffer = string[index+counter];
      }
      
      char *output_token = calloc(counter+1);
      strncpy(output_token,string+index,counter);
      printf("%s \n", output_token);
      counter++;    //This is required since when the loop exit, counter would be at the position of ' '.
      test->current_index += counter;
      index += counter;
      

      将此添加到您的主 while 循环中。

      【讨论】:

      • 感谢您帮助我,非常感谢。我将我的 strncpy 替换为:strncpy( output_token, string, counter ),但似乎在每个不是第一个标记的标记之前都会打印一个空格。我找不到这个愚蠢的错误来自哪里。我将内部 while 循环条件更改为:while((token_buffer != ' ') && (counterend_index)) 并且我认为这已经解决了您发现的第二个问题。
      • 哇,这对我的学习过程有很大帮​​助,可以看到我以前代码的更精简版本。再次感谢 Rakholiya Jenish。
      • 您可能需要注意strncpy 手册页中的警告。 "警告: 如果 src 的前 n 个字节中没有空字节,则放在 dest 中的字符串不会以空值结尾。" (有很多方法可以解决这个问题,其中两种是 (1) 手动 null 终止;或 (2) 使用 calloc 而不是 malloc)。
      • 感谢@DavidC.Rankin,这是我不知道的事情。
      猜你喜欢
      • 1970-01-01
      • 2020-04-24
      • 1970-01-01
      • 1970-01-01
      • 2013-09-24
      • 1970-01-01
      • 1970-01-01
      • 2018-02-13
      相关资源
      最近更新 更多