为什么这个数组分配给非指定数组?

时间:2013-10-19 05:39:03

标签: c++ c arrays

/ *我观察到的是:

  1. 当我向b(数组)提供像“ab”这样的字符串时   然后输出是:“ab”“help”“dude”
  2. 当我给“abc”时   然后输出是:“abc”“”“dude”
  3. 如果我给“abcd”   然后输出是:“abc”“d”“dude”

    等等* /

       #include<stdio.h>
       main()
       {
            char a[5]="help",b[3],c[10]="dude";
         scanf("%s",b);
         printf("\t%s",b); 
         printf("\t%s",a);
         printf("\t%s",c);
       }
    
       /* what i dont get is :
        Here iam  gaving a string to b(array),  why, if the string has more than the  
        required no. of charecters, its printing those charecters in other arrays 
       (though i had not assiged scanf to other arrays )?   
    

7 个答案:

答案 0 :(得分:5)

请记住,C中的字符串需要空终止符。如果没有空间,打印将继续“到下一个nul”。以下是您的内存在初始化中的表现:

h  e  l  p \0 \0 \0 \0  d  u  d  e \0
^             ^         ^
a             b         c

当您在ab指向的位置读取字符串b时:

h  e  l  p \0  a  b \0  d  u  d  e \0
^              ^        ^
a              b        c

一切都很好。但是abc给出了:

h  e  l  p \0  a  b  c \0  u  d  e \0
^              ^        ^
a              b        c

当您打印b时,您将获得abc;打印c不会给你任何东西(第一个字符是'\0')。

最后,输入abcd即可获得

h  e  l  p \0  a  b  c  d \0  d  e \0
^              ^        ^
a              b        c

打印c将导致"d" - 正如您所见。

事实上,事物存储在内存中的顺序不是“定义的”,尽管编译器通常会执行与上面类似的操作。因此,虽然您知道不能写入不属于您的内存,但您无法确定在执行此操作时会发生什么(如您的情况)。这就是为什么它被称为“未定义的行为”。你不能依赖其他编译器给你相同的结果 - 甚至相同的编译器给你相同的结果......

有意义吗?

当然,解决方案是为b分配更多空间。这会导致'\0'b之间的c更多,并且不会被覆盖。

编辑 - 我刚刚意识到ba的存储顺序似乎与我刚才描述的顺序相反 - 因为它是{{ 1}},而不是被覆盖的a。这表明编译器订购的东西非常愉快,并且当我写详细的答案时我应该戴上眼镜。但原则完全一样 - 所以我会“把剩下的作为学生的练习”。

答案 1 :(得分:1)

您的数组按以下顺序放入内存

c [10],b [3],a [5]

因此,如果数组b将包含的字符超出其容纳范围,那么它的某些字符将重叠数组a, 考虑这两个数组,b和a,因为它们在内存中

b [0] b [1] b [2] a [0] a [1] a [2] a [3] a [4]

当你在b中获得“abc”时,你得到了

b[0] b[1] b[2] a[0] a[1] a[2] a[3] a[4]
'a'  'b'  'c'  '\0' 'e'  'l'  'p'  '\0'

执行语句后

 printf("\t%s",b); 
 printf("\t%s",a);

输出

"abc" ""

因为[0]包含'\ 0'

当你输入“abcd”时,你得到了

b[0] b[1] b[2] a[0] a[1] a[2] a[3] a[4]
'a'  'b'  'c'  'd' '\0'  'l'  'p'  '\0'

,输出

"abcd" "d"

因为[0]包含'd'而[1]包含'\ 0'

答案 2 :(得分:0)

b[3]是一个包含3个字符的数组。但是,字符串abc由4个字符组成,最后一个字符为\0,表示字符串的结尾。因此,如果您希望能够存储abc,则需要至少声明一个包含4个字符的数组,而不是3个

答案 3 :(得分:0)

当您输入abc作为输入时,您的数组b会被填满(因为它只有3个位置)并且没有留给\0字符的空间。因此,当您尝试将其作为字符串打印时...它会溢出并导致错误

要使字符串可打印,必须采用以下格式: stringtext\0但是当您用完数组b中的所有空格时,在打印时没有为\0留出空间,则会出现错误

此代码中的错误也是错误的:

scanf("%s",&b);

它应该是:

scanf("%s",b);

答案 4 :(得分:0)

当你将“abc”放入b[3]时,它会越过数组的末尾。 abc字符串是四个字节,因为它在末尾有一个nul终止符。

由于它是未定义的行为,任何技术上都可能发生,但实际发生的是字符串末尾的nul覆盖内存中下一个变量的第一个字符,使其成为空字符串。

最快的解决方案是确保您的字符数组足以存储所有字符和终结符:

char b[4] = "abc";

或者让编译器为这个特殊的简单情况处理它:

char b[] = "abc";

答案 5 :(得分:0)

所以真正发生的事情是你要超出数组的末尾并覆盖内存。

当您提供“ab”作为b的输入时,它的作用是因为b足以存储'ab'和\0,正如其他人所提到的那样。

当您提供'abc'作为输入时,b没有足够的空间分配来存储abc和null所以它只存储'abc'然后null似乎写入了a数组的第一个字节,这意味着它只是一个空字符串......或者它可能不是,这是未定义的部分。谁知道你的阵列外面存储了什么。事实上你可能会很幸运,因为你定义的数组最有可能是连续的内存。

当您提供“abcd”作为输入时,dnull会被写入a数组。

很多时候,在不太简单的程序中,你会得到一个像这样的编程错误的SEGV。

答案 6 :(得分:0)

这只是未定义行为的情况之一。 b[3]可以存储三个字符的字符串(包括\0),但是当您的输入为abc时,它是四个字符的字符串,您无法将其存储在数组{{1}中}。你会得到任何东西。