将多个字符串作为输入时不必要的换行符

Unnecessary new line character while taking multiple strings as input

我编写了一个小代码来将多个字符串作为用户输入。在此之前,我要求用户输入要作为输入的字符串数。当以字符串作为输入时,换行符自动占据第一个字符串的位置。我不知道发生了什么:( 这是我的代码:

#include<stdio.h>
#include<string.h>
void main()
{
    char *arr[20],str[40];
    int n;
    printf("enter the number of strings\n");
    scanf("%d",&n);
    int i;
    printf("Enter the strings\n");[It isn't taking 3 strings as input,as a newline character is already occupying first place][1]
    for(i=0;i<n;i++)
    {
        gets(str);
        arr[i]=(char *)malloc(sizeof str);
        strcpy(arr[i],str);
    }
    printf("The Strings are:\n");
    for(i=0;i<n;i++)
    {
        printf(arr[i]);
        printf("\n");
    }
}

当您使用scanf 读取位数时,它只处理输入的数字,而不是您输入数字后按的回车。

刷新输入的其余部分可能是值得的,例如 How to clear input buffer in C?

gets() 函数应从标准输入流 stdin 读取字节到 s 指向的数组中,直到读取 <newline> 或遇到文件结束条件。

所以每当你输入之后

enter the number of strings

5

因此,如果您按回车键,则会调用 gets,它会将新行作为第一个输入。

如果您没有输入 enter 并按 5abc 然后再输入,那么它会将 abc 视为第一个字符串。

您需要在 gets 之前清除缓冲区。

你的正确程序是

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void main()
{
        char *arr[20],str[40];
        int n;
        int ch;
        printf("enter the number of strings\n");
        scanf("%d",&n);
        int i;
        printf("Enter the strings\n");
        //flush the input stream
        while ((ch = getchar()) != '\n' && ch != EOF);
        for(i=0;i<n;i++)
        {
                gets(str);
                arr[i]=(char *)malloc(sizeof str);
                strcpy(arr[i],str);
        }
        printf("The Strings are:\n");
        for(i=0;i<n;i++)
        {
                printf("%s",arr[i]);
                printf("\n");
        }
}

根据评论,您的代码中存在许多问题。首先 gets,不要使用它,这是 'hanging' 的冒犯 -- 说得够多了。

接下来,验证 所有用户输入。众所周知,一只猫可能正在踩键盘。确保测试您收到的输入内容,并确保它符合您的预期。

混合 scanf 面向行的 输入(例如 fgetsgetline 会给新用户带来问题。为什么?scanf 系列函数不会删除 '\n' 而是将其留在输入缓冲区中(例如 stdin)。当您尝试使用 fgets 读取它看到的第一个字符时in stdin is what? A '\n', 它读取并考虑整行。如果你打算使用 scanf 读取字符串的数量,则由你删除scanf 留在 stdin 中的 '\n'

并不难,您实际上可以在格式字符串中使用 scanf 提供的 赋值抑制运算符 。例如:

scanf ("%d%*c", &n);

* 是赋值抑制运算符,当与 %*c 一起使用时,它只是告诉 scanf 读取并丢弃 下一个字符不添加到match count(例如什么scanfreturns)。

在填充数组时,您需要使用 while 循环而不是 for 循环(或使用独立索引)。为什么?如果用户使用 ctrl + d(或 windoze 上的 ctrl + z 取消输入会怎样)。如果无论用户做什么,你都迭代到 n,你可以轻松地尝试索引一个你没有分配的数组元素,或者为一个没有输入的字符串分配。

总而言之,您可以执行以下操作:

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

enum { MAXA = 20, MAXS = 40 }; /* max ptrs and str */

int main (void) {

    char *arr[MAXA] = {NULL}, str[MAXS] = "";
    int i = 0, n = 0, ndx = 0;   /* initialize all variables */

    printf ("enter the number of strings: ");
    /* use assignment suppression %*c to discard the \n */
    if (scanf ("%d%*c", &n) != 1) { /* always validate input */
        fprintf (stderr, "error: invalid integer input.\n");
        return 1;
    }

    if (n > MAXA) { /* validate the value of n */
        fprintf (stderr, "warning: n > %d, using %d as limit.\n",
                MAXA, MAXA);
        n = MAXA;
    }

    printf("Enter the strings\n");
    while (ndx < n && fgets (str, sizeof str, stdin)) { /* validate input */
        size_t len = strlen (str); /* get the length */
        if (str[len - 1] == '\n')  /* check for '\n' */
            str[--len] = 0;        /* overwrite with nul-terminator */
        if (!(arr[ndx] = malloc (len + 1))) { /* validate allocation */
            fprintf (stderr, "error: virtual memory exhausted.\n");
            break;
        }
        strcpy (arr[ndx], str);   /* copy to array */
        ndx++;                    /* increment index */
    }

    printf("\nThe Strings are:\n");

    for (i = 0; i < ndx; i++) {  /* you have ndx strings not n */
        printf (" arr[%2d] : %s\n", i, arr[i]);
        free (arr[i]);  /* free memory when no longer needed */
    }

    return 0;
}

例子Use/Output

$ ./bin/nogets
enter the number of strings: 3
Enter the strings
My dog
has a lot
of fleas.

The Strings are:
 arr[ 0] : My dog
 arr[ 1] : has a lot
 arr[ 2] : of fleas.

现在尝试同样的操作,然后按 ctrl + d 而不是输入 "of fleas."(你被覆盖了)。

最后,在您编写的任何动态分配内存的代码中,您对分配的任何内存块负有 2 责任:(1) 始终保留指针到内存块的起始地址,因此,(2) 当不再需要它时可以释放。养成跟踪您分配的内存的习惯,并且 free 它而不是依赖它在 exit 上完成。随着您的程序变得越来越复杂,这对您很有帮助。

查看代码,确保您了解发生了什么。如果您有任何问题,请告诉我。