int main(void) {
char *input;
printf("prompt>");
scanf("%s", input);
printf("%s", input);
return 0;
}
提示>输入
RUN FAILED(退出值138,总时间:3s)
代码有什么问题?必须是scanf()或第二个printf()。输入长度未知。很多人都说只需创建一个长度为'X'的字符数组来保存输入。只是想知道为什么这段代码有效。
#include <stdio.h>
#include <stdlib.h>
int main(void) {
/* prompt */
char input;
printf("prompt>");
scanf("%s", &input);
printf("%s", &input);
return 0;
}
答案 0 :(得分:6)
您的具体问题是input
后面没有存储空间。它是一个未初始化的指针,指向内存中的随机点,这不太可能有用。
您可以使用以下内容:
char *input = malloc (100);
// check that input != NULL
// use it
free (input);
或:
char input[100];
但您使用scanf
时遇到严重问题(见下文)。
除非您完全控制输入,否则您永远不会<{>} <{1}}(或其任何变体)中使用无界%s
。这是一种容易出现缓冲区溢出的危险做法,越早摆脱这种习惯就越好。它以这种方式类似于scanf
。
从我之前的一个回答中,下面这段代码(以及包含在其中的主要代码)提供了一种获取用户输入的安全方式。您传入一个可选的提示,缓冲区以加载输入,以及缓冲区的大小。
它会将输入返回到缓冲区的大小(如果存在,则删除换行符),然后在必要时清除行的其余部分,以便它不会影响下一个输入操作。它将在文件结尾返回OK或错误指示,或者如果输入太长(如果你想对它做一些事情,你仍然得到输入的第一部分)。
一旦你有了这条线,你就可以安全地gets()
到你的内心。但是,在您的情况下不需要这样做,因为您只是尝试获取字符串。只需使用直接返回的缓冲区。
sscanf
#include <stdio.h>
#include <string.h>
#define OK 0
#define NO_INPUT 1
#define TOO_LONG 2
static int getLine (char *prmpt, char *buff, size_t sz) {
int ch, extra;
// Get line with buffer overrun protection.
if (prmpt != NULL) {
printf ("%s", prmpt);
fflush (stdout);
}
if (fgets (buff, sz, stdin) == NULL)
return NO_INPUT;
// If it was too long, there'll be no newline. In that case, we flush
// to end of line so that excess doesn't affect the next call.
if (buff[strlen(buff)-1] != '\n') {
extra = 0;
while (((ch = getchar()) != '\n') && (ch != EOF))
extra = 1;
return (extra == 1) ? TOO_LONG : OK;
}
// Otherwise remove newline and give string back to caller.
buff[strlen(buff)-1] = '\0';
return OK;
}
给它一个镜头,它比自己使用int main(void) {
char input[10];
int rc = getLine ("prompt> ", input, sizeof (input));
switch (rc) {
case NO_INPUT: printf ("\nNo input recieved\n"); break;
case TOO_LONG: printf ("Too long, truncated input below:\n");
default: printf("Your input was [%s]\n", input);
}
return 0;
}
更强大。
至于您的更新,询问其工作原理:
scanf("%s")
这是未定义的代码。期。您只为字符分配空间,但扫描字符串。由于字符串是所有字符后跟零字符的字符数组,因此唯一可以安全输入的字符串将是空字符串。
任何其他内容都会写入字符和,无论发生在堆栈上的字符旁边是什么。
这与分配#include <stdio.h>
#include <stdlib.h>
int main(void) {
/* prompt */
char input;
printf("prompt>");
scanf("%s", &input);
printf("%s", &input);
return 0;
}
然后输入200个字符没什么不同,它仍然是缓冲区溢出,应该避免。
下面的讨论基于C的特定实现,不一定是所有实现。
很有可能,你在这里很幸运。编译器可以生成保持堆栈指针对齐的代码,这样即使你要求一个字节,也可以为4个空间分配空间(甚至更多,具体取决于体系结构) - 为了简单起见,我假设大多数类型都是4个字节)。
另外,您可能会发现您还可以安全地覆盖argc整数和argv指针的八个字节(即使您不使用它们,它们可能仍然存在,没有一点有两组不同的启动代码只是为了在堆栈上保存几个字节。)
如果您进一步编写,则最终会将char input[100]
的返回地址覆盖到您的启动代码中。 然后你会知道它,因为你的代码会在main
退出时进入la-la land。
对于未定义的行为,任何都可能发生。有时任何东西包括它可以完美地工作的可能性(类似于“经常在空中抛出一副牌,它们最终将落入一个漂亮整齐的堆中”但随机性稍差一点)。
这不会使未定义的行为变得更糟糕。
答案 1 :(得分:3)
char *input;
只是一个指针 - 没有分配数据空间来存储scanf收集的数据。
试试这个
char input[100];
答案 2 :(得分:1)
您可能想要在具有分隔字符的scanf("%c", input)
循环内尝试while
。您还应该输入一个数组char input[X]
,其中X是一个足够值的数字,用于保存输入的最可能值。我会先尝试输入一个数组。
答案 3 :(得分:1)
您使用什么编译器?在Turbo C 3.0中它可以工作。 试试这个变种:
#include <stdio.h>
#include <alloc.h>
int main(void)
{
char *input = (char*)calloc(100, sizeof(char));
printf("prompt>");
scanf("%s", input);
printf("%s", input);
free(input);
return 0;
}
答案 4 :(得分:1)
在使用指针之前忘了分配内存。
试一试:
int main(void) {
char input[256];
printf("prompt>");
scanf("%s", input);
printf("%s", input);
return 0;
}
甚至:
#include <stdlib.h>
#include <stdio.h>
int main(void) {
char *input = (char *) malloc(sizeof(char) * 256));
printf("prompt>");
scanf("%s", input);
printf("%s", input);
return 0;
}
答案 5 :(得分:1)
尝试: -
int main(void) {
char input[100];
printf("prompt>");
scanf("%99s", input);
printf("%s", input);
return 0;
}
这会将字符串限制为99个字节。注意“%s”==由空格或换行符分隔的字符串,即。你只得到第一个字!
我认为你真正想要的是:
#include <stdio.h>
int main(void) {
char input[99];
printf("prompt>");
fgets(input,99,stdin);
printf("->%s<-", input);
return 0;
}
你可能需要添加一些代码来摆脱不需要的新行字符!