第三十三天学习记录:C语言进阶:指针详解Ⅰ

初识指针回顾:
1、指针就是个变量,用来存放地址,地址唯一标识一块内存空间。
2、指针的大小是固定的4/8个字节(32位平台/64位平台)。
3、指针是有类型,指针的类型决定了指针的±整数的步长,指针解引用操作的时候的权限。
4、指针的运算。

推薦網站:segmentfault

字符指针

在指针的类型中有一种指针类型为字符指针:char*

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>

int main()
{
	char arr[] = "abcdef";
	char* pc = arr;
	char* p = "abcdef";//是一个常量字符串
	printf("%s\n", arr);
	printf("%p\n", arr);
	printf("%s\n", pc);
	printf("%s\n", p);
	printf("%p\n", p);
	printf("%c\n", *p);
	return 0;
}

输出如下:
在这里插入图片描述

指针数组

指针数组是数组,用来存放指针
指针数组的主要用法。

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>

int main()
{
	int arr[10] = { 0 };//整型数组
	char ch[5] = { 0 };//字符数组
	int* parr[4];//存放整型指针的数组-指针数组
	char* pch[5];//存放字符指针的数组-指针数组
	return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>

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 = 0;
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 5; j++)
		{
			printf("%d ", *(parr[i] + j));
		}
		printf("\n");
	}
	return 0;
}

输出:
在这里插入图片描述

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

数组指针

数组指针的定义
数组指针是指针。

int arr[10]={1,2,3,4,5,6,7,8,9,10}
arr-首元素地址
&arr[0]-首元素地址
&arr-数组的地址

int (*p)[10]=&arr

解释:

int (*p)[10];
//解释:p先和 星 结合,说明p是一个指针变量,然后指着指向的是一个大小为10个整型的数组。所以p是一个指针,指向一个数组,叫数组指针。
//这里要注意:[]的优先级要高于 星 号的,所以必须加上()来保证p先和 星 结合。

例子:

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>

int main()
{
	char* arr[5];
	char* (*pa)[5]=&arr;

	int arr2[10] = { 0 };
	int(*pa2)[10] = &arr2;

	return 0;
}

例题:(方法一方法二不推荐使用)

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	//int (*pa)[10] = &arr;
	//int i = 0;
	//for (i = 0; i < 10; i++)//方法一
	//{
	//	printf("%d ",(*pa)[i]);
	//}

	//int(*pa)[10] = &arr;
	//int i
	//for (i = 0; i < 10; i++)//方法二
	//{
	//	printf("%d ",*(*pa + i));//*pa==arr
	//}

	int *p=arr;//方法三
	int i = 0;
	for (i = 0; i < 10; i++)//方法一
	{
		printf("%d ",*(p+i));
	}

	return 0;
}

使用:

#define _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>
#include<Windows.h>

void print1(int arr[3][5], int x, int y)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < x; i++)
	{
		for (j = 0; j < y; j++)
		{
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
}

void print2(int(*p)[5], int x, int y)
{
	int i = 0;
	for (i = 0; i < x; i++)
	{
		int j = 0;
		for (j = 0; j < y; j++)
		{
			printf("%d ", p[i][j]);
			//printf("%d ", *(p[i] + j));
			//printf("%d ", *(*(p + i)+j));
			//printf("%d ", (*(p + i))[j]);
		}
		printf("\n");
	}
}

int main()
{
	int arr[3][5] = { { 1,2,3,4,5 },{ 2,3,4,5,6 },{ 3,4,5,6,7 } };
	//print1(arr,3,5);//基本方法  arr-数组名-数组名就是首元素地址
	print2(arr, 3, 5);
	return 0;
}

使用2:

#define _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>
#include<Windows.h>

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

指针和数组是两种不同的数据类型,但它们之间有一些相同和不同之处。

相同点:

+都可以用来访问内存中的数据;
+都可以通过指针算术运算或数组的索引操作来访问该数据;
+都具有传递参数和返回值等功能。
不同点:

+指针是一个变量,它存储了一个内存地址,而数组是一组相同数据类型的元素集合;
+指针可以指向任何数据类型的内存地址,而数组只能包含相同类型的元素;
+指针可以动态修改指向的内存地址,而数组的大小在编译时已经确定,不能动态修改;
+指针本身占用空间,而数组不占用额外空间,其大小仅取决于元素个数和类型大小。

总之,指针和数组都是非常重要的C语言特性,它们可以帮助我们更好地管理和使用内存。.

自行探索补充:
在这里插入图片描述
在这里插入图片描述
(&(*pa))[i]和&(*pa)[i]不一样。前者步长是整个数组,后者是一个元素。

(&(*pa))[i]和&(*pa)[i]是不同的表达式。

首先,&(pa)[i]表示的是指向pa所指向的数组的第i个元素的指针。pa本身是一个指向数组首元素的指针,所以pa表示数组的首元素,(*pa)[i]表示数组的第i个元素,然后&(*pa)[i]表示该元素的地址。

而(&(*pa))[i]表示的是指向pa所指向的指针所在内存地址处的数组的第i个元素的指针。即将pa指向的指针本身视为一个数组,其下标为0的元素的地址就是pa指向的内存地址,所以&(*pa)就是pa指向的内存地址,(&(*pa))[i]就是该地址后面的第i个元素的地址。

因此,这两个表达式虽然都涉及到指针和数组,但其含义和计算方式是不同的。

在这里插入图片描述
在这里插入图片描述
int(*pa)[10] = &arr;
printf(“%p\n”, *pa);
printf(“%p\n”, pa);

在这段代码中,pa是一个指向大小为10的数组的指针, &arr是整个数组的地址。因为&arr是一个指向数组arr的指针,所以可以将&arr赋值给指向数组的指针pa

在第一个printf语句中,*pa将解引用指针pa指向的数组,因此表达式*pa的值是数组的首个元素的地址。因为数组的元素的大小是sizeof(int),因此首个元素的地址也是该数组的地址。所以第一个printf打印的是数组arr的地址。

在第二个printf语句中,我们直接打印指针pa的值,这个值是指向数组arr的地址,因此第二个printf打印的就是数组arr的地址。

值得注意的是,*papa指向的内存位置不同,*pa指向的是数组中第一个元素的地址,而pa指向的是整个数组的地址。这两个指针指向的内存地址是不同的,尽管它们的值相同。

为什么定义一个int* p之后,p也能通过p[]来表示?

在C语言中,指针和数组在使用上是非常相似的,有时它们可以互换使用,这是因为数组的下标运算符[]可以被重载,可以被用于指针运算做下标。

指针p本身是一个地址值,p[]实际上等价于*(p + i),即取指针p所指向的内存地址加上下标i所表示的偏移量的值,然后再解引用得到该地址处的值。由于编译器在处理数组时,会将数组名先转换成指向数组首元素的指针,所以在使用数组下标运算符[]时,指针的使用方式可以与数组等价使用。因此,定义一个int* p后,p也能通过p[]来表示。

需要注意的是,这种方式只适用于已经申请了合法内存地址的指针,否则会出现未定义行为或者导致程序崩溃。同时,指针与数组的实际类型和内存布局等仍然有所区别,因此在某些特定情况下,应该明确区分指针和数组的使用方式。

int arr[5]; //arr是一个5个元素的整型数组

int * parr1[10]; //parr1是一个数组,数组有10个元素,每个元素的类型是int*,parr1是指针数组。

int (*parr2)[10]; //parr2是一个指针,该指针指向了一个数组,数组有10个元素,每个元素的类型是int.parr2是数组指针。

int (*parr3[10])[5]; //parr3是一个数组,该数组有10个元素,每个元素是一个数组指针。该数组指针指向的数组有5个元素,每个元素是int.

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值