如何在C语言中将字符串输入到数组中?

4

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

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

5
在任何基础的C语言书籍或教程中都会涵盖这个基本任务。同时,搜索引擎可以为你带来无数学习文章。在发布新问题之前,请进行基本的研究。请查看编译器的提示信息。它应该会有警告。阅读警告并尝试理解其意思,修复代码以至少不再出现任何警告,使得程序能够成功编译。 - kaylum
4
根据回答,我开始质疑评论的第一部分 :) - David C. Rankin
我重新打开了这个问题,不仅关乎如何读取未分配字符串的内容,还涉及如何将行读入数组等问题... - Antti Haapala -- Слава Україні
7个回答

10

在这行代码中:

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 */

使用fgets作为另一种不需要scanf的方法

一个更加恰当的读取字符串的方式应该使用fgets函数。

char *fgets(char *str, int n, FILE *stream)从输入流中读取一行,并将字节复制到char *str中,该缓冲区必须被给定一个大小为n字节的阈值。

需要注意的事项:

  • 在缓冲区的末尾添加了\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 */

带有注释的示例代码:

#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

3
在这个领域似乎存在一些混淆。你的主要问题是试图将每个单词写入你用char *word[3]声明的每个指针的地址上。(更不用说你根本没有在每个指针所指向的位置分配存储空间--但你从未到达过那里,因为你试图将每个指针的地址&word[i]一起写入,而不是直接写入指针本身)。
虽然你可以使用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" 命令时。 - Spikatrix
是的,说得好。一般来说,只有Windows终端提供了最大的问题。那些在Linux上的人通常更熟悉(除非使用IDE,否则可能从)终端编译。但为了完整起见,您可以删除#if#endif预处理器条件,并使代码在退出之前等待按键。 (或使用__linux__测试宏显式测试操作系统) - David C. Rankin

0

你正在声明一个指针数组 (char *word[3];)。你需要分配内存来存储数据。在赋值之前,使用malloc或类似的函数来分配内存。


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

首先输入数组的大小,然后逐个输入所有元素。 - GouravKotnala
1
你试过运行这段代码吗?它并没有真正地工作。 - kirjosieppo

0
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
 }

0

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

例如:

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);

-2
代码 char *word [3] 创建了一个由3个指针元素组成的数组!
你可以看到,你基本上创建了一个字符指针数组,所以你不能将“字符串”放入其中的每一个,因为指针变量的类型是长十六进制数。

提供存储空间并使用指针引用它,然后在其中存储字符串是没有问题的。 - David C. Rankin
抱歉,我匆忙回答了!对不起。 - Satyam Raj
在C语言中没有类型为“任何十六进制数”。 - alk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接