Linux下的C语言编程(指针)

本文详细介绍了Linux环境中C语言的指针概念,包括一级、二级和三级指针的定义与理解,以及指针的内存大小和偏移。同时,文章探讨了一维和二维数组与指针的关系,说明数组名的性质以及如何通过指针进行地址偏移操作。
摘要由CSDN通过智能技术生成

目录

1 一级指针

1.1 定义

1.2 指针的内存大小

1.3 指针的偏移

1.3.1 加法偏移

1.3.2 减法偏移

2 二级指针

2.1 定义

2.2 如何理解二级指针

3 三级指针

3.1 定义

4 数组和指针的关系

4.1 一维数组与指针的关系

4.1.1 数组名的性质

4.1.2 数组名与指针的地址偏移

4.2 二维数组与指针的关系

4.2.1 数组名的性质

4.2.2 数组名与指针的关系


一提到指针大多数人可能会头大,在学习指针之前可能都有一个疑问“指针是什么呢?”,其实说白了指针就是内存地址,而指针类型的变量就是保存内存地址的变量。常说的指针类型的变量在64位的操作系统上占8个字节(32位操作系统上占4个字节)

1 一级指针

1.1 定义

如下图所示,我们在定义一级指针的时,如果是*和int(变量类型)在一起时表示的是数据类型,即整型指针类型。*和p在一起时是运算符

 tips: 中的p表示保存的是a的地址,*p表示的是a的地址对应的值

1.2 指针的内存大小

通过实验来证明:

#include <stdio.h>

int main ()
{
	char a = 1;
	short b = 1;
	int c = 1;
	long d = 1;
	float e = 1;
	double f = 1;

	char *pchar = &a;
	short *pshort = &b;
	int *pint = &c;
	long *plong = &d;
	float *pfloat = &e;
	double *pdouble = &f;

	printf("sizeof(pchar)=%ld\n", sizeof(pchar));
	printf("sizeof(pshort)=%ld\n", sizeof(pshort));
	printf("sizeof(pint)=%ld\n", sizeof(pint));
	printf("sizeof(plong)=%ld\n", sizeof(plong));
	printf("sizeof(pfloat)=%ld\n", sizeof(pfloat));
	printf("sizeof(pdouble)=%ld\n", sizeof(pdouble));
	return 0;
}

运行结果:

通过上面的实验可知指针变量占8个字节的大小(我的是64位的操作系统)

1.3 指针的偏移

1.3.1 加法偏移

指针的偏移反映为地址的变化,加法偏移地址会向下的地址偏移,通过实验来证明:

#include <stdio.h>

int main()
{
	char a = 10;
	char *pchar = &a;

	int b = 20;
	int *pint = &b;

	printf("&pchar = %p\n", pchar);
	printf("&pchar+1 = %p\n", pchar+1);
	printf("&pchar+2 = %p\n", pchar+2);
	printf("&pchar+3 = %p\n", pchar+3);
	printf("&pchar+4 = %p\n", pchar+4);
	
	printf("&pint = %p\n", pint);
	printf("&pint+1 = %p\n", pint+1);
	printf("&pint+2 = %p\n", pint+2);
	printf("&pint+3 = %p\n", pint+3);
	printf("&pint+4 = %p\n", pint+4);
	return 0;
}

运行结果:

由实验可知,pa+1表示地址偏移1个字节,具体偏移字节的大小与指针的数据类型相关,如char类型是1个字节,而int类型是4个字节

1.3.2 减法偏移

指针的偏移反映为地址的变化,减法偏移地址会向上的地址偏移,通过实验来证明:

#include <stdio.h>

int main()
{
	char a = 10;
	char *pchar = &a;

	int b = 20;
	int *pint = &b;

	printf("&pchar = %p\n", pchar);
	printf("&pchar-1 = %p\n", pchar-1);
	printf("&pchar-2 = %p\n", pchar-2);
	printf("&pchar-3 = %p\n", pchar-3);
	printf("&pchar-4 = %p\n", pchar-4);
	
	printf("&pint = %p\n", pint);
	printf("&pint-1 = %p\n", pint-1);
	printf("&pint-2 = %p\n", pint-2);
	printf("&pint-3 = %p\n", pint-3);
	printf("&pint-4 = %p\n", pint-4);
	return 0;
}

运行结果:

tips:指针使用的注意事项

*”作为一个运算符是有优先级的,如果直接使用*p++很可能会出现错误,因此要使用(*p)++

2 二级指针

二级指针理解起来比较“绕”,下面是我总结的一些心得,大家如果有什么更好的理解方法,欢迎一起交流学习!

2.1 定义

二级指针的定义如上图所示,可以理解为p表示保存的是a的地址,*p表示的是a的值(a=20),pp代表保存的是p的地址,*pp代表的是p中保存的地址即a的地址,**pp代表的是a的值(a=20)

tips:int *p=&a的意思就在定义一级指针p的时候同时给它赋值(地址),等同于先定义一个指针再给它赋值,如:int *p;p=&a;。int *是个数据类型,表示的是一个整型的指针

2.2 如何理解二级指针

理解1指针p的值就是一个地址;加*(*p)的意思就是解析p的值的值—即指针p指向的地址的值

理解2指针pp作为一个二级指针存放的是一级指针的地址;加*(*pp)的意思就是解析pp值的值,也就是一级指针的值(一级指针的值也是一个地址);而加**(**pp)的意思就是解析两次,也就是pp的值的值的值(实际上就是一级指针所指向的地址的值)

通过实验来证明:

#include <stdio.h>

int main()
{
	int a = 20;
	int *p = &a;
	int **pp = &p;

	printf("a = %d\n", a);
	printf("&a = %p\n", &a);
	printf("p = %p\n", p);
	printf("&p = %p\n", &p);
	printf("*p = %d\n", *p);
	printf("pp = %p\n", pp);
	printf("*pp = %p\n", *pp);
	printf("**pp = %d\n", **pp);

	return 0;
}

运行结果:

3 三级指针

3.1 定义

关于三级指针了解即可,在实际编码中很少使用 

如上图所示,可以理解为ppp的值就是pp的地址,*ppp表示的是pp中保存的值即p的地址,**ppp表示的是p中保存的的值即a的地址,***ppp代表的是a对应的值(a=20)

通过实验来证明:

#include <stdio.h>

int main()
{
	int a = 20;
	int *p = &a;
	int **pp = &p;
	int ***ppp = &pp;

	printf("a = %d\n", a);
	printf("&a = %p\n", &a);
	printf("p = %p\n", p);
	printf("&p = %p\n", &p);
	printf("*p = %d\n", *p);
	printf("pp = %p\n", pp);
	printf("&pp = %p\n", &pp);
	printf("*pp = %p\n", *pp);
	printf("**pp = %d\n", **pp);
	printf("ppp = %p\n", ppp);
	printf("&ppp = %p\n", &ppp);
	printf("*ppp = %p\n", *ppp);
	printf("**ppp = %p\n", **ppp);
	printf("***ppp = %d\n", ***ppp);

	return 0;
}

运行结果:

4 数组和指针的关系

4.1 一维数组与指针的关系

4.1.1 数组名的性质

一维数组名a的性质:如上图所示a中保存的是该数组的起始地址,且该地址不可修改,但可以作偏移处理(类似于指针的偏移);并且,a、&a、&a[0]的结果是相同的

通过实验来证明:

#include <stdio.h>

int main()
{
	int a[5] = {1,2,3,4,5};
	int *p = a;

	printf("a = %p\n", a);
	printf("&a = %p\n", &a);

	for (int i = 0; i < 5; i++) {
		printf("&a[%d] = %p\n", i, &a[i]);
	}

	return 0;
}

运行结果:

4.1.2 数组名与指针的地址偏移

 通过一维数组名进行地址偏移的值和通过一级指针进行地址偏移的值是相同的

通过实验来证明:

#include <stdio.h>

int main()
{
	int a[5] = {1,2,3,4,5};
	int *p = a;

	for (int i = 0; i < 5; i++) {
		printf("a+%d = %p\n", i, a+i);
	}
	for (int i = 0; i < 5; i++) {
		printf("a[%d] = %d\n", i, a[i]);
	}
	for (int i = 0; i < 5; i++) {
		printf("p[%d] = %d\n", i, p[i]);
	}
	for (int i = 0; i < 5; i++) {
		printf("*(a+%d) = %d\n", i, *(a+i));
	}
	for (int i = 0; i < 5; i++) {
		printf("*(p+%d) = %d\n", i, *(p+i));
	}

	return 0;
}

运行结果:

通过实验表明数组名a与一级指针p的性质是相同的,也就是说一位数组的数组名a就相当于是一个一级指针

4.2 二维数组与指针的关系

4.2.1 数组名的性质

二维数组名a存储的是a[0]的地址,即数组a[3][4]的首地址。而a[0]、a[1]、a[2]存储的是数组a[3][4]每行的首地址的地址;并且aa[0]a[1]a[2]的地址是无法直接获取的,但实际上是存在的,这样的目的是防止地址被修改 

通过实验来证明:

#include <stdio.h>

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

	printf("a = %p\n", a);
	printf("&a = %p\n", &a);

	for (int i = 0; i < 3; i++) {
		printf("&a[%d] = %p\n", i, &a[i]);
	}
	for (int i = 0; i < 3; i++) {
		printf("a[%d] = %p\n", i, a[i]);
	}

	return 0;
}

运行结果:

4.2.2 数组名与指针的关系

在二维数组a[3][4]中,数组名a相当于二级指针,存储的是a[0]的地址即二维数组的首地址,a[0]、a[1]、a[2]相当于一级指针存储的是数组a[3][4]每行的首地址,*a就代表a[0]的值即a[0][0]的地址,**a就代表a[0][0]的值。如下图所示:

 通过实验来证明:

#include <stdio.h>

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

	printf("a = %p\n", a);
	printf("&a = %p\n", &a);
	
	for (int i = 0; i < 3; i++) {
		printf("&a[%d] = %p\n", i, &a[i]);
	}
	for (int i = 0; i < 3; i++) {
		printf("a[%d] = %p\n", i, a[i]);
	}

	printf("*a = %p\n", *a);
	printf("**a = %d\n", **a);
	return 0;
}

运行结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张小小小张sc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值