char str[40] 与char str[40] = {0}的区别在哪里,该怎么解决

char str[40] 与char str[40] = {0}的区别在哪里
下面一个小程序,用char str[40] 与char str[40] = {0}的输出结果不一样,为什么?

include "stdafx.h"
#include "stdio.h"
#include "string.h"

int main(void)
{
char str[40];  //与char str[40] = {0};有很大区别。
strncpy(str, "abc", 2);
puts(str);
printf("%d\n", sizeof(str));

return 0;
}


用char str[40];输出结果为
ab烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫?
40
Press any key to continue
有一堆乱码。

用char str[40] = {0};输出结果为
ab
40
Press any key to continue
结果很正常。

为什么?

另外,如果程序用strcpy再用两者的话结果又是一样的正常:
abc
40
Press any key to continue



------解决方案--------------------
一个未初始化,一个数组中每一个字符被初始化为0(有了结束符,字符才能被正确处理)
------解决方案--------------------
引用:
一个未初始化,一个数组中每一个字符被初始化为0(有了结束符,字符才能被正确处理)

这难道不是每本书上都会讲的东西?
------解决方案--------------------
char str[40];没有初始化,给没有初始化的内存拷贝东西,结果自然不确定
char str[40] = {0};初始化为全0,拷贝ab,剩下的还是0,自然不会有乱码
------解决方案--------------------
puts的时候是要一直输出到字符'\0'才停止的,如果你没有初始化,strncpy复制了两个字符ab到str,后边的字符是随机不确定的。。所以你puts的时候后边会有一堆乱码。。
而如果你初始化了。。整个str都初始化为0。。你strncpy后。。前两个字符变为ab。。后边的字符不变,还是0。。那么puts的时候就只输出ab。。
------解决方案--------------------
VC的DEBUG版会把未初始化的指针自动初始化为0xCCCCCCCC,而不是就让它随机去,那是因为DEBUG版的目的是为了方便我们调试程序的,如果野指针的初值不确定,那么每次调试同一个程序就可能出现不一样的结果,比如这次程序崩掉,下次正常运行,再一次虽然没崩掉,但结果不对……那显然对我们解bug是非常不利的。
DEBUG版本为了能让程序员更早的发现错误,把堆栈上的数据对初始化成了0xcc,也就是说局部变量如果不初始化,那么DEBUG版本中就会是0xCC

转到汉字就是烫了。

至于strcpy的问题,你可以看看他是怎么实现的就明白了
/*
  GNU-C中的实现(节选):
  */
  char* strcpy(char *d, const char *s)
  {
  char *r=d;
  while((*d++=*s++));
  return r;
  }
  /* while((*d++=*s++)); 的解释:两层括号是为了取赋值表达式的值,而赋值表达式的值为左操作数,所以在复制NULL后,循环停止 */

------解决方案--------------------
strcpy在复制NULL后就停止了,准确的说是在复制'\0'之后,所以输出的时候到\0就结束了
------解决方案--------------------
引用:
那么未初始化的char str[40];是定义了一个字符数组还是定义了一个字符串呢?书中有好多程序并没有把它初始化为0。
没必要就不初始化的 挺正常的做法 
------解决方案--------------------
    str[40]未初始化,所以你调试的时候,就会看见“烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫。。。”,然后你用strcpy拷贝ab两个字符到str[0],str[1]中,但是没有给str[3]之后的赋值,输出结果当然就是“ab烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫”。
    解决办法1:strcpy之后,给后一位赋值‘\0’,此为结束符,printf输出的时候遇见‘\0’就会停止输出。
    解决办法2:声明数组时,给数组初始化,即LZ所说的str[40]={0},然后printf输出时,遇见‘0’就会停止输出。