C语言 -- 数组指针 与 指针数组

C语言 -- 指针进阶

  • 字符指针
    • 一般使用
    • (字符串)区分字符数组与字符指针
  • 指针数组
  • 数组指针
    • 指针数组 与 数组指针 的区分
    • &数组名 与 数组名 的区分
    • 数组指针的使用
    • 小总结

先复习复习(点击进入) -> 指针基础

先把握以下几个概念:

  1. 指针就是个变量,用来存放地址,地址唯一标识一块内存空间
  2. 指针的大小是固定的,32位平台位4个字节大小,64位平台位8个字节大小
  3. 指针有类型,指针的类型决定了指针+或者-整数的步长,指针解引用操作的时候的权限
  4. int a = 10;
    int *pa = &a;
    p的值为 a的地址
    *p的值为 p所指向空间的值,即 *p= 10
    &p的值为指针变量 p的地址

字符指针

字符指针就是指向字符的指针:char*;

一般使用

void main()
{
	char ch = 'a';
	char* pch = &ch;
	*pch = 'w'; //修改字符ch的值为w
}

(字符串)区分字符数组与字符指针

观察以下两种定义方式:

char str1[] = “abcd”;
char *str2 = “abcd”;

上面定义str1与受str2都可以称为“字符串”,但是两者却有着本质的区别:

  1. char str1[] = “abcd”;
  • 应该称str1为一个字符数组
  • 运行可知sizeof(str1) 的值为5
  • 本质是开辟了一块大小为5字节的内存空间,该内存空间的名字为str1,空间内存放’a’, ‘b’, ‘c’, ‘d’, ‘\0’
  1. char *str2 = “abcd”;
  • 应该称str2为字符指针
  • 运行可知sizeof(str2) 的值为4(32位平台)
  • 本质是将“abcd”的首字符的地址放入了str2中,“abcd”是一个常量字符串,不能通过指针去修改其值

下面,请仔细观察下面代码:

void main()
{
	char str1[] = "hello bit.";
	char str2[] = "hello bit.";
	char* str3 = "hello bit.";
	char* str4 = "hello bit.";
	if (str1 == str2)
		printf("str1 and str2 are same\n");
	else
		printf("str1 and str2 are not same\n");
	if (str3 == str4)
		printf("str3 and str4 are same\n");
	else
		printf("str3 and str4 are not same\n");
}

该代码的输出结果是:
str1 and str2 are not same
str3 and str4 are same

出现这个结构的原因如下:

str1与str2都是字符数组,只是用相同的常量字符串进行了初始化,但是两者所开辟的内存块不同;
str3与str4都是字符指针,两者指向的是同一个常量字符串,C语言/C++会将常量字符串存储到单独的一个内存区域,当几个指针指向同一个字符串的时候,他们是机会指向同一块内存。

指针数组

指针数组 – 是数组,是存放指针的数组

int *arr1[10]; //存放整型指针的数组
char *arr2[4]; //存放字符指针的数组
char **arr3[5]; //存放二级字符指针的数组

数组指针

数组指针 – 是指针,是指向数组的指针

指针数组 与 数组指针 的区分

  1. int *arr1[10]; //指针数组
  2. int (*arr2)[10]; //数组指针

可以看出arr1与arr2的区别就是一对小括号 () ;
那如何理解呢?

  • [] 的优先级是高于 * 的,所以在没有 () 时,名字会先与 [] 结合,所以其大前提就是一个数组;
  • 而加了 () 之后,名字会先与 * 结合,所以其大前提就是一个指针。

&数组名 与 数组名 的区分

先看一段代码:

void main()
{
	int arr[] = { 1,2,3,4 };
	printf("%p\n", arr);
	printf("%p\n", &arr);
}

通过运行可以发现,&arr与arr打印出来的值是一样的,都是首元素的地址。但是两者的含义一样吗?
当然不一样

为了验证两者是不同的,先来看下面一段代码:

void main()
{
	int arr[] = { 1,2,3,4 };
	printf("arr: %p\n", arr);
	printf("arr+1: %p\n", arr + 1);

	printf("&arr: %p\n", &arr);
	printf("&arr+1: %p\n", &arr + 1);
	printf("%d", sizeof(arr));

}

运行之后发现,arr+1只增加了4个字节,而&arr+1增加了16(十六进制的10是十进制的16)个字节。

arr与&arr的值虽然一样,但是含义不一样

  • arr的值是数组首元素的地址,arr+1就是数组第二个元素的地址
  • &arr标识的是整个数组的地址,&arr+1,也就是数组的地址+1,跳过整个数组的大小,数组的大小为16,所以&arr+1相对于&arr的差值为16.

数组指针的使用

  1. 既然数组指针是指向数组的指针,那么指针中存放的应该是数组的地址
    代码示例:
void main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
	int(*parr)[10] = &arr; //把数组arr的地址赋值给指针变量parr
}
  1. 一个数组指针的使用代码示例:
void print_arr1(int arr[][3], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
}

void print_arr2(int (*parr)[3], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			printf("%d ", parr[i][j]);
		}
		printf("\n");
	}
}

void main()
{
	int arr[5][3] = { 1,2,3,4,5,6,7,8,9,10 };

	print_arr1(arr, 5, 3);

	printf("\n---------------\n");
	
	print_arr2(arr, 5, 3);

}
  • 对于二维数组 arr[5][3] 来说,可以认为其每一个元素都是一个有三个元素的一维数组(arr[3]),这个二维数组一共有5个这样的一维数组。
  • 数组名表示的是首元素的地址,所以在函数print_arr2中,可以用数组指针来接收二维数组的名字arr。

小总结

最后,来看看下面代码的含义吧:

int arr[5]; //整型数组
int *parr1[10]; //指针数组
int (*parr2)[10]; //数组指针

int (*parr3[10]) [5]; //数组指针数组
是一个数组,该数组存放的是指针,存放的指针指向的是整型数组

你可能感兴趣的:(C语言,c语言,开发语言,后端)