高级指针2

前面已经学习了关于指针与数组的一些概念,现在我们继续对它们进行了解,学习指针和数组的定义与声明,还有具体是怎么传参的呢?

【指针与数组的定义,声明】

     通俗易懂的来说,定义是不存在的时候要它存在,而声明是不知道的是让它知道。

      定义和声明之间的差别就是 定义分配了内存而声明没有;定义只能出现一次,而声明可以出现多次。

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):二级指针变量,一级指针变量地址,一维指针数组的数组名。






猜你喜欢

转载自blog.csdn.net/snowyuuu/article/details/80424370