首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【C语言进阶】指针1

【C语言进阶】指针1

作者头像
良木生香
发布2026-01-09 14:18:04
发布2026-01-09 14:18:04
1130
举报

   百尺竿头须进步。

讲完之前的C语言的基础知识后,现在我们来讲讲C语言一个重要的部分--指针

一、内存与地址

1.内存

      在讲述内存的相关内容之前,先从生活中的例子来引入。学校中的宿舍楼往往有六七楼这么高,每一层都有差不多有二十个房间及以上,咱想想,如果这些房间都没有编号,那么宿舍楼管理起来是不是很混乱呢?朋友想来宿舍找你串门都找不到你在哪个宿舍,但是当我们根据实际情况宿舍加上门牌号之后,一切都变得有序起来了,像201、202、203、304.......

      将现实生活中的情况反映到计算机中也是一样的,计算机从内存中读取数据,处理之后的数据也会放进内存中。既然内存这么大,计算机又是怎样在内存中读取数据的呢?原来,内存也是被划分成一个个存储单元的,内个单元的大小取一个字节,这里要补充一下一些单位的换算:

代码语言:javascript
复制
1byte = 8bit    //1个字节等于8个比特位
1KB = 1024byte
1Mb = 1024KB
1Gb = 1024MB
1TB = 1024GB
1PB = 1024TB

生活中我们将门牌号称之为地址,在计算机中亦是如此,这些内存编号我们也将其称为地址

而在C语言中,这些地址又有了一个新的名字---指针

由此我们可以这样理解:

内存单元编号 == 地址 == 指针

这里还要简单讲一下,在计算机中,我们经常能看到这是32位或者是64位机器,这里的32和64代表的就是这台计算机中地址线的数量,32位机器有32根地址线,64位机器有64根地址线,而每一根地址线上只有0或者1两种表示形态

二、指针变量于地址

1.取地址操作符(&)

既然指针是围绕地址展开的,那么肯定少不了怎么获取地址这个问题。在C语言中,我们用 “&”这个符号来帮助我们获取地址,并将其称之为“取地址符”。我们在定义变量的时候其实就是向内存申请一块存储空间,例如:

代码语言:javascript
复制
#include<stdio.h>
int main()
{
    int a = 10;
    return 0;
}

这里的 a = 10就是在告诉内存,我要申请一块大小为4个字节的内存来存放变量a,然后将他赋值为10 ,而下面的代码:

代码语言:javascript
复制
#include<stdio.h>
int main()
{
    int a = 10;
    &a;
    printf("%p",&a);
    return 0;
}

但我会运行这段代码之后,运行结果可以得到:

这时候的运行结果就是此时变量a在内存中的地址(指针),但是这个结果是一成不变的吗?当我们再次运行这个程序的时候,再看看结果:

由此可见,我们的变量在内存中存放的位置不是固定的,是随着程序开始后才固定的。

2.指针变量与解引用操作符

1.指针变量

计算机中有许多东西是相通的。既然我们能取出一个变量的地址,那么就一定有可以存放这个地址的变量,这是后就出现了一种变量----指针变量,用来存放变量的地址,也就是我知道了你的门牌号之后,我要拿一个小本本开记录你的门牌号,而指针变量就相当于是这个小本本。指针变量的命名与普通变量命名规则相似:

代码语言:javascript
复制
#include<stdio.h>
int main()
{
    int a = 10;
    int* p = &a;
    printf("%p",p);
    return 0;
}

这里的p就是一个指针变量,用来存放a的地址。而“*”这个符号表示的就是,这个p变量是一个指针变量,而int表示的是,这个指针变量p指向的对象是一个整型变量,简而言之就是,p这个指针变量里存放的是一个整型变量的地址

上述代码中指针变量存放的是整型变量的地址,也可以存放其他类型的地址,如:

代码语言:javascript
复制
#include<stdio.h>

int main()
{
	char ch = 'w';
	char* p = &ch;
	printf("%p", p);
	return 0;
}

想要存放其他类型的地址,只要改变类型名称即可。

2.解引用操作符

我们常常说,事物具有两面性,既然我们可以通过变量来找到这个变量的地址,那么我们能不能通过地址来找到变量呢?答案是,当然可以的老铁!

这里我们就要用“*”(解引用操作符)来进行这个操作了。

注意:这里的“*”与指针变量命名的*意义不相同!这里的“*”(解引用操作符)的含义是通过这个指针变量来找到原来的变量,而指针命名的“*”的含义是,告诉系统,这个变量是指针变量,不是常规变量。

代码语言:javascript
复制
#include<stdio.h>

int main()
{
	int a = 10;
	int* p = &a;        //定义一个指针变量P来存放a的在地址
	printf("%p\n", p);
	printf("%d", *p);   //*P是通过指针变量来找到变量a
	return 0;
}

简而言之,*p就是a,而p存放的是a的地址

3.指针变量的大小

在环境为32为的机器上,一个地址就有32个bit位,那么指针变量的大小就是四个字节 而在环境为64位的机器上,一个地址就有64个bit位,那么指针变量的大小就是八个字节 如果想要指针变量来存放地址,那么指针变量的大小得是4个字节的才可以(32位)

我们也可以通过以下代码来计算当前环境的指针变量的大小。

代码语言:javascript
复制
#include<stdio.h>
int main()
{
    int a = 10;
    int* p = &a;
    printf("%d",sizeof(int*));
    return 0;
}

注意:指针变量的大小与类型是无关的,与环境有关,也就是说,在32位环境下,指针变量的大小就一定是4个字节,不论是int或者是double类型,都是一样的,64位同理也是如此。

三、指针变量大小的意义

刚才我们说到,在大环境相同的情况下,指针变量的大小是不变的,那为什么我们还要将指针变量写成 int*  或者是  char* 呢?为什么不能用统一类型来命名指针变量呢?这就是我们接下来要讨论的话题

1.指针的解引用

首先先运行下面这段代码:

代码语言:javascript
复制
#include<stdio.h>
int main()
{

	int a = 0x11223344;
	int* p = &a;
	*p = 0;
	return 0;
}

调试起来:

当创建变量a之后,a的值为:

当执行完

代码语言:javascript
复制
*p = 0;

这句代码时,a的值变为了:

这时我们可以得出结论,指向的对象为整形类型的指针一次可以访问4个字节的内存;

那我们再运行下面的代码:

代码语言:javascript
复制
#include<stdio.h>
int  main()
{
    int a=10;
    char* p = (char*)&a;   //强制类型转换
    *p = 0;
    return 0;
}

此时a的值为:

但是运行完 *p = 0之后,a的值变为:

由此可见,char 类型的指针变量一次只能访问1个字节的内存空间。

综上:虽然指针变量在大环境下的大小是一样的,但是不同类型的指针变量一次能够访问的内存空间是不同的。

2.指针+-整数

运行下面代码,看看地址的变化情况:

代码语言:javascript
复制
#include<stdio.h>
int main()
{
	int a = 10;
	int* pi = &a;
	char* pc = (char*)&a;
	printf("&a   = %p\n", &a);
	printf("pi   = %p\n", pi);
	printf("pi+1 = %p\n", pi+1);
	printf("pc   = %p\n", pc);
	printf("pc+1 = %p\n", pc+1);
	return 0;
}

运行结果为:

由此可见,int*与char*类型在加减整数时,结果是不一样的,char*+1跳过了一个字节,而int*+1跳过了4个字节

综上:指针类型决定了指针向前或向后走一步的距离是多大

四、指针的运算

指针的运算有基本的三种:

  1. 指针+-整数
  2. 指针-指针
  3. 指针的大小比较

下面我们一一来介绍

1.指针+-整数

按照惯例,先运行下面这个代码:

代码语言:javascript
复制
#include<stdio.h>
int main()
{
	int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	int* pa = a;
	int count = sizeof(a) / sizeof(a[0]);
	for (int i = 0; i < count; i++)
	{
		printf("%d ", a[i]);
	}
	printf("\n");
	for (int i = 0; i < count; i++)
	{
		printf("%d ", *(pa + i));  //这里就是指针+-整数
	}
	return 0;
}

运行结果为:

说明通过指针加减整数,可以定位到数组的任意元素,不需要手动计算偏移量。

2.指针-指针

先运行下面这段代码:

代码语言:javascript
复制
#include<stdio.h>
#include<string.h>

int my_strlen(char* str)
{
	char* pstr = str;
	while (*pstr != '\0')
	{
		pstr++;
	}
	return pstr - str;    //指针-指针
}


int main()
{
	char str[] = "abcdefgh";
	int sz = my_strlen(str);
	printf("%d", sz);
	return 0;
}

说明通过  指针-指针  的方式,可以计算出两个指针之间的元素的个数。

3.指针的关系运算

运行下面代码:

代码语言:javascript
复制
#include<stdio.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9 };
	int* p = arr;
	int sz = sizeof(arr) / sizeof(arr[0]);
	while (p < arr + sz)    //指针的关系运算
	{
		printf("%d ", *p);
		p++;
	}
	return 0;
}

运行结果为:

由此可见,指针的关系运算可以实现像打印数组元素这样的功能

文章是自己写的哈,有啥描述不对的、不恰当的地方,恳请大佬指正,看到后会第一时间修改,感谢您的阅读。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-10-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、内存与地址
    • 1.内存
  • 二、指针变量于地址
    • 1.取地址操作符(&)
    • 2.指针变量与解引用操作符
      • 1.指针变量
      • 2.解引用操作符
      • 3.指针变量的大小
  • 三、指针变量大小的意义
    • 1.指针的解引用
    • 2.指针+-整数
  • 四、指针的运算
    • 1.指针+-整数
    • 2.指针-指针
    • 3.指针的关系运算
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档