我编写了一个小代码,可以将多个字符串作为用户的输入。在此之前,我要求用户输入要作为输入的字符串数。在将字符串作为输入时,新行字符会自动占据第一个字符串的位置。我不知道发生了什么:(这是我的代码:
#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");
}
}
答案 0 :(得分:1)
在评论之后,您的代码中存在许多问题。首先gets
,不要使用它,这是一个“悬挂”的进攻 - 足够说。
接下来,验证所有用户输入。如你所知,一只猫可能正踩在键盘上。确保测试您收到的输入内容,并将其与您期望的内容相匹配。
将scanf
与面向行的输入混合(例如fgets
或getline
可能会给新用户带来问题。为什么?scanf
家庭函数不会删除'\n'
而是将其留在输入缓冲区中(例如stdin
)。然后当您尝试使用fgets
读取它在stdin
中看到的第一个字符时是什么?一个'\n'
,它读取并考虑整行。如果您打算使用scanf
来读取字符串的数量,则由您删除{{1} } '\n'
留在scanf
。
这并不难,您实际上只需在格式字符串中使用stdin
提供的赋值抑制运算符。 E.g:
scanf
scanf ("%d%*c", &n);
是分配抑制运算符,当与*
一起使用时,只需告诉%*c
读取并丢弃下一个字符而不添加到 scanf
(例如match count
返回的内容。)
填充数组时,您需要使用scanf
循环而不是while
循环(或使用独立索引)。为什么?如果用户使用 ctrl + d (或在windoze上 ctrl + z )取消输入,该怎么办?如果您正在迭代到for
而不管用户做了什么,您可以轻松地尝试索引尚未分配的数组元素,或者为未输入的字符串分配。
完全放弃,你可以这样做:
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;
}
现在尝试相同的事情并按 ctrl + d 而不是输入$ ./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.
(你被覆盖)。
最后,在您动态分配内存的任何代码中,对于分配的任何内存块,您有2个职责:(1)始终保留指向起始地址的指针对于内存块,(2)当不再需要时,它可以释放。养成跟踪你分配的内存的习惯,并"of fleas."
而不是依赖于free
上的内存。随着您的计划变得更加复杂,这将对您有所帮助。
查看代码,确保您了解正在发生的事情。如果您有任何问题,请告诉我。
答案 1 :(得分:0)
当您使用scanf读取位数时,它只处理输入的数字,而不是输入数字后输入的数字。
可能值得同时刷新其余输入,例如 How to clear input buffer in C?
答案 2 :(得分:0)
gets()函数必须将标准输入流stdin中的字节读入s指向的数组,直到读取<newline>
或遇到文件结束条件。
所以每当你进入
之后输入字符串数
5
因此,如果按Enter键,则gets
被调用,它将新行作为第一个输入。
如果您没有输入输入并按下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");
}
}