【问题标题】:How to input strings into an array in C?如何将字符串输入到C中的数组中?
【发布时间】:2017-05-21 22:40:07
【问题描述】:

我试图从用户那里获取输入(字符串)并将它们存储在一个数组中。但是在我运行这段代码之后,程序立即崩溃了。

#include <stdio.h>
int main() {
    int i;
    char *word[3];
    for(i=0;i<3;i++)
    {
        printf(" Enter a word: ");
        scanf("%s", &word[i]);
    }
    printf("%s ", word[0]);
    return 0;
}

【问题讨论】:

  • 这个基本任务在任何基本的 C 书籍或教程中都有介绍,而且搜索将带来无数的文章,你可以学习。请在发布新问题之前进行基础研究。请看编译器告诉你什么。它应该有警告。阅读警告,尝试理解它们告诉你的内容并修复它们,以便至少你的程序编译时没有任何警告。
  • 根据答案,我开始质疑该评论的第一部分:)
  • 我重新打开了这个问题,这不仅仅是只是读取未分配字符串的问题,而是如何将行读入数组等...

标签: c arrays string pointers


【解决方案1】:

在这一行:

scanf("%s", &word[i]);

您需要确保word[i] 指向某个地方,并且有足够的空间来占用输入的字符串。由于word[i]char * 指针,因此您有时需要为此分配内存。否则,它只是一个不指向任何地方的悬空指针。

如果你想坚持scanf(),那么你可以预先分配一些空间malloc

malloc() 在堆上分配请求的内存,然后在最后返回一个void* 指针。

您可以像这样在代码中应用malloc()

size_t malloc_size = 100;

for (i = 0; i < 3; i++) {
    word[i] = malloc(malloc_size * sizeof(char)); /* allocates 100 bytes */
    printf("Enter word: ");
    scanf("%99s", word[i]); /* Use %99s to avoid overflow */
                            /* No need to include & address, since word[i] is already a char* pointer */
} 

注意:必须检查malloc()的返回值,因为不成功时可以返回NULL

此外,每当您使用malloc() 分配内存时,您必须在最后使用free 来释放请求的内存:

free(word[i]);
word[i] = NULL; /* safe to make sure pointer is no longer pointing anywhere */

另一种不用 scanf 的方法

更正确的读取字符串的方法应该是使用fgets

char *fgets(char *str, int n, FILE *stream) 从输入流中读取一行,并将字节复制到char *str,它必须指定n 字节的大小作为它可以占用的空间阈值。

关于 fget 的注意事项:

  • 在缓冲区末尾追加\n 字符。可以轻松移除。
  • 出错时返回NULL。如果没有读取任何字符,最后仍然返回NULL
  • 缓冲区必须以给定大小静态声明n
  • 读取指定的流。来自stdinFILE *

这是一个示例,说明如何使用它从stdin 读取一行输入:

char buffer[100]; /* statically declared buffer */

printf("Enter a string: ");
fgets(buffer, 100, stdin); /* read line of input into buffer. Needs error checking */

使用 cmets 的示例代码:

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

#define NUMSTR 3
#define BUFFSIZE 100

int main(void) {
    char *words[NUMSTR];
    char buffer[BUFFSIZE];
    size_t i, count = 0, slen; /* can replace size_t with int if you prefer */

    /* loops only for three input strings */
    for (i = 0; i < NUMSTR; i++) {

        /* read input of one string, with error checking */
        printf("Enter a word: ");
        if (fgets(buffer, BUFFSIZE, stdin) == NULL) {
            fprintf(stderr, "Error reading string into buffer.\n");
            exit(EXIT_FAILURE);
        }

        /* removing newline from buffer, along with checking for overflow from buffer */
        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);
            }
        } 

        /* checking if nothing was entered */
        if (!*buffer) {
            printf("No string entered.\n");
            exit(EXIT_FAILURE);
        }

        /* allocate space for `words[i]` and null terminator */
        words[count] = malloc(strlen(buffer)+1);

        /* checking return of malloc, very good to do this */
        if (!words[count]) {
            printf("Cannot allocate memory for string.\n");
            exit(EXIT_FAILURE);
        }

        /* if everything is fine, copy over into your array of pointers */
        strcpy(words[count], buffer);

        /* increment count, ready for next space in array */
        count++;
    }  

    /* reading input is finished, now time to print and free the strings */
    printf("\nYour strings:\n");
    for (i = 0; i < count; i++) {
        printf("words[%zu] = %s\n", i, words[i]);
        free(words[i]);
        words[i] = NULL;
    }

    return 0;
}

示例输入:

Enter a word: Hello
Enter a word: World
Enter a word: Woohoo

输出:

Your strings:
words[0] = Hello
words[1] = World
words[2] = Woohoo

【讨论】:

    【解决方案2】:

    这方面似乎有些混乱。您的主要问题是您试图将每个单词写入您使用char *word[3]; 声明的每个指针的地址。 (更不用说您在每个指针指向的位置没有分配存储空间——但是当您尝试使用 &amp;word[i] 而不是写入每个指针的 地址 时,您永远不会到达那里指针本身)

    虽然您可以使用scanf,但您很快就会遇到使用scanf 获取用户输入的众多陷阱之一,这会困扰所有新的C 程序员(例如无法处理输入中留下的'\n'缓冲区未能处理字符串中的空格未能限制读取/写入的字符数未能验证读取或处理 EOF、等...)

    更好的方法是简单地使用fgets,然后修剪fgets 读取的'\n',并将其包含在存储字符串的缓冲区中。一个简单的例子是:

    #include <stdio.h>
    #include <string.h>
    
    #define NWDS 3    /* declare a constant for the maximum number of words */
    
    int main (void) {
    
        int i, n = 0;
        char word[NWDS][50] = { "" };       /* provide storage or allocate */
    
        for (i = 0; i < NWDS; i++) {        /* for a max of NWDS */
            printf ("Enter word : ");       /* prompt */
            if (!fgets (word[i], sizeof word[i], stdin))  /* read/validate */
                break;                      /* protect against EOF */
            size_t len = strlen (word[i]);  /* get length */
            if (word[i][len-1] == '\n')     /* check for trailing '\n' */
                word[i][--len] = 0;         /* overwrite with nulbyte  */
        }
        n = i;                              /* store number of words read */
        putchar ('\n');                     /* make it pretty */
    
        for (i = 0; i < n; i++)             /* output each word read */
            printf (" word[%d] : %s\n", i, word[i]);
    
    #if (defined _WIN32 || defined _WIN64)
        getchar();  /* keep terminal open until keypress if on windows */
    #endif
    
        return 0;
    }
    

    通过在输入过程中生成EOF(在 Linux 上为 ctrl + d 或在 windows 上为 ctrl + z)来继续并随时取消输入,您将被覆盖.

    使用/输出示例

    $ ./bin/wordsread
    Enter word : first word
    Enter word : next word
    Enter word : last word
    
     word[0] : first word
     word[1] : next word
     word[2] : last word
    

    仔细查看,考虑其他答案,如果您还有其他问题,请告诉我。

    【讨论】:

    • 为什么是#if (defined _WIN32 || defined _WIN64)?程序执行后终端也可能在linux中关闭,对吗?即通过 GUI 或使用terminal -e "./bin/wordsread" 运行程序时。
    • 是的,说得好。不过,一般来说,只有 Windows 终端提供了最大的问题。 Linux 上的用户通常更熟悉终端(除非使用 IDE,否则可能是从终端编译的)。但为了完整起见,您可以删除 #if#endif 预处理器条件,并让代码在退出前等待按键。 (或使用__linux__ 测试宏显式测试操作系统)
    【解决方案3】:
    char *word[3]; // <-- this is an array of 3 dangling pointers, of type char*
    // they still point nowhere, we later need to set them to some allocated location.
     ...
     for(i=0;i<3;i++) {
         word[i] = malloc(some_max_size * sizeof(char)); // <-- allocate space for your word
         printf(" Enter a word: ");
         scanf("%s", word[i]); // <-- not &word[i]; word[i] is already a char* pointer
     }
    

    【讨论】:

      【解决方案4】:

      您将 word 声明为指针数组 (char *word[3];)。您必须分配内存来存储数据。在赋值之前用malloc或类似函数分配内存。

      【讨论】:

        【解决方案5】:

        是的,代码崩溃是因为声明了一个字符数组 指针是不够的,你需要设置指针指向 到可以存储字符串的内存中。

        例如

        const int maxLen = 32;
        char* word[3] = {NULL,NULL,NULL};
        
        word[i] = malloc(maxLen);
        

        然后从键盘读取字符串,确保字符串不会太 长期使用 fgets 和 maxLen:

        printf("Enter a word:");
        fgets(word[i],maxLen,stdin);
        

        【讨论】:

          【解决方案6】:
          #include <stdio.h>
          int main(){
          int n;
          int i=0;
          scanf("%d",&n);
          char arr[n];
          while(n>i){
              scanf("%s",&arr[i]);
              i+=1;
              }
          while(n-i<n){
          printf(" %c ",arr[n-i]);
          i-=1;
              }
          }
          

          【讨论】:

          • 先输入数组的大小,然后逐个输入所有元素
          • 您是否尝试运行此代码?真的不行。
          【解决方案7】:

          代码char *word[3] 生成了一个三元素指针数组!

          你看,你基本上已经创建了一个指针的字符数组,所以你不能把一个“字符串”放到每个指针中,因为指针变量的类型是长十六进制。

          【讨论】:

          • 提供存储,并用指针对其进行引用,然后在其中存储一个字符串并没有错。
          • 哎呀..赶紧回答!对不起
          • C 中没有类型“whatever hexadecimal”。
          猜你喜欢
          • 1970-01-01
          • 2015-05-23
          • 1970-01-01
          • 2015-10-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-12-30
          相关资源
          最近更新 更多