前面已经学习了关于指针与数组的一些概念,现在我们继续对它们进行了解,学习指针和数组的定义与声明,还有具体是怎么传参的呢?
【指针与数组的定义,声明】
通俗易懂的来说,定义是不存在的时候要它存在,而声明是不知道的是让它知道。
定义和声明之间的差别就是 定义分配了内存而声明没有;定义只能出现一次,而声明可以出现多次。
1.定义为数组,声明为指针
定义:
//test.c char arr[] = "abcdef";
声明:
//main.c #include<stdio.h> #include<windows.h> extern char *arr; int main() { printf("%s\n", arr); system("pause"); return 0; }
定义为数组,声明为指针,程序运行起来就会发生中断。这是因为,在声明extern char *arr时,编译器认为arr是一个指针变量,在32位系统操作下占4个字节。这4个字节保存了一个地址,这个地址上存的是char类型数据。在test.c文件中定义了arr是一个数组,但是在main.c文件中不知道。所以就会发生中断。
访问形式如下:
2.定义为指针,声明为数组
//test.c char *p = "abcdef";
//main.c #include<stdio.h> #include<windows.h> extern char p[]; int main() { printf("%s\n", p); system("pause"); return 0; }
定义为指针,声明为数组,运行也有问题。在test.c中,编译器分配4个byte空间,并命名为p。
同时p里保存了字符串常量“abcdefg”的首字符的首地址。这个字符串常量本身保存在内存的静态区,其内容不可更改。
在man.c中,编译器认为p是一个数组,其大小为4个byte,数组内保存的是char类型的数据。
extern char p[]访问时,是对p(指针里的内容)进行访问,所以结果是随机值。
通过上面我们可以得出结论:定义为指针,只能声明为指针;定义为数组,也只能声明为数组。
【数组传参,指针传参问题】
指针和数组作为参数传入函数时,传入的是地址,即指向变量的地址和数组的首地址,可以在函数中改变指针或数组的值,但本质上它们还是值的传递(区别于变量的值传递的是:变量值传递不会改变实参原来的值。),我们无法对指针和数组的地址进行操作(如:地址赋值,分配内存等),要进行地址操作需要使用指针引用或指针的指针。
1.一维数组传参:一维数组传参时会发生降维问题,会降成指向其内部元素类型的指针。
char* test2(char *arr2[]) //char* test2(char **arr2) { char *p=" abcd"; return arr2[1]=p; } //int test1(int arr1[],int size) int test1(int *arr1, int size) { int i = 0; for (i = 0; i < size; i++) { arr1[i++]; } return arr1[4]; } int main() { int arr1[5] = { 1, 2, 3, 4, 5 }; int size = sizeof(arr1) / sizeof(arr1[0]); char *arr2[5] = { 0 }; test1(arr1, size);//一维数组,传参时会降成指向int类型的一级指针 test2(arr2);//指针数组,传参时会降成指针数组的指针 printf("%d\n", arr1[4]);//5 printf("%s ", arr2[1]);//abcd system("pause"); return 0; }
2.二维数组传参:二维数组传参时会降成一级指向其内部元素的指针。
//二维数组传参 //void test(int arr[][5]) void test(int (*arr)[5]) { } int main() { int arr[3][5] = {0}; test(arr); system("pause"); return 0; }
arr[3][5]理解为一个一维数组a[3],其每个元素都是一个含有5个char类型数的数组.在传参时,会降成一维数组的指针(即数组指针),注意:传参后,除了首个[]能省略,其余的括号绝对不能省略,这样才能保证编译器把arr解析为一个指向包含4个char类型数据元素的数组,即一维数组a[3]的元素。
3.一级指针传参:
//一级指针传参 void fun(int *p,int size) { int i = 0; for (; i < size; i++) { printf("%d\n", *(p+i));//1 2 3 4 5 } } int main() { int arr[] = { 1, 2, 3, 4, 5 }; int *p = arr; int size = sizeof(arr) / sizeof(arr[0]); fun(p,size); system("pause"); return 0; }
函数参数部分是一级指针时,可以接受的参数例如:
fun(int*p):可以是一个整形一级指针,可以是一维整型数组数组名
fun (char *p):可以是字符数组
4.二级指针传参:
void fun(int **ptr) { printf("%d\n", **ptr); } int main() { int n = 10; int *p = &n;//一级指针p指向n int **pp = &p;//二级指针pp指向p,也是指向p所指向的内容 fun(pp);//10 fun(&p);//10 system("pause"); return 0; }
test(int**p):二级指针变量,一级指针变量地址,一维指针数组的数组名。