C语言 指针初阶

发布时间:2024年01月01日

C语言学习!

目录

文章目录

前言

一、指针和数组

1.1 指针与数组的关系

1.2 指针运算符和下标运算符

1.3 数组传参

二、二级指针

三、指针数组

3.1 一维数组

3.2 二维数组

总结


前言

? ? ? ? 上一篇博文C语言 指针-CSDN博客简单介绍了指针,本篇文章是对指针内容的补充。


一、指针和数组

1.1 指针与数组的关系

  • 数组:一组相同类型元素的集合。
  • 指针变量:是一个变量,存放的是地址。
  • 数组可以通过指针访问。

? ? ? ? arr 是数组,表达式 arr 的值就与 arr[0] 的地址,即 &arr[0] 一致,如果数组 arr 的元素类型为 int 型,那么不管元素个数是多少,表达式 arr 的类型就是 int* 型。

代码示例:

#include <stdio.h>

int main()
{
	int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
	int* p = arr;
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("&a[%d] = %p   p+%d = %p\n", i, &arr[i], i, p + i);
	}
	return 0;
}

运行结果:

&a[0] = 00AFFEAC   p+0 = 00AFFEAC
&a[1] = 00AFFEB0   p+1 = 00AFFEB0
&a[2] = 00AFFEB4   p+2 = 00AFFEB4
&a[3] = 00AFFEB8   p+3 = 00AFFEB8
&a[4] = 00AFFEBC   p+4 = 00AFFEBC
&a[5] = 00AFFEC0   p+5 = 00AFFEC0
&a[6] = 00AFFEC4   p+6 = 00AFFEC4
&a[7] = 00AFFEC8   p+7 = 00AFFEC8
&a[8] = 00AFFECC   p+8 = 00AFFECC
&a[9] = 00AFFED0   p+9 = 00AFFED0

? ? ? ? 代码声明了数组 arr 和指针 p ,指针 p 的初始值是 arr ,因为数组名 arr 会被解释为 &arr[0],所以存入 p 的值为 &arr[0] 的值,也就是指针 p 会被初始化为指向数组 arr 的起始元素 arr[0]。

? ? ? ? 由运行结果也可看出,指向个元素的指针 p+i 和 &arr[i] 是等价的。 &arr[i] 是指向元素 arr[i] 的指针,其值是?arr[i] 的地址。

指向数组元素的指针,有以下规则成立:

指针 p 指向数组中的元素 e 时

  • p+i 为指向元素 e 后第 i 个元素的指针。
  • p-i?为指向元素 e 前第 i 个元素的指针。

数组名在以下两种情况下不被视为指向起始元素的指针:

1.作为 sizeof 运算符的操作数出现时。

? ? ? ? sizeof(数组名) 不会生成指向起始元素的指针的长度,而是生成数组整体的长度。

2.作为取地址运算符 & 的操作数出现时。

? ? ? ? & 数组名 不是指向起始元素的指针的指针,而是指向数组整体的指针。


1.2 指针运算符和下标运算符

指向数组内部元素的指针 p+i 前加指针运算符 *?

? ? ? ? 因为 p+i 是指向 p 所指元素后第 i 个元素的指针,所以在其前加上指针运算符后得到的 *(p+i) 就是该元素的别名。若 p 指向 a[0] ,那么表达式 *(p+i) 就表示 a[i] 本身。

指针 p 指向数组中的元素 e 时,

  • 指向元素 e 后第 i 个元素的 *(p+i),可以写成 p[i]。
  • 指向元素 e 前第 i 个元素的 *(p-i),可以写成 p[-i]。

????????关于指针的运算可参考上篇博文C语言 指针-CSDN博客

代码示例:

#include <stdio.h>

int main()
{
	int i = 0;
	int arr[5] = { 1,2,3,4,5 };
	int* p = arr;//arr是首元素地址
	int sz = sizeof(arr) / sizeof(arr[0]);
	for (i = 0; i < sz; i++)
	{
		printf("arr[%d] = %d   *(arr+%d) = %d   p[%d] = %d   *(p+%d) = %d\n", i, arr[i], i, *(arr + i), i, p[i], i, *(p + i));
	}
	for (i = 0; i < sz; i++)
	{
		printf("&arr[%d] = %p   arr+%d = %p   &p[%d] = %p   p+%d = %p\n", i, &arr[i], i, (arr + i), i, &p[i], i, (p + i));
	}
	return 0;
}

运行结果:

arr[0] = 1   *(arr+0) = 1   p[0] = 1   *(p+0) = 1
arr[1] = 2   *(arr+1) = 2   p[1] = 2   *(p+1) = 2
arr[2] = 3   *(arr+2) = 3   p[2] = 3   *(p+2) = 3
arr[3] = 4   *(arr+3) = 4   p[3] = 4   *(p+3) = 4
arr[4] = 5   *(arr+4) = 5   p[4] = 5   *(p+4) = 5
&arr[0] = 004FFD38   arr+0 = 004FFD38   &p[0] = 004FFD38   p+0 = 004FFD38
&arr[1] = 004FFD3C   arr+1 = 004FFD3C   &p[1] = 004FFD3C   p+1 = 004FFD3C
&arr[2] = 004FFD40   arr+2 = 004FFD40   &p[2] = 004FFD40   p+2 = 004FFD40
&arr[3] = 004FFD44   arr+3 = 004FFD44   &p[3] = 004FFD44   p+3 = 004FFD44
&arr[4] = 004FFD48   arr+4 = 004FFD48   &p[4] = 004FFD48   p+4 = 004FFD48
  • p+i 指向 arr[i] ,所以 *(p+i) 是 arr[i] 的别名。
  • *(p+i) 可以写为 p[i] ,所以 p[i] 也是arr[i] 的别名。
  • 数组名 arr 是指向起始元素 arr[0] 的指针,所以 arr+i 就是指向元素 arr[i] 的指针。
  • 指针 arr+i 指向元素 arr[i] ,所以在其前写上指针运算符后得到的 *(arr+i) 就是 arr[i] 的别名。

访问各元素的4个表达式:?arr[i] 、*(arr + i) 、 p[i] 、*(p + i) 。

指向各元素指针的4个表达式:?&arr[i] 、arr + i 、&p[i] 、p + i 。

总结:

? ? ? ? int* 型指针 p 指向 int 型数组 arr 的起始元素?arr[0] 时,指针 p 的行为就和数组 arr 本身一样。

????????这里的类型可以是 char 、double、int?等等。


1.3 数组传参

????????数组传参传的是首元素地址。

数组名传参代码示例:

#include <stdio.h>

void text(int arr[], int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}
int main()
{
	int arr[10] = { 0 };
	text(arr, 10);
	return 0;
}

运行结果:

0 0 0 0 0 0 0 0 0 0

指针传参代码示例:

#include <stdio.h>

void text(int* p, int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", *(p + i));
	}
}

int main()
{
	int arr[10] = { 0 };
	text(arr, 10);
	return 0;
}

运行结果:

0 0 0 0 0 0 0 0 0 0

? ? ? ? 上述两个代码等效。

二、二级指针

????????指针变量也是变量,是变量就有地址,那指针变量的地址也可以存放在指针里。?就是二级指针。

代码示例:

#include <stdio.h>

int main()
{
	int a = 0;
	int* pa = &a;
	int** ppa = &pa;
	**ppa = 6;
	printf("%d", a);

	return 0;
}

运行结果:

6

pa是一个指针变量,一级指针变量。

ppa是一个二级指针变量。

对ppa解引用 *ppa ,找到 pa;再解引用 **ppa 才可以找到 a。

int* pa = &a;

pa前面的int表示 pa 指向的对象是int类型的,*说明 pa 是指针变量。

int** ppa = &pa;

int* 是说明 ppa 指向的对象是 int* 类型,后面的 * 是说明 ppa 是指针。

总结:

? ? ? ? 二级指针变量是用来存放一级指针变量的地址的。

三、指针数组

? ? ? ? 存放指针的数组就是指针数组。

3.1 一维数组

代码示例:

#include <stdio.h>

int main()
{
	int arr[5] = { 0,1,2,3,4 };
	int* parr[5] = { &arr[0],&arr[1], &arr[2], &arr[3], &arr[4] };
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d ", *(parr[i]));
	}

	return 0;
}

运行结果:

0 1 2 3 4

3.2 二维数组

普通二维数组的使用代码示例:

#include <stdio.h>

int main()
{
	int arr[3][4] = { 1,2,3,4,2,3,4,5,3,4,5,6 };
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 4; j++)
		{
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
	return 0;
}

运行结果:

1 2 3 4
2 3 4 5
3 4 5 6


二维指针数组代码示例:

#include <stdio.h>

int main()
{
	int arr1[4] = { 1,2,3,4 };
	int arr2[4] = { 2,3,4,5 };
	int arr3[4] = { 3,4,5,6 };

	int* parr[3] = { arr1,arr2,arr3 };

	int i = 0;
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 4; j++)
		{
			printf("%d ", parr[i][j]);
		}
		printf("\n");
	}
	return 0;
}

运行结果:

1 2 3 4
2 3 4 5
3 4 5 6

? ? ? ? parr 指针数组指向3个数组 arr1、arr2、arr3 的数组首元素地址 arr1[0]、 arr2[0]、 arr3[0]。

parr 因为是指向 int 型数组的指针,所以 parr 类型为 int* 。

? ? ? ? 指针数组 parr 把三个独立的一维数组 arr1、arr2、arr3 串在一起管理。可以运行出上述普通二维数组的代码结果。

注:在 printf 函数打印数组时操作符 [ ] 就相当于解引用操作符 * ,arr[i] 等价于 *(arr+i) 。


总结

????????以上就是今天要讲的内容,本文仅仅简单介绍了指针和数组、二级指针、指针数组的内容。

文章来源:https://blog.csdn.net/Echo_cy_/article/details/135213289
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。