C 编程输入错误

发布于 2024-09-20 00:49:55 字数 522 浏览 3 评论 0原文

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;
}
int main(void) {
    char *input;
    printf("prompt>");
    scanf("%s", input);
    printf("%s", input);
    return 0;
}

prompt>input

RUN FAILED (exit value 138, total time: 3s)

What's wrong with the code? Has to be either the scanf() or the second printf(). The input is of unknown length. A lot people have said to simply create a char array of length 'X' to hold the input. Just wanted to know then why this code works.

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

int main(void) {
    /* prompt */
    char input;
    printf("prompt>");
    scanf("%s", &input);
    printf("%s", &input);
    return 0;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

眉黛浅 2024-09-27 00:49:55

您的具体问题是您在输入后面没有存储空间。它是一个未初始化的指针,指向内存中的随机位置,不太可能有任何用处。

您可以使用类似:

char *input = malloc (100);
// check that input != NULL
// use it
free (input);

或: 的

char input[100];

内容,但是您在使用 scanf 时遇到了严重的问题(见下文)。


您不应该在 scanf(或其任何变体,除非您完全控制输入)中使用无限制的 %s。这是一种危险的做法,容易导致缓冲区溢出,越早改掉这个习惯越好。在这方面它类似于 gets()

从我之前的回答来看,下面的这段代码(以及合并到其中的主代码)提供了一种获取用户输入的安全方法。您传入一个可选提示、用于加载输入的缓冲区以及缓冲区的大小。

它将返回最大缓冲区大小的输入(如果有,则去除换行符),然后在必要时清除该行的其余部分,以便它不会影响下一个输入操作。如果输入太长,它将返回 OK 或错误指示(如果您想对其执行某些操作,您仍然可以获得输入的第一部分)。

获得该线路后,您可以安全地扫描它,并随心所欲。但是,这在您的情况下不是必需的,因为您只是想获取一个字符串。只需使用直接返回的缓冲区即可。

#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;
}

这是未定义的代码。时期。您只为一个字符分配空间,但扫描的是一个字符串。由于字符串是所有字符后跟零字符的字符数组,因此您可以安全输入的唯一字符串将是一个空字符串。

任何其他内容都将写入字符堆栈上与该字符相邻的任何内容。

这与分配 char input[100] 然后输入 200 个字符没有什么不同,它仍然是缓冲区溢出,应该避免。

下面的讨论基于 C 的特定实现,而不一定是所有实现。

很有可能,你在这里很幸运。编译器可能会生成保持堆栈指针对齐的代码,这样,即使您要求一个字节,您也可能会获得分配四个字节(甚至更多,取决于体系结构)的空间 - 为了简单起见,我假设大多数类型都是四个字节)。

此外,您可能会发现您还可以安全地覆盖 argc 整数和 argv 指针的八个字节(即使您不使用它们,它们也可能仍然存在,没有必要拥有两套不同的启动代码只是为了在堆栈上保存一些字节)。

如果您写得比这更多,您最终会将 main 的返回地址覆盖到您的启动代码。 然后你就会知道它,因为当main退出时你的代码将进入la-la land。

对于未定义的行为,任何事情都可能发生。有时,任何事情都包含完美运行的可能性(类似于“经常将一副纸牌扔到空中,它们最终会落入整齐有序的堆中”,但随机性稍低一些) )。

这并不会让未定义的行为变得不那么糟糕。

Your specific problem is that you have no storage behind input. It's an uninitialised pointer, pointing to a random spot in memory, which is unlikely to be anywhere useful.

You can use something like:

char *input = malloc (100);
// check that input != NULL
// use it
free (input);

or:

char input[100];

but you have a serious problem with your use of scanf (see below).


You should never use an unbounded %s in scanf (or any of its variants unless you totally control the input). It's a dangerous practice prone to buffer overflows and the sooner you get out of the habit, the better. It's akin to gets() in that way.

From an earlier answer of mine, this piece of code below (along with your main code incorporated into it) provides a safe way of getting user input. You pass in an optional prompt, the buffer to load the input into, and the size of the buffer.

It will return the input up to the size of the buffer (stripped of the newline if there) then clear out the rest of the line if necessary so that it doesn't affect the next input operation. It will return either OK or an error indication on end-of-file or if the input was too long (you still get the first part of the input in case you want to do something with it).

Once you have the line, you can sscanf it, safely, to your heart's content. However, that's not required in your case since you're only trying to get a string. Just use the buffer that's returned directly.

#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;
}

Give that a shot, it's far more robust than using scanf("%s") on its own.


As for your update asking why this works:

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

int main(void) {
    /* prompt */
    char input;
    printf("prompt>");
    scanf("%s", &input);
    printf("%s", &input);
    return 0;
}

It's undefined code. Period. You only allocate space for a character but you scan in a string. Since a string is a character array of all the characters followed by a zero character, the only string you could input safely there would be an empty one.

Anything else will write to both the character and whatever happens to be adjacent to the character on the stack.

This is no different to allocating char input[100] then entering 200 characters, it's still buffer overflow and should be avoided.

Discussion below is based on a particular implementation of C, not necessarily all implementations.

Chances are, you got lucky here. Compilers may generate code that keeps the stack pointer aligned so that, even though you asked for one byte, you may get space allocated for four (or even more, depending on the architecture - I'll assume most types are four bytes here for simplicity).

In addition, you may find that you can also safely overwrite the eight bytes of argc integer and argv pointer (they're probably still there even though you don't use them, no point having two different sets of start-up code just to save a few bytes on the stack).

If you write further than that, you'll eventually overwrite the return address from main to your start-up code. Then you'll know about it since your code will go off into la-la land when main exits.

With undefined behaviour, anything can happen. Sometimes that anything includes the possibility that it will work perfectly (similar to "throw a deck of cards in the air often enough and they'll eventually fall in a nice neat sorted heap" but a little less random).

That does not make undefined behaviour any less of a bad thing.

得不到的就毁灭 2024-09-27 00:49:55
  char *input;

只是一个指针 - 没有分配数据空间来存储 scanf 收集的数据。

试试这个

char input[100];
  char *input;

Is only a pointer - there is no data space allocated store the data that scanf collects.

try this instead

char input[100];
关于从前 2024-09-27 00:49:55

您可能想在具有分隔字符的 while 循环内尝试 scanf("%c", input) 。您还应该将输入设置为数组 char input[X],其中 X 是足以容纳输入最可能值的数字。不过,我会尝试先将输入设置为数组。

You may want to try scanf("%c", input) inside of a while loop that has your delimiting character. You should also make input an array char input[X] where X is a number of sufficient value to hold the most likely values for your input. I would try making input an array first though.

别念他 2024-09-27 00:49:55

您忘记在使用指针之前分配内存。

尝试一下:

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;
}

You forgot to allocate the memory before using your pointer.

Try it:

int main(void) {
    char input[256];
    printf("prompt>");
    scanf("%s", input);
    printf("%s", input);
    return 0;
}

or even:

#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;
}
你与清晨阳光 2024-09-27 00:49:55

你使用什么编译器?在 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;
}

What compiler do you use? In Turbo C 3.0 it works.
Try this variant:

#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;
}
年华零落成诗 2024-09-27 00:49:55

尝试:-

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; 
} 

您可能需要添加一些代码来删除不需要的换行符!

Try:-

int main(void) { 
char input[100]; 
printf("prompt>"); 
scanf("%99s", input); 
printf("%s", input); 
return 0; 

}

This will limit the string to 99 bytes. Note "%s" == string of characters delimited by white space or newline ie. you only get the first word!

I think what you really want is:

#include <stdio.h>
int main(void) { 
    char input[99]; 
    printf("prompt>"); 
    fgets(input,99,stdin);
    printf("->%s<-", input); 
    return 0; 
} 

You probably need to add some code to get rid of unwanted new line characters!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文