前言:
此刻姐妹们对“c二维数组传参”大约比较重视,大家都想要剖析一些“c二维数组传参”的相关内容。那么小编在网络上收集了一些对于“c二维数组传参””的相关内容,希望你们能喜欢,兄弟们快快来学习一下吧!C编译器会为每个函数分配一个一定空间的栈帧用于存放相关数据。例如主函数main(),即使没有局部变量和参数,也会分配44h的保存局部变量的空间,如果有局部变量定义,则会根据局部变量的空间需求情况,增加局部变量空间。
由此,在函数内部定义一个局部变量后,可以以此局部变量为基准做地址偏移,来测试栈帧的空间使用。当然,这样操作肯定有溢出和非法操作的风险。
1 向高地址偏移(栈底)
#include <stdio.h>int main(){ int a; int *p = &a; for(int i=0;i<10;i++) // 向高地址偏移 *(p+i) = i+1; for(int j=0;j<10;j++) printf("%d ",*(p+j)); // 正确执行到这里 getchar(); return 0; // 无法返回,因为ebp和ebp+4所在的返回地址都被覆盖}// 正确打印后,内存访问错误提示
栈帧空间:
2 向低地址偏移情形1
#include <stdio.h>int main(){ int a; int *p = &a; for(int i=0;i<10;i++) // 向低地址偏移 *(p-i) = i+1; // 参考下面栈帧图,当*(p-1)时,修改的是p本身的值 for(int j=0;j<10;j++) printf("%d ",*(p+j)); getchar(); return 0; }// 当修改*(p-1)后,提示访问内存错误
栈帧空间:
3 向低地址偏移情形2
#include <stdio.h>#if 1int main() // sub esp,54h,给main局部变量的空间{ int a; int *p = &a; int i; for(i=3;i<26;i++) // 向低地址偏移,并越过三个局部变量:a,p,i *(p-i) = i-2; // 正常压入全部值 for(i=3;i<26;i++) printf("%d ",*(p-i)); // 当调用printf()時,会压入一个栈帧,替换掉ebp-54h更低的地址的值 getchar(); return 0; } // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 20 4337692 4198539// 前面正确访问,后面访问了一些垃圾值
栈帧空间:
4 不使用二维数组声明和定义来模拟一下二维数组(不超过函数栈帧内存空间)
int main(){ int arr; int *p = &arr; int r = 3, c = 4; int i,j; const int n = 7; // 用于跨越此前的局部变量数(包括自身) // 模拟a[3][4]; for(i=n;i<r+n;i++) for(j=n;j<c+n;j++) *(p-c*(i-n)-j-n) = (i-n+1)*(j-n+1); for(i=n;i<r+n;i++) { for(j=n;j<c+n;j++) printf("%d ",*(p-c*(i-n)-j-n)); printf("\n"); } getchar(); return 0;}/*1 2 3 42 4 6 83 6 9 12*/
由上面可见,int*p指针的移动,是按sizeof(int)个字节的长度来移动的,这个计算由编译器完成。如果声明并定义二维数组,其空间的分配和数组元素的移动长度的计算,也是由编译器完成。
#include <stdio.h>int main(){ int a[3][4]; int (*p)[4] = a; // 处理数组,是处理数组的元素,此时数组名会转换为指向其首元素的指针 int i,j; for(i=0;i<3;i++) for(j=0;j<4;j++) *(*(p+i)+j) = (i+1)*(j+1); for(i=0;i<3;i++) { for(j=0;j<4;j++) printf("%d ",*(*(p+i)+j)); printf("\n"); } getchar(); return 0;}/*1 2 3 42 4 6 83 6 9 12*/
p+i 如何偏移或移动指针?p的类型是int[4],由编译器计算按sizeof(int[4])的字节长度来移动。操作a[3][4],操作的是a的元素(数组名在类似的上下文中会转换为指向数组首元素的指针),a[4],操作a[i],操作的是a[i][j]。
*(p+i)+j 如何偏移或移动指针?*(p+i)的类型是int,由编译器计算按sizeof(int)的字节长度来移动。
同样的,用函数来处理二维数组,传参不能传数组,但可以传一个指向数组元素的指针,函数不能返回数组,但可以返回一个指向数组元素的指针。对数组元素的偏移操作,就是其对第一维的处理,由第一维再延伸到其它维。
#include <stdio.h>#include <malloc.h>void arr2d(int(*p)[4],int n){ int i,j; for(i=0;i<n;i++) for(j=0;j<4;j++) *(*(p+i)+j) = (i+1)*(j+1); for(i=0;i<n;i++) { for(j=0;j<4;j++) printf("%d ",*(*(p+i)+j)); printf("\n"); }}int(*arr2d2(int n))[4]{ int(*p)[4] = (int(*)[4])malloc(sizeof(int)*4*n); return p;}int main(){ int a[3][4]; arr2d(a,3); int (*p)[4] = arr2d2(3); arr2d(p,3); free(p); getchar(); return 0;}/*1 2 3 42 4 6 83 6 9 121 2 3 42 4 6 83 6 9 12*/
-End-
标签: #c二维数组传参