将多个字符串作为输入时不必要的换行符
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
与 面向行的 输入(例如 fgets
或 getline
会给新用户带来问题。为什么?scanf
系列函数不会删除 '\n'
而是将其留在输入缓冲区中(例如 stdin
)。当您尝试使用 fgets
读取它看到的第一个字符时in stdin
is what? A '\n'
, 它读取并考虑整行。如果你打算使用 scanf
读取字符串的数量,则由你删除scanf
留在 stdin
中的 '\n'
。
并不难,您实际上可以在格式字符串中使用 scanf
提供的 赋值抑制运算符 。例如:
scanf ("%d%*c", &n);
*
是赋值抑制运算符,当与 %*c
一起使用时,它只是告诉 scanf
读取并丢弃 下一个字符不添加到match count
(例如什么scanf
returns)。
在填充数组时,您需要使用 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
上完成。随着您的程序变得越来越复杂,这对您很有帮助。
查看代码,确保您了解发生了什么。如果您有任何问题,请告诉我。
我编写了一个小代码来将多个字符串作为用户输入。在此之前,我要求用户输入要作为输入的字符串数。当以字符串作为输入时,换行符自动占据第一个字符串的位置。我不知道发生了什么:( 这是我的代码:
#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
与 面向行的 输入(例如 fgets
或 getline
会给新用户带来问题。为什么?scanf
系列函数不会删除 '\n'
而是将其留在输入缓冲区中(例如 stdin
)。当您尝试使用 fgets
读取它看到的第一个字符时in stdin
is what? A '\n'
, 它读取并考虑整行。如果你打算使用 scanf
读取字符串的数量,则由你删除scanf
留在 stdin
中的 '\n'
。
并不难,您实际上可以在格式字符串中使用 scanf
提供的 赋值抑制运算符 。例如:
scanf ("%d%*c", &n);
*
是赋值抑制运算符,当与 %*c
一起使用时,它只是告诉 scanf
读取并丢弃 下一个字符不添加到match count
(例如什么scanf
returns)。
在填充数组时,您需要使用 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
上完成。随着您的程序变得越来越复杂,这对您很有帮助。
查看代码,确保您了解发生了什么。如果您有任何问题,请告诉我。