二维数组的存储和输出

不明白运行的结果是怎么来的。二维数组的具体存储方式是怎样的啊
小白真心求助,提前谢过

 #include <iostream>
#include <cstring>
using namespace std;

int main()
{
    char big[2][3];              //定义一个2行3列的数组,应该对吧。。 
    strcpy(big[1], "what");      //这里故意来个了4个字节的,超出一个。 
    cout << big[1] << endl;      //按我的理解,这里应该输出 wha (因为只能称下3个嘛) 
    cout << big[2];              //然后这里输出 t 
    return 0;                       
}                                //然而运行的结果并不是我想象的那样!! 

图片说明

为什么第一行多了一个 t 啊.. 而且这里输出也就算了,然而第二行又输出一个 t 这不就重复了么..

在C++里传递数组永远都是传递指向数组首元素的指针,编译器不知道数组的大小,也就是数组退化为指针。
那么big数组里存的是什么呢?写代码看一下吧!
图片说明

也就是输出big[1]的时候也就是big[1]做为首地址,把所有东西数出来,直到遇到/0,也就是what了
输出big[2]的时候,以big[2]为首地址,那里存的是t,所以从t开始把后面的都输出来,但是后面没有字符了,只输出t了。
把what改出sunny看一下结果,就更清楚了
图片说明

strcpy不会考虑你数组的长度(缓冲区大小),它直接循环拷贝,直到遇到\0为止。

cout输出字符串会以0x0字符为结束符,二维数组也是申请的一片连续的空间,根据机器类型,默认一般填0,也可能是0xff(部分单片机EEPROM就是如此),你申请的二维数组字符空间太少,没有结束符,因此cout输出big[1]就会超界,多输出一个t。

 #include <stdio.h>
#include <string.h>
int main(int argc, char* argv[])
{
    int i = 123;
    char x = 'A';
    char test[3];
    char * s = "hello";
    printf("%c\n", x);
    strcpy(test, s);
    printf("%c\n", x);
    printf("%s\n", test);
    return 0;
}


图片说明

看这个代码,很明显,原来x存储的是A
因为test长度不足。所以strcpy拷贝的时候,就侵犯到后面的内存,也就是x的存储。
结果就是x原来的内容被冲掉,存储了o这个字符
为什么不是l呢?因为c++语言按照4字节对齐内存,因此虽然test是3个字节,但是实际上,x和它之间的那个字节是不存储东西,被浪费的。

如果你去看很多c++的函数的定义,你会发现一个现象,就是函数调用的时候,需要你传入数组的同时,还需要传入数组的长度。
换一句话说,C++函数的调用者是不能得到数组的长度的。这个现象叫做数组退化成指针。

所以无论是<<(其实它是重载了<<运算符,本质上也是函数)还是printf,它怎么知道输出一个字符串应该输出几个字符?它只有通过字符串结尾的\0判断。
如果你strcpy越界了,那么它读取字符数组的时候,也会跟着越界。

数组退化成指针
http://blog.csdn.net/foreverhuylee/article/details/38333101
http://blog.csdn.net/mydreamremindme/article/details/9734707
https://www.cnblogs.com/sanghai/archive/2013/11/01/3402258.html

多维数组和一维数组一样也是线性储存
big 指向6个字节
big[2][3] = big[6]

big[0] = big = 0, 0, 0, 'w' , 'h', 'a', 】't', '0'
big[1] = big+3 = 【 'w' , 'h', 'a', 】't', '0'
big[2] = big+6 = 't', '0'

所以big[2]那个t越界了

图片说明

二维数组在存储中是线性存储的,a[0][0]在a[0][1]的上面。
而数组名,你可以简单的理解为指向一维数组的指针。

数组的下表从0开始的
把数组当做字符串答应的时候需要字符'\0'作为结束符号,不然会出错