【问题标题】:Scanf unknown number of string arguments CScanf 未知数量的字符串参数 C
【发布时间】:2017-05-02 21:14:38
【问题描述】:

我想知道是否有使用 scanf 的方法,这样我就可以接收未知数量的字符串参数并将它们放入 char* 数组中。我已经看到它是用 int 值完成的,但找不到用 char 数组完成它的方法。参数也在同一行输入,用空格分隔。

示例: 用户输入hello goodbye yeshello 存储在array[0] 中,goodbyearray[1]yesarray[2]。或者用户可以只输入hello,然后数组中唯一的就是hello

我真的没有任何代码要发布,因为我不知道该怎么做。

【问题讨论】:

    标签: c arrays char scanf


    【解决方案1】:

    您可以执行类似的操作,直到 "\n" 为止:

    scanf("%[^\n]",buffer);

    您需要事先分配足够大的缓冲区。

    现在通过缓冲区计算字数,并分配必要的空间char **array = ....(dynamic string allocation),转到缓冲区并将字符串逐个字符串复制到数组中。

    一个例子:

    int words = 1;
    char buffer[128];
    int result = scanf("%127[^\n]",buffer);
    
    if(result > 0)
    {
        char **array;
    
        for(int i = 0; buffer[i]!='\0'; i++)
        {
           if(buffer[i]==' ' || buffer[i]=='\n' || buffer[i]=='\t')
           {
            words++;
           }
        }
    
       array = malloc(words * sizeof(char*));
    
       // Using RoadRunner suggestion
      array[0] = strtok (buffer," ");
      for(int w = 1; w < words; w++)
      {
         array[w] = strtok (NULL," ");
      }
    }
    

    如 cmets 中所述,您应该使用(如果可以)fgets 而不是 fgets(buffer,128,stdin);。 更多关于strtok

    【讨论】:

      【解决方案2】:

      如果您对可能从用户那里收到的字符串数以及每个字符串中的字符数设置了上限,并且所有字符串都在一行中输入,则可以通过以下步骤执行此操作:

      • fgets()阅读全文,
      • 使用sscanf() 转换说明符的最大数量的格式字符串解析带有sscanf() 的行。

      这是一个最多 10 个字符串的示例,每个字符串最多 32 个字符:

          char buf[400];
          char s[10][32 + 1];
          int n = 0;
      
          if (fgets(buf, sizeof buf, sdtin)) {
              n = sscanf("%32s%32s%32s%32s%32s%32s%32s%32s%32s%32s",
                         s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9]));
          }
          // `n` contains the number of strings
          // s[0], s[1]... contain the strings
      

      如果单个字符串的最大长度不固定,或者如果字符串可以在连续的行中输入,则如果不知道最大数量,则需要使用简单的循环进行迭代:

          char buf[200];
          char **s = NULL;
          int n;
      
          while (scanf("%199s", buf) == 1) {
              char **s1 = realloc(s, (n + 1) * sizeof(*s));
              if (s1 == NULL || (s1[n] = strdup(buf)) == NULL) {
                  printf("allocation error");
                  exit(1);
              }
              s = s1;
              n++;
          }
          // `n` contains the number of strings
          // s[0], s[1]... contain pointers to the strings
      

      除了错误处理之外,此循环与上面的硬编码示例相当,但它仍然具有每个字符串的最大长度。除非您可以使用 scanf() 扩展来自动分配字符串(在 GNU 系统上为 %as),否则处理任意长度的任意数量的字符串会更加复杂。

      【讨论】:

        【解决方案3】:

        你可以使用:

        • fgets 读取用户的输入。使用它而不是 scanf 会更轻松。
        • malloc 为堆上的指针分配内存。您可以使用起始尺寸,如下例所示:

          size_t currsize = 10
          char **strings = malloc(currsize * sizeof(*strings)); /* always check
                                                                   return value */
          

          当空间超出时,realloc 需要更多空间:

          currsize *= 2;
          strings = realloc(strings, currsize * sizeof(*strings)); /* always check
                                                                      return value */
          
        • 使用完从malloc()realloc() 请求的内存后,最好将指针放在末尾的free

        • strtok 在每个空格处解析输入。从strtok() 复制char * 指针时,还必须为strings[i] 分配空间,使用malloc()strdup

        这是我不久前写的一个例子,它做的事情与你想要的非常相似:

        #include <stdio.h>
        #include <stdlib.h>
        #include <string.h>
        
        #define INITSIZE 10
        #define BUFFSIZE 100
        
        int
        main(void) {
            char **strings;
            size_t currsize = INITSIZE, str_count = 0, slen;
        
            char buffer[BUFFSIZE];
            char *word;
            const char *delim = " ";
            int i;
        
            /* Allocate initial space for array */
            strings = malloc(currsize * sizeof(*strings));
            if(!strings) {
                printf("Issue allocating memory for array of strings.\n");
                exit(EXIT_FAILURE);
            }
        
            printf("Enter some words(Press enter again to end): ");
            while (fgets(buffer, BUFFSIZE, stdin) != NULL && strlen(buffer) > 1) {
        
                /* grow array as needed */
                if (currsize == str_count) {
                    currsize *= 2;
                    strings = realloc(strings, currsize * sizeof(*strings));
                    if(!strings) {
                        printf("Issue reallocating memory for array of strings.\n");
                        exit(EXIT_FAILURE);
                    }
                }
        
                /* Remove newline from fgets(), and check for buffer overflow */
                slen = strlen(buffer);
                if (slen > 0) {
                    if (buffer[slen-1] == '\n') {
                        buffer[slen-1] = '\0';
                    } else {
                        printf("Exceeded buffer length of %d.\n", BUFFSIZE);
                        exit(EXIT_FAILURE);
                    }
                }
        
                /* Parsing of words from stdin */
                word = strtok(buffer, delim);
                while (word != NULL) {
        
                    /* allocate space for one word, including nullbyte */
                    strings[str_count] = malloc(strlen(word)+1);
                    if (!strings[str_count]) {
                        printf("Issue allocating space for word.\n");
                        exit(EXIT_FAILURE);
                    }
        
                    /* copy strings into array */
                    strcpy(strings[str_count], word);
        
                    str_count++;
                    word = strtok(NULL, delim);
                }
            }
        
            /* print and free strings */
            printf("Your array of strings:\n");
            for (i = 0; i < str_count; i++) {
                printf("strings[%d] = %s\n", i, strings[i]);
                free(strings[i]);
                strings[i] = NULL;
            }
        
            free(strings);
            strings = NULL;
        
            return 0;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2023-03-04
          • 2016-11-11
          • 1970-01-01
          • 1970-01-01
          • 2016-08-16
          • 2011-01-14
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多