一篇文章带你了解C语言指针进阶

1.字符指针

我们已经知道了数组名在大部分时候表示数组的地址,指针本质上也表示一个地址,那么我们能否用指针来创建一个字符串呢?

int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abcdef";
	const char* p1 = "abcdef";
	const char* p2 = "abcdef";//const可省略,默认为常量字符串
	printf("%s\n", arr1);
	printf("%s\n", arr2);
	printf("%s\n", p1);
	printf("%s\n", p2);
	return 0;
}

需要注意的是字符指针创建的字符串是常量字符串,普通的字符串只要数组名不同即使字符串内容相同,也是不同的字符串,但是不论用多少个指针创建字符串,只要字符串内容相同,所有指针指向的就是同一个字符串,因此字符指针指向的字符串不能修改,在没有const修饰的情况下也是如此。

2.指针数组

我们知道数组可以存储整形,浮点型,或自定义的结构体,那么可不可以存储指针呢?答案是:可以。元素都为指针的数组就称为指针数组,形式为:数据类型* 数组名[ ],例如:储存整形指针的指针数组创建成int*p[10],表示的就是一个包含十个指针元素的数组,利用指针数组我们可以访问指针数组内的指针进而操作变量或其他数组。

int main()//利用指针数组分别遍历三个数组
{
	int arr1[] = { 1, 2, 3, 4, 5 };
	int arr2[] = { 2, 3, 4, 5, 6 };
	int arr3[] = { 3, 4, 5, 6, 7 };
	int*parr[] = { arr1, arr2, arr3 };
	int i, j;
	int Sz = sizeof(parr) / sizeof(parr[0]);
	int sz = sizeof(arr1) / sizeof(arr1[0]);
	for (i = 0; i < Sz; i++)
	{
		for (j = 0; j < sz; j++)
		{
			printf("%d ",*(parr[i]+j) );
		}
		printf("\n");
	}
}

3.数组指针

我们知道指针可以指向整形,浮点型,或自定义的结构体,那么能不能指向数组呢?答案也是:可以。指向数组的指针称为数组指针,形式为:数据类型(*p)[ ] ,例如int(*p)[10],表示的就是一个指向包含十个元素数组的指针,这和指针数组的区别在于要将*p用小括号括起来以确保它是一个指针而非数组(无括号的情况下p先和 [ ]结合)。

int main()利用数组指针遍历数组
{
	int arr[6] = { 1, 2, 3, 4, 5, 6 };
	int(*p)[6] = &arr;
	int i;
	int sz = sizeof(arr) / sizeof(arr[0]);
	for (i=0;ip[10]是一个指针数组,剩下int(*  )[5]的是数组的类型,类型为数组指针,p是一个数组有十个元素,每个元素都是一个数组指针,指向的数组有五个int类型的元素
	return 0;
}

有了指针数组和数组指针,我们还可以进行两者的嵌套使用,例如:数组指针数组(int(*p[ ])[ ]),指针数组指针(int*(*p)[ ]),前者是一个数组里面的元素是指向另外一些数组的指针,后者是个指针指向一个元素全为另外一些指针的数组。

void print(int(*p)[5],int x,int y)//用数组指针接收数组地址
{
	int i,j;
	for (i = 0; i < x; i++)
	{
		for (j = 0; j < y; j++)
		{
			printf("%d ", *(*(p + i) + j));//arr[i]==*(arr+i)==*(p+i)==p[i]
		}
		printf("\n");
	}
}
int main()//利用数组指针遍历二维数组
{
	int arr[3][5] = { { 1, 2, 3, 4, 5 }, { 2, 3, 4, 5, 6 }, { 3, 4, 5, 6, 7 } };
	print(arr, 3, 5);//arr是首元素地址,二维数组的首元素是个第一行的一维数组
	return 0;
}

4.函数指针

我们知道指针可以指向整形,浮点型,自定义的结构体和数组,那么能不能指向一个函数呢?答案同样是:可以。函数指针的形式为:函数返回类型(*p)(参数类型,参数类型....)例如:int(*p)(int,int)表示的就是一个指向返回类型为整形,两个参数类型也是整形的函数的指针。注意:利用函数指针调用函数时有几个解引用操作符都可以没有也可以,但是括号不可或缺!

int Mul(int x, int y)
{
	return x*y;
}
int main()
{
	int a, b;
	scanf("%d%d", &a, &b);
	int(*p)(int,int) = &Mul;//函数指针,有无&都可以
	printf("%d", (p)(a, b));//用指针调用函数(*(void(*)()0))()
	printf("%d", (*p)(a, b)); 
	printf("%d", (**p)(a, b));
	printf("%d", (***p)(a, b));//任意个数的*都可以
	return 0;
}

5.数组传参

我们知道简单的一维数组的传参方式:数组名是首元素地址,我们可以直接用指针接收也可以直接用数组接收,那么指针数组和二维数组呢?指针数组传参传的也是其首元素的地址,而它的首元素是一个指针,指针的地址我们当然用二级指针接收,同样地我们也可以直接指针数组接收。二维数组传参传的是其首元素的地址,要注意的是,二维数组的首元素并不是第一个元素而是第一行元素所构成的一维数组,一维数组的地址我们当然用数组指针接收,同样地,我们也可以直接用二维数组接收。

void test1(int arr[])//直接数组接收
{
	printf("%d\n", arr[]);
}
void test2(int*arr)//指针接收首元素地址
{
	printf("%d\n", arr[]);
}
void test3(int arr[][5])//二位数组直接接收
{
	printf("%d\n", arr[][5]);
}
void test4(int(*arr)[5])//数组指针接收
{
	printf("%d\n", arr);
}
void test5(int*arr[])//直接指针数组接收
{
	printf("%d\n", arr);
}
void test6(int**arr)//二级指针接收
{
	printf("%d\n", arr);
}
int main()
{
	int arr1[5] = {1,2,3,4,5};
	int arr2[3][5] = {1,2,3,4,5};
	int* arr3[5] = {NULL};
	test1(arr1);
	test2(arr1);
	test3(arr2);
	test4(arr2);
	test5(arr3);
	test6(arr3);
	return 0;
}

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!

你可能感兴趣的:(一篇文章带你了解C语言指针进阶)