我遇到运行时错误的具体原因是什么?

时间:2017-07-03 20:13:47

标签: c

#include<stdio.h>
#include<string.h>
void main()
{
    char a,b,c;
    printf("Enter alien names:\n");
    scanf("%s\n%s\n%s\n",a,b,c);
    printf("The alien names are %s, %s and %s. A meteor hit %s's spaceship. A star scratched %s\'s spaceship. But %s fixed %s and %s\'s spaceships. The three became friends and are from the planet BYG (which means BLUE YELLOW GREEN)",a,b,c,a,b,c,a,b);
}

我到达这里的运行时错误的具体原因是什么?

5 个答案:

答案 0 :(得分:1)

发布的代码具有未定义的行为,因为变量abc属于char类型,而%s转换说明符属于scanf()scanf()的调用期望指向可以保存输入字符串的字符数组的第一个元素。 a调用中的转换指定符和参数不匹配会导致未定义的行为,并且尝试在接收数组中写入太多字符会导致未定义的行为。

第一个问题可以通过将bcchar a[100], b[100], c[100]; ... scanf("%s\n%s\n%s\n", a, b, c); 声明为足以容纳预期输入的数组来解决:

a

请注意,数组在大多数表达式中都会衰减指向它们的第一个元素,包括函数调用,所以这里a[]是指向字符数组&a[0]的第一个元素的指针;这相当于scanf()

如果用户输入太多字符,仍有可能存在未定义的行为。要避免这种情况,请始终在使用\0将用户输入读入字符串时指定最大宽度。请注意,指定的宽度是将为该输入项读取的最大字符数,不包括空终止符scanf(),它将由scanf("%99s\n%99s\n%99s\n", a, b, c); 自动添加,因此最大宽度必须为至少比接收阵列的大小小一个:

\n

但是如果编译并运行此代码,您会发现它的行为不符合预期。输入第三个名称后,程序将继续等待更多输入。这是因为scanf()字符是一个空格字符,当%s遇到格式字符串中的空白字符时,它会读取并丢弃输入中的零个或多个空白字符,直到遇到非空白字符为止,或直到不再能读取任何字符。 scanf()指令告诉scanf()读取字符,直到遇到空白字符。因此,当用户在最终名称后按 Enter 时,\n完成匹配最终名称的输入字符,并将\n字符返回到输入流;然后在上面的格式字符串中到达scanf()\n匹配输入流中前面提到的scanf()字符,以及遇到的任何其他空格字符。如果用户输入另一个非空白字符,或者从键盘发出文件结尾信号(例如,使用 Ctrl-D Ctrl-Z ),这将结束。

为了避免这种复杂情况,请记住结束带有空格字符的\n格式字符串几乎永远不正确。此外,无需使用scanf()而不是空格字符,因为两者都被scanf("%99s %99s %99s", a, b, c); 简单地解释为空格指令:

scanf()

如果在尝试使用输入之前检查了来自scanf()的调用的返回值,它将进一步改进发布的代码。由于3会返回成功分配的数量,因此该值应为#include <stdio.h> #include <string.h> int main(void) { char a[100], b[100], c[100]; printf("Enter alien names:\n"); int ret_val = scanf("%99s %99s %99s", a, b, c); if (ret_val == 3) { printf("The alien names are %s, %s and %s. A meteor hit %s's " "spaceship. A star scratched %s\'s spaceship. But %s " "fixed %s and %s\'s spaceships. The three became friends " "and are from the planet BYG (which means BLUE YELLOW GREEN)\n", a, b, c, a, b, c, a, b); } else { puts("Input error"); } }

setContext

答案 1 :(得分:1)

要解决此问题,您应该只考虑使用字符串(字符数组)来包含不同的名称。

以下是如何执行此操作的示例:

    void main()
{
// The string "a" can contain up to 100 symbols (chars).
char a[100];

printf("Enter an alien name:\n");

scanf("%s",a);

printf("The alien name is %s.", a);

}

&#34; char a&#34;之间的区别&#34; char a [100]&#34;在第一种情况下是变量&#34; a&#34;对应一个字符,第二个字符串对应一个字符串 - 一个字符数组,最多可包含100个字符。

答案 2 :(得分:0)

  

我遇到运行时错误的具体原因是什么?

使用格式说明符scanf的函数%s期望传递char数组的地址,在该地址中放置输入数据。例如,

等数组
char a[100];

但是,您传递简单的char变量ab以及c,它们可以保存-128到127或0到255范围内的值,具体取决于实施的char是签名还是未签名。

这些变量甚至没有初始化,因此不确定的值传递给scanf。但即使它们已被初始化,当用作地址时,传递的值很可能会导致段错误。

我的编译器为传递给a的{​​{1}},bc分别发出了2条警告。

  

警告C4477:'scanf':格式字符串'%s'需要类型为'char *'的参数,但可变参数1的类型为'int'

     

警告C4700:未初始化的本地变量'a'使用

请启用并执行所有编译器警告。

答案 3 :(得分:0)

    //There are things that shoudn't be there. Im not a pro but this is what I think.

    #include<stdio.h>
    #include<string.h>//you have include this library but you didn't use a function from it.
                      //I think what you want to do is use the str functions like strcpy
                      //but in this case you don't need to use it.

    void main()
    {
        char a[25],b[25],c[25];//Here you declared a character a, b and c. But if you want to store a string, you have to declare an array of characters. So instead of a, b, c, it's a[someValue], b[someValue] and c[someValue].
                   //Declare an array with a size that you think will cover the whole "alien name". e.g. a[25]..
                   //but i don't know, maybe you did it on purpose. Maybe you just want to name the aliens with one character like A, B, C. But if you want to name the aliens with a long name, you must declare an array.


        printf("Enter alien names:\n");
        scanf("%s\n%s\n%s\n",a,b,c);//You don't need to put the "\n" between those "%s". "\n" means "newline". It will work without it because scanf automatically reads next set of characters when it meets white space of newline.
                                    //--so you can remove "\n" in there and replace it with space. But you can leave it there also but  you really have to remove the last "\n" because scanf will search again for the next 
                                    //--new line before it will end asking for input and pressing enter will not work because you have to type another set of characters before scanf will read the last "\n" that you put at scanF. 
                                    //Another mistake here is the format specifier that you used (%s). It doesn't match declaration because you declare char a, b, c, that will only store one character each.
                                    //In case that you're really just storing one character each alien's name, you have to use the "%c" instead of "%s" and you must pass the reference of the char variable in 
                                    //--scanf, e.g. scanf("%c %c %c", &a, &b, &c);
                                    //Just remember that if you plan on storing a string or a long name there, you must declare an array like I said at the beginning.
                                    //--and if it's an array, you don't need to include the '&' on every variable when you're passing it in scanF.


        //There's nothing wrong here if you're alien's names are string. 
        printf("The alien names are %s, %s and %s. A meteor hit %s's spaceship. A star scratched %s\'s spaceship. But %s fixed %s and %s\'s spaceships. The three became friends and are from the planet BYG (which means BLUE YELLOW GREEN)",a,b,c,a,b,c,a,b);
    }

答案 4 :(得分:0)

运行时错误的特定原因是这一行:

scanf("%s\n%s\n%s\n",a,b,c);

%s转换说明符告诉scanf从输入流中读取非空白字符的序列(跳过前导空格)并将该序列存储到<相应参数指向的char的em> array 。问题是abc不是指向char的指针;它们是尚未初始化的单个char对象。其中任何一个包含与scanf可以写入的地址相对应的值的几率几乎是不存在的。

首先,将abc的声明更改为

char a[SOME_LENGTH] = {0}; // initialize array contents to 01
char b[SOME_LENGTH] = {0};
char c[SOME_LENGTH] = {0};
其中 SOME_LENGTH 是一个足够长的数字,用于包含您希望输入的最长字符串加上字符串终止符的一个额外空格。 IOW,如果您打算读取的最长字符串长度为10个字符,那么您的声明需要

char a[11] = {0};
char b[11] = {0};
char c[11] = {0};

其次,将scanf来电更改为

scanf( "%(SOME_LENGTH-1)s %(SOME_LENGTH-1)s %(SOME_LENGTH-1)s", a, b, c );

其中 (SOME_LENGTH-1) 是缓冲区的长度减去1.再次假设 SOME_LENGTH 为11:

scanf( "%10s %10s %10s", a, b, c );

如果您输入的字符串长于缓冲区大小要容纳的字符串,这将有助于防止缓冲区溢出。

%s转换说明符和格式字符串中的空格都告诉scanf使用并丢弃任何前导空格。在格式字符串中指定空白字符时可能会遇到麻烦。

附加说明:

main返回int,而不是void - 将main更改为

int main (void)
{
  ...
}

<小时/>

  1. 如果初始化器中的元素少于数组中的元素,则多余的元素初始化为0.因此,在这种情况下,第一个元素*显式*初始化为0,其余元素*隐式*初始化为0。