前面已经学习了关于指针与数组的一些概念,现在我们继续对它们进行了解,学习指针和数组的定义与声明,还有具体是怎么传参的呢?
【指针与数组的定义,声明】
通俗易懂的来说,定义是不存在的时候要它存在,而声明是不知道的是让它知道。
定义和声明之间的差别就是 定义分配了内存而声明没有;定义只能出现一次,而声明可以出现多次。
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):二级指针变量,一级指针变量地址,一维指针数组的数组名。