从输入中读取带空格的字符串?

112

我使用Ubuntu,我的IDE是Geany和CodeBlock。 我想做的事情是读取一个字符串(比如"Barack Obama")并把它放到一个变量中:

#include <stdio.h>

int main(void)
{
    char name[100];

    printf("Enter your name: ");
    scanf("%s", name);
    printf("Your Name is: %s", name);

    return 0;
}

输出:

Enter your name: Barack Obama
Your Name is: Barack

我该如何让程序读取整个名称?


1
只需要一个简单的答案,使用:scanf("%[^\n]", char_variable_name); - user7122338
13个回答

200

使用:

fgets (name, 100, stdin);

100 是缓冲区的最大长度。您应根据需要进行调整。

用法:

scanf ("%[^\n]%*c", name);
[]是扫描集字符。[^\n]表示当输入不是换行符('\n')时,接受输入。然后使用%*c从输入缓冲区中读取换行符(未读取),*表示此读取的输入被丢弃(赋值抑制),因为您不需要它,并且该缓冲区中的换行符不会对您可能采取的下一个输入造成任何问题。
在这里阅读有关扫描集赋值抑制运算符的内容。
请注意,您也可以使用gets,但是....

永远不要使用gets()。 因为无法在事先不知道数据的情况下确定gets()将读取多少个字符,并且由于gets()将继续存储超出缓冲区的字符,因此使用它非常危险。 它已被用于破坏计算机安全。 请改用fgets()


1
@Stallman:你不能将字符串声明为char name[],因此这不是有效的C语法。C字符串是由空字符终止的一系列字节。因此,我们总是可以知道字符串的结尾。即使我们指向一个不代表字符串开头的内存位置,字符串也会被认为从地址的起始位置到第一个空字符出现的位置。 - phoxis
1
char name[]="" 包含一个空字符。我们可以使用 char name[]="My name" - phoxis
2
@phoxis 为什么要用 %*c?使用 c 而不是其他字母有什么原因吗?因为我在网上找不到相关的参考资料。此外,我一直在使用 scanf("%[^\n]\n", name) 来丢弃换行符,并且效果非常好。 - John Strood
2
@Djack:%*c 只是消除任何字符,比如当它不是 \n 时。 - phoxis
3
%c代表一个字符,就像%d代表整数一样,%*c则代表读取所有的字符。因此,它的意思是读取所有的字符,直到遇到一个新的换行符。@NathanProgrammer - Nobody
显示剩余5条评论

24

试试这个:

scanf("%[^\n]s",name);

\n 只是设置了被扫描字符串的定界符。


4
这里的s是没有意义的。 %[^\n]已经要求包括所有字符,除了换行符。 - alk

7

正确的答案是这样的:

#include <stdio.h>

int main(void)
{
    char name[100];

    printf("Enter your name: ");
    // pay attention to the space in front of the %
    //that do all the trick
    scanf(" %[^\n]s", name);
    printf("Your Name is: %s", name);

    return 0;
}

在%前的那个空格非常重要,因为如果您的程序中有其他几个scanf,例如您有1个scanf用于整数值和另一个scanf用于双精度值...当您到达用于char(字符串名称)的scanf时,该命令将被跳过,您不能输入它的值...但是如果在%前放置那个空格,一切都会好起来,不会跳过任何内容。


2
此处的s没有意义。%[^\n]已经要求所有字符但不包括换行符。 - alk
这个问题困扰了我很长时间。感谢您提供的解决方案。在 [^\n] 的开头放置空格可以防止跳过输入。 - Puspam

6
scanf(" %[^\t\n]s",&str);

str 是你从中获取字符串的变量。


2
这里的s也没有意义。 - alk

6
这里有一个示例,说明如何使用fgets函数获取包含空格的输入。
#include <stdio.h>

int main()
{
    char name[100];
    printf("Enter your name: ");
    fgets(name, 100, stdin); 
    printf("Your Name is: %s", name);
    return 0;
}

2
注意:使用fgets()函数时,在CLI(命令行解释器)中,当您输入较少内容并以“Enter”键结束字符串时,数组中的最后一个字符将有时是'\n'。 因此,当打印该字符串时,编译器总会在打印字符串时换行。 如果要使输入的字符串具有类似于空终止字符串的行为,请使用这个简单的技巧。
#include<stdio.h>
int main()
{
 int i,size;
 char a[100];
 fgets(a,100,stdin);;
 size = strlen(a);
 a[size-1]='\0';

return 0;
}

更新:在其他用户的帮助下进行了更新。


1
如果输入长度超过可用空间,例如100个字符,在输出中将不会出现\n - user694733
@user694733 是的,但有时我们会在CLI中使用fgets来处理小输入。这个注释是针对这种情况的,感谢您指出这一点。 - Ritesh Sharma

1
#include <stdio.h>
// read a line into str, return length
int read_line(char str[]) {
int c, i=0;
c = getchar();
while (c != '\n' && c != EOF) { 
   str[i] = c;
   c = getchar();
   i++;
}
str[i] = '\0';
return i;
}

2
在你的代码中加入一些描述,以及OP应该采取哪些措施来实现所需的功能,这将使你的回答更有效。 - Muhammad Omer Aslam
1
你的代码没有考虑数组的大小,可能会导致溢出。 - Jazz

0
如果您需要读取多行内容,需要清除缓冲区。例如:
int n;
scanf("%d", &n);
char str[1001];
char temp;
scanf("%c",&temp); // temp statement to clear buffer
scanf("%[^\n]",str);

0
使用此代码,您可以在按下键盘上的回车键之前输入内容。
char ch[100];
int i;
for (i = 0; ch[i] != '\n'; i++)
{
    scanf("%c ", &ch[i]);
}

0

虽然上述方法确实可行,但每种方法都有各自的问题。

如果您使用支持POSIX的平台,则可以使用getline()getdelim()。如果您使用Windows和MinGW作为编译器,则应该可以使用它们。

getline()被定义为:

ssize_t getline(char **lineptr, size_t *n, FILE *stream);

为了输入,首先需要创建一个指向char类型的指针。

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

// s is a pointer to char type.
char *s;
// size is of size_t type, this number varies based on your guess of 
// how long the input is, even if the number is small, it isn't going 
// to be a problem
size_t size = 10;

int main(){
// allocate s with the necessary memory needed, +1 is added 
// as its input also contains, /n character at the end.
    s = (char *)malloc(size+1);
    getline(&s,&size,stdin);
    printf("%s",s);
    return 0;
}

示例输入:Hello world to the world!

输出:Hello world to the world!\n

需要注意的一件事是,即使为s分配的内存为11个字节,而输入大小为26个字节,getline()仍然使用realloc()重新分配s

因此,您的输入有多长并不重要。

size会随着读取的字节数更新,根据上面的示例输入,size将为27

getline()还将\n视为输入。因此,您的's'将在末尾保留'\n'。

还有更通用的getline()版本,即getdelim(),它需要一个额外的参数,即delimiter

getdelim()定义如下:

ssize_t getdelim(char **lineptr, size_t *n, int delim, FILE *stream);

Linux man page


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