繁体   English   中英

C编程输入错误

[英]C Programming Input Error

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

提示>输入

RUN FAILED(退出值138,总时间:3秒)

代码有什么问题? 必须是scanf()或第二个printf()。 输入的长度未知。 很多人说过只需创建一个长度为'X'的char数组来保存输入。 只是想知道为什么此代码有效。

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

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

您的特定问题是您在input没有存储空间。 这是一个未初始化的指针,指向内存中的随机点,不太可能有用。

您可以使用类似:

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

要么:

char input[100];

但是您使用scanf遇到了严重问题(请参见下文)。


切勿scanf使用无限制的%s (或其任何变体,除非您完全控制输入)。 这是一种危险的做法,容易造成缓冲区溢出,越早摆脱习惯,越好。 类似于gets()

根据我的较早答案,下面的这段代码(以及合并到其中的主要代码)提供了一种获取用户输入的安全方法。 您传入一个可选提示,要加载输入内容的缓冲区以及缓冲区的大小。

它将输入返回到缓冲区的大小(如果有,则将其换行),然后在必要时清除其余行,以免影响下一个输入操作。 如果文件结束或输入时间过长,它将返回OK或错误指示(如果您想对它做一些事情,您仍然会得到输入的第一部分)。

有了线路,就可以安全地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")使用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。

具有不确定的行为, 任何事情都会发生。 有时, 任何事情都包括它可能完美运行的可能性(类似于“经常在空中扔一副纸牌,它们最终会落入一个整齐,整齐的分类堆中”,但随机性要小一些)。

这样做不会使未定义的行为成为一件坏事。

  char *input;

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

试试这个代替

char input[100];

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

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

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

试试吧:

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

尝试:-

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM