c语言数组越界不报错 但能正常输出

时间:2021-05-31 19:30:39
#include  <stdio.h>
main()
{static int a[3][4];
  int i,j;
   for(i=0;i<3;i++)
     for(j=0;j<4;j++)
     scanf("%d",&a[i][j]);
   {for(i=0;i<3;i++)
   { for(j=0;j<4;j++)
     printf("%d",a[i][j]);
     printf("\n");
   }
   }

    printf("\n");
   {for(i=0;i<6;i++)
   { for(j=0;j<2;j++)
     printf("%d*",a[i][j]);
     printf("\n");
   }
   }


}


我知道越界不报错 但是能正确输出(后面那个)不知道为什么 拜托大家了

27 个解决方案

#1



for(i=0;i<6;i++)

  for(j=0;j<2;j++)
     printf("%d*",a[i][j]);
  printf("\n");
}
  

这个可以正常输出?????  本来就只有三行四列,当i = 3;是 就是第四行的行地址了,都不知道指向哪里去了

#2


越界访问的行为不可预测,取决于你越界到哪里了(是否还在进程空间中)以及做了什么(读还是写)。
你的例子,你越界读了栈上的空间,读到的值难以预测,虽然未必会crash. 

#3


引用 2 楼  的回复:
越界访问的行为不可预测,取决于你越界到哪里了(是否还在进程空间中)以及做了什么(读还是写)。
你的例子,你越界读了栈上的空间,读到的值难以预测,虽然未必会crash.


错了,你的程序没有越界,因为 int [3][4]和 int [2][6]的内存布局兼容。

#4


引用 3 楼  的回复:
引用 2 楼  的回复:
越界访问的行为不可预测,取决于你越界到哪里了(是否还在进程空间中)以及做了什么(读还是写)。
你的例子,你越界读了栈上的空间,读到的值难以预测,虽然未必会crash.


错了,你的程序没有越界,因为 int [3][4]和 int [2][6]的内存布局兼容。


++

你分配了48个字节的内存空间,那种矩形的排列只是为了方便学习而做成的模型,实际上是连续排在一起的,你用{for(i=0;i<6;i++)
  { for(j=0;j<2;j++)
输出,也就是输出那48个字节里的内容

#5


引用 3 楼  的回复:
引用 2 楼 的回复:
越界访问的行为不可预测,取决于你越界到哪里了(是否还在进程空间中)以及做了什么(读还是写)。
你的例子,你越界读了栈上的空间,读到的值难以预测,虽然未必会crash.


错了,你的程序没有越界,因为 int [3][4]和 int [2][6]的内存布局兼容。

真是这样吗!!
 int [3][4];   那  [4][2]  的数值不是 已到 下一行了么?? 

#6


引用 4 楼  的回复:
引用 3 楼 的回复:

引用 2 楼 的回复:
越界访问的行为不可预测,取决于你越界到哪里了(是否还在进程空间中)以及做了什么(读还是写)。
你的例子,你越界读了栈上的空间,读到的值难以预测,虽然未必会crash.


错了,你的程序没有越界,因为 int [3][4]和 int [2][6]的内存布局兼容。


++

你分配了48个字节的内存空间,那种矩形的排列只是为……


那我数组的定义还有什么意义吗?

#7


正常输出,你想一下a[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
它的存放位置是连续的   你3 * 4遍历  只是  1,2,3,4     5,6,7,8    9,10,11,12这样遍历出来
而 2 * 6 遍历   是   1,2,3,4,5,6,   7,8,9,10,11,12  这样遍历 
始终没有 超过12之后

#8


引用 7 楼  的回复:
正常输出,你想一下a[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
它的存放位置是连续的 你3 * 4遍历 只是 1,2,3,4 5,6,7,8 9,10,11,12这样遍历出来
而 2 * 6 遍历 是 1,2,3,4,5,6, 7,8,9,10,11,12 这样遍历 
始终没有 超过12之后


仔细看下LZ的 代码!!!!!
和下面的代码 有区别么
#include <stdio.h>


int main()
{
int arrya[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};

printf("%d\n",arrya[4][2]);

return 0;
}

#9


只是恰巧你越界的位置没有被其他程序使用,所以没有报错。

#10


引用 9 楼  的回复:
只是恰巧你越界的位置没有被其他程序使用,所以没有报错。
++

#11


数组的存储是连续的int [3][4]访问的是还是数组本身范围内

#12


下标越界但是你的数据在内存中存放时连续的,可以直接
for(i=0;i<12;i++)
  printf("%d",a[i]);
一样可以访问。你把两种方式的地址全部打印出来看下就知道了

#13


因为 int [3][4]和 int [2][6]的内存布局兼容。

这是什么理论?表示真心没听过。元芳,你怎么看?

元芳曰:“此碎尸案是自杀。”

#14


就是12个字节嘛

#15


不报错只是巧合,并不代表一直不出问题,那样是危险的

#16


引用 3 楼  的回复:
引用 2 楼  的回复:
越界访问的行为不可预测,取决于你越界到哪里了(是否还在进程空间中)以及做了什么(读还是写)。
你的例子,你越界读了栈上的空间,读到的值难以预测,虽然未必会crash.


错了,你的程序没有越界,因为 int [3][4]和 int [2][6]的内存布局兼容。

怎么没越界,他程序是int[3][4]变成int[6][2]好不好?(i<6)

#17


不服气啊 为什么我初学到时候 就没有这个问题 
发现越界了 就知道错了 

#18


给个比较负责任的解释吧
a[3][4]我们可以认为是连续的12个存储单元a相当于a[0][0],其地址我们这样理解即*(a+4*i+j),所以a[6][2],相当于*(a+4*6+2)已经越界了,输出的内容不可预测。
你仔细看C的书应该都有解释。

#19


引用 13 楼  的回复:
因为 int [3][4]和 int [2][6]的内存布局兼容。

这是什么理论?表示真心没听过。元芳,你怎么看?

元芳曰:“此碎尸案是自杀。”

C专家编程有讲的貌似~

作案工具,大型绞肉机。。

#20


引用 3 楼  的回复:
引用 2 楼 的回复:
越界访问的行为不可预测,取决于你越界到哪里了(是否还在进程空间中)以及做了什么(读还是写)。
你的例子,你越界读了栈上的空间,读到的值难以预测,虽然未必会crash.


错了,你的程序没有越界,因为 int [3][4]和 int [2][6]的内存布局兼容。

++

#21


引用 18 楼  的回复:
给个比较负责任的解释吧
a[3][4]我们可以认为是连续的12个存储单元a相当于a[0][0],其地址我们这样理解即*(a+4*i+j),所以a[6][2],相当于*(a+4*6+2)已经越界了,输出的内容不可预测。
你仔细看C的书应该都有解释。



+1

#22


引用 3 楼  的回复:
引用 2 楼  的回复:
越界访问的行为不可预测,取决于你越界到哪里了(是否还在进程空间中)以及做了什么(读还是写)。
你的例子,你越界读了栈上的空间,读到的值难以预测,虽然未必会crash.


错了,你的程序没有越界,因为 int [3][4]和 int [2][6]的内存布局兼容。


内存布局兼容。。。好亮。

你能告诉我,若a 的地址是0x0000,  a + 5 的地址是多少不。

#23


越界会现不可预料的错。

#24


我以前也遇到这个问题  确实没报错  但是你程序要是那么写  按规范说已经错了 毕竟越界

#25



//为了地址计算的方便使用char类型进行计算 char占用一个字节
static char A [3][4] ={1,2,3,4,5,6,7,8,9,10,11,12};
设A的地址为0x0
i < 3 , j < 4
0x0 1     0x1 2     0x2 3     0x3 4     //(0xX Y)0x为地址, Y为地址对应的值
0x4 5     0x5 6     0x6 7     0x7 8     
0x8 9     0x9 10   0xA 11   0xB 12     
i < 6 , j < 2
0x0 1     0x1 2     
0x4 5     0x5 6     
0x8 9     0x9 10     
0xC 0     0xD 0
0x10 0   0x11 0     
0x14 0   0x15 0

因为A的类型为3行4列,每当A[x][y]的时候,相当于去A的A + x * 4 + y的地址区去找值,以此类推,如果是int ,long,double,只要在地址上乘以相应的系数就可以了,
比如int:

i < 3 , j < 4
0x0 1     0x4 2     0x8 3     0xC 4     
0x10 5     0x14 6
//相当于     
//0x0 1     0x1*4 2     0x2*4 3     0x3*4 4     
//0x4*4 5     0x5*4 6

。。。。。。   

#26


越界不一定报错,这种行为是未定义

#27


栈里面   虚拟内存已经映射了物理内存  没事儿所以

#1



for(i=0;i<6;i++)

  for(j=0;j<2;j++)
     printf("%d*",a[i][j]);
  printf("\n");
}
  

这个可以正常输出?????  本来就只有三行四列,当i = 3;是 就是第四行的行地址了,都不知道指向哪里去了

#2


越界访问的行为不可预测,取决于你越界到哪里了(是否还在进程空间中)以及做了什么(读还是写)。
你的例子,你越界读了栈上的空间,读到的值难以预测,虽然未必会crash. 

#3


引用 2 楼  的回复:
越界访问的行为不可预测,取决于你越界到哪里了(是否还在进程空间中)以及做了什么(读还是写)。
你的例子,你越界读了栈上的空间,读到的值难以预测,虽然未必会crash.


错了,你的程序没有越界,因为 int [3][4]和 int [2][6]的内存布局兼容。

#4


引用 3 楼  的回复:
引用 2 楼  的回复:
越界访问的行为不可预测,取决于你越界到哪里了(是否还在进程空间中)以及做了什么(读还是写)。
你的例子,你越界读了栈上的空间,读到的值难以预测,虽然未必会crash.


错了,你的程序没有越界,因为 int [3][4]和 int [2][6]的内存布局兼容。


++

你分配了48个字节的内存空间,那种矩形的排列只是为了方便学习而做成的模型,实际上是连续排在一起的,你用{for(i=0;i<6;i++)
  { for(j=0;j<2;j++)
输出,也就是输出那48个字节里的内容

#5


引用 3 楼  的回复:
引用 2 楼 的回复:
越界访问的行为不可预测,取决于你越界到哪里了(是否还在进程空间中)以及做了什么(读还是写)。
你的例子,你越界读了栈上的空间,读到的值难以预测,虽然未必会crash.


错了,你的程序没有越界,因为 int [3][4]和 int [2][6]的内存布局兼容。

真是这样吗!!
 int [3][4];   那  [4][2]  的数值不是 已到 下一行了么?? 

#6


引用 4 楼  的回复:
引用 3 楼 的回复:

引用 2 楼 的回复:
越界访问的行为不可预测,取决于你越界到哪里了(是否还在进程空间中)以及做了什么(读还是写)。
你的例子,你越界读了栈上的空间,读到的值难以预测,虽然未必会crash.


错了,你的程序没有越界,因为 int [3][4]和 int [2][6]的内存布局兼容。


++

你分配了48个字节的内存空间,那种矩形的排列只是为……


那我数组的定义还有什么意义吗?

#7


正常输出,你想一下a[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
它的存放位置是连续的   你3 * 4遍历  只是  1,2,3,4     5,6,7,8    9,10,11,12这样遍历出来
而 2 * 6 遍历   是   1,2,3,4,5,6,   7,8,9,10,11,12  这样遍历 
始终没有 超过12之后

#8


引用 7 楼  的回复:
正常输出,你想一下a[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
它的存放位置是连续的 你3 * 4遍历 只是 1,2,3,4 5,6,7,8 9,10,11,12这样遍历出来
而 2 * 6 遍历 是 1,2,3,4,5,6, 7,8,9,10,11,12 这样遍历 
始终没有 超过12之后


仔细看下LZ的 代码!!!!!
和下面的代码 有区别么
#include <stdio.h>


int main()
{
int arrya[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};

printf("%d\n",arrya[4][2]);

return 0;
}

#9


只是恰巧你越界的位置没有被其他程序使用,所以没有报错。

#10


引用 9 楼  的回复:
只是恰巧你越界的位置没有被其他程序使用,所以没有报错。
++

#11


数组的存储是连续的int [3][4]访问的是还是数组本身范围内

#12


下标越界但是你的数据在内存中存放时连续的,可以直接
for(i=0;i<12;i++)
  printf("%d",a[i]);
一样可以访问。你把两种方式的地址全部打印出来看下就知道了

#13


因为 int [3][4]和 int [2][6]的内存布局兼容。

这是什么理论?表示真心没听过。元芳,你怎么看?

元芳曰:“此碎尸案是自杀。”

#14


就是12个字节嘛

#15


不报错只是巧合,并不代表一直不出问题,那样是危险的

#16


引用 3 楼  的回复:
引用 2 楼  的回复:
越界访问的行为不可预测,取决于你越界到哪里了(是否还在进程空间中)以及做了什么(读还是写)。
你的例子,你越界读了栈上的空间,读到的值难以预测,虽然未必会crash.


错了,你的程序没有越界,因为 int [3][4]和 int [2][6]的内存布局兼容。

怎么没越界,他程序是int[3][4]变成int[6][2]好不好?(i<6)

#17


不服气啊 为什么我初学到时候 就没有这个问题 
发现越界了 就知道错了 

#18


给个比较负责任的解释吧
a[3][4]我们可以认为是连续的12个存储单元a相当于a[0][0],其地址我们这样理解即*(a+4*i+j),所以a[6][2],相当于*(a+4*6+2)已经越界了,输出的内容不可预测。
你仔细看C的书应该都有解释。

#19


引用 13 楼  的回复:
因为 int [3][4]和 int [2][6]的内存布局兼容。

这是什么理论?表示真心没听过。元芳,你怎么看?

元芳曰:“此碎尸案是自杀。”

C专家编程有讲的貌似~

作案工具,大型绞肉机。。

#20


引用 3 楼  的回复:
引用 2 楼 的回复:
越界访问的行为不可预测,取决于你越界到哪里了(是否还在进程空间中)以及做了什么(读还是写)。
你的例子,你越界读了栈上的空间,读到的值难以预测,虽然未必会crash.


错了,你的程序没有越界,因为 int [3][4]和 int [2][6]的内存布局兼容。

++

#21


引用 18 楼  的回复:
给个比较负责任的解释吧
a[3][4]我们可以认为是连续的12个存储单元a相当于a[0][0],其地址我们这样理解即*(a+4*i+j),所以a[6][2],相当于*(a+4*6+2)已经越界了,输出的内容不可预测。
你仔细看C的书应该都有解释。



+1

#22


引用 3 楼  的回复:
引用 2 楼  的回复:
越界访问的行为不可预测,取决于你越界到哪里了(是否还在进程空间中)以及做了什么(读还是写)。
你的例子,你越界读了栈上的空间,读到的值难以预测,虽然未必会crash.


错了,你的程序没有越界,因为 int [3][4]和 int [2][6]的内存布局兼容。


内存布局兼容。。。好亮。

你能告诉我,若a 的地址是0x0000,  a + 5 的地址是多少不。

#23


越界会现不可预料的错。

#24


我以前也遇到这个问题  确实没报错  但是你程序要是那么写  按规范说已经错了 毕竟越界

#25



//为了地址计算的方便使用char类型进行计算 char占用一个字节
static char A [3][4] ={1,2,3,4,5,6,7,8,9,10,11,12};
设A的地址为0x0
i < 3 , j < 4
0x0 1     0x1 2     0x2 3     0x3 4     //(0xX Y)0x为地址, Y为地址对应的值
0x4 5     0x5 6     0x6 7     0x7 8     
0x8 9     0x9 10   0xA 11   0xB 12     
i < 6 , j < 2
0x0 1     0x1 2     
0x4 5     0x5 6     
0x8 9     0x9 10     
0xC 0     0xD 0
0x10 0   0x11 0     
0x14 0   0x15 0

因为A的类型为3行4列,每当A[x][y]的时候,相当于去A的A + x * 4 + y的地址区去找值,以此类推,如果是int ,long,double,只要在地址上乘以相应的系数就可以了,
比如int:

i < 3 , j < 4
0x0 1     0x4 2     0x8 3     0xC 4     
0x10 5     0x14 6
//相当于     
//0x0 1     0x1*4 2     0x2*4 3     0x3*4 4     
//0x4*4 5     0x5*4 6

。。。。。。   

#26


越界不一定报错,这种行为是未定义

#27


栈里面   虚拟内存已经映射了物理内存  没事儿所以