简体   繁体   English

Scanf未知数量的字符串参数C

[英]Scanf unknown number of string arguments C

I wanted to know if there was a way to use scanf so I can take in an unknown number of string arguments and put them into a char* array. 我想知道是否有一种使用scanf的方法,这样我就可以输入数量未知的字符串参数并将它们放入char*数组中。 I have seen it being done with int values, but can't find a way for it to be done with char arrays. 我已经看到它是用int值完成的,但是找不到用char数组完成它的方法。 Also the arguments are entered on the same line separated by spaces. 同样,在同一行中输入参数,并用空格分隔。

Example: user enters hello goodbye yes , hello gets stored in array[0] , goodbye in array[1] and yes in array[2] . 示例:用户输入hello goodbye yeshello被存储在array[0]goodbye存储在array[1]yesarray[2] Or the user could just enter hello and then the only thing in the array would be hello . 或者用户可以只输入hello ,然后数组中唯一的东西就是hello

I do not really have any code to post, as I have no real idea how to do this. 我实际上没有任何代码可发布,因为我不知道如何执行此操作。

You can do something like, read until the "\\n" : 您可以执行类似的操作,直到读取“ \\ n”为止:

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

you need to allocate before hand a big enough buffer. 您需要事先分配足够大的缓冲区。

Now go through the buffer count the number of words, and allocate the necessary space char **array = .... ( dynamic string allocation ), go to the buffer and copy string by string into the array. 现在通过缓冲区计算单词数,并分配必要的空间char **array = ....动态字符串分配 ),转到缓冲区,然后将字符串逐个字符串复制到数组中。

An example: 一个例子:

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," ");
  }
}

As mention in the comments you should use (if you can) fgets instead fgets(buffer,128,stdin); 如评论中所述,您应该(如果可以)使用fgets代替fgets(buffer,128,stdin); . More about strtok 有关strtok的更多信息

If you have an upper bound to the number of strings you may receive from the user, and to the number of characters in each string, and all strings are entered on a single line, you can do this with the following steps: 如果您可以从用户那里接收到的字符串数以及每个字符串中的字符数都有上限,并且所有字符串都在一行中输入,则可以执行以下步骤:

  • read the full line with fgets() , fgets()读取整行,
  • parse the line with sscanf() with a format string with the maximum number of %s conversion specifiers. 使用sscanf()具有格式转换字符串的行,该字符串具有最大数量的%s转换说明符。

Here is an example for up to 10 strings, each up to 32 characters: 以下是最多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

If the maximum number is not known of if the maximum length of a single string is not fixed, or if the strings can be input on successive lines, you will need to iterate with a simple loop: 如果最大数目未知,或者单个字符串的最大长度不确定,或者可以在连续的行中输入字符串,则需要使用一个简单的循环进行迭代:

    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

Aside from the error handling, this loop is comparable to the hard-coded example above but it still has a maximum length for each string. 除了错误处理外,此循环可与上面的硬编码示例进行比较,但每个字符串的最大长度仍为最大。 Unless you can use a scanf() extension to allocate the strings automatically ( %as on GNU systems), the code will be more complicated to handle any number of strings with any possible length. 除非您可以使用scanf()扩展名自动分配字符串(在GNU系统上%as ),否则代码将变得更加复杂,以处理任何数量的任何长度的字符串。

You can use: 您可以使用:

  • fgets to read input from user. fgets读取用户的输入。 You have an easier time using this instead of scanf . 使用此方法而不是使用scanf更轻松。
  • malloc to allocate memory for pointers on the heap. malloc为堆上的指针分配内存。 You can use a starting size, like in this example: 您可以使用起始大小,例如以下示例:

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

    and when space is exceeded, then realloc more space as needed: 并且在超出空间时,根据需要重新realloc更多空间:

     currsize *= 2; strings = realloc(strings, currsize * sizeof(*strings)); /* always check return value */ 
  • When finished using the requested memory from malloc() and realloc() , it's always to good to free the pointers at the end. 当完成使用malloc()realloc()的请求的内存后,最后free指针始终是一件好事。

  • strtok to parse the input at every space. strtok解析每个空间的输入。 When copying over the char * pointer from strtok() , you must also allocate space for strings[i] , using malloc() or strdup . strtok()复制char *指针时,还必须使用malloc()strdupstrings[i]分配空间。

Here is an example I wrote a while ago which does something very similar to what you want: 这是我前一段时间写的一个示例,该示例的功能与您想要的非常相似:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM