首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >C语言、初识指针

C语言、初识指针

原创
作者头像
xieliyu
修改2026-09-20 22:02:04
修改2026-09-20 22:02:04
340
举报
文章被收录于专栏:C语言C语言

前言:

  当我们在学习C语言中指针的时候是不是也被指针给恶心坏了?正如我的名字,当时在学习指针的时候快崩溃了,现在静下来把我的理解分享给你们。

1. 内存和地址

  为什么学指针必须先懂内存和地址?-> 因为指针本质就是存地址的变量。

  举个我们生活中的例子:假设你住在一间公寓里面,公寓里面有40多间房间没有编号,如果小明周末想要来找你玩,在他不知道你住哪间房子的情况下,就得挨个挨个去找,时间的成本增加了,如果给房间编上号比如:201,小明一到公寓门口就能直接对着编号去找你。

  这个公寓的例子,其实就是计算机内存工作的缩影:

  整栋公寓 = 计算机的内存

  每个房间 = 内存里的一个 存储 单元(1 字节)

  房间号(201)= 存储单元的地址

  小明找你 = CPU 通过地址,精准定位到内存里的数据

注意:如果你的行李很多,一个房间放不下,就需要占用连续的几个房间(比如 4 个)。

  这时候,我们说 “你的地址”,其实是指第一个房间的编号,计算机就能顺着这个编号,找到你所有的行李。对应到 C 语言里:一个int变量占 4 个字节,它的地址就是这 4 个字节中第一个字节的地址。

  你有没有想过:计算机的内存里存着成千上万的数据,它是怎么在一瞬间精准找到你要的那个值的?

  答案就是 ——地址。而我们要学的指针,本质上就是帮你拿着这个地址的 “导航员”。

___

2. 取地址操作符

  我们了解内存和地址关系后,在我们的C语言中,在创建变量的过程中,本质就是向内存申请空间。

  那么想要得到我们变量的地址,就需要用到我们的取地址(&)操作符。

在这里插入图片描述
在这里插入图片描述

  上述的代码就是创建了整型变量a,内存中申请4个字节,⽤于存放整数10,其中每个字节都有地址。

在这里插入图片描述
在这里插入图片描述

  虽然整型变量占用4个字节,我们只要知道了第⼀个字节地址,我们就能顺藤摸⽠访问到4个字节的数据。

  想要把我们的地址打印在屏幕上我们可以用%p来打印。

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

3. 指针变量和解引用操作符

  我们学习了&地址操作符后,那么取出来的地址放哪里呢?->指针变量中。

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

  指针变量也是⼀种变量,这种变量就是⽤来存放地址的,存放在指针变量中的值都会理解为地址。

  容易记不住?看小蟹给你们把他拆了。

  这⾥p左边写的是int* ,*是在说明p是指针变量,而前⾯的int 是在说明p指向的是整型(int)。

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

  *pa 的意思就是通过pa中存放a的地址,找到指向的空间,_pa其实就是a变量了;所以_pa=100,这个操作符是把a改成了100。

结构体指针间接访问操作符: ->

当我们用到结构体指针的时候我们通过结构体指针访问结构体变量的时候,我们就需要用到结构体指针间接访问的操作符:->

在这里插入图片描述
在这里插入图片描述

-> 是结构体指针访问成员的专属操作符,. 是结构体变量访问成员的操作符   

->成员 等价于 (*p).成员,是简化写法,核心是 “先通过指针找到结构体,再访问成员”

记住核心区别:有变量本身用 .,只有指针(地址)用 ->。

4. 指针变量的意义

  指针变量的大小和 类 型无关,在同一个平台下,指针变量的大小都是相同的。

在这里插入图片描述
在这里插入图片描述

结论:

  • 32位平台下地址是32个bit位,指针变量⼤⼩是4个字节

  • 64位平台下地址是64个bit位,指针变量⼤⼩是8个字节

  当我们使用int*类型的变量的时候,如果我们把他强制类型转换为char *的话,那他只会一次访问一个字节。

代码语言:c
复制
#include<stdio.h>
int main()
{
	int a =0x11223344;
	int b =0x11223344;
	int* p1 = &a;
	char* p2 = &b;
	*p1=0;
	*p2=0;
 return 0;
 }

  通过VS调试里面可以知道

在这里插入图片描述
在这里插入图片描述

  a的4个字节全部被改成了0,而b只有一个字节被改成了0。

___

5. 指针运算

代码语言:c
复制
#include <stdio.h>
int main()
{
int n = 10;
char *pc = (char*)&n;
int *pi = &n;
printf("%p\n", &n);
printf("%p\n", pc);
printf("%p\n", pc+1);
printf("%p\n", pi);
printf("%p\n", pi+1);
return  0;
}
在这里插入图片描述
在这里插入图片描述

  char*类型的指针+1或者-1,跳过一个字节。

  同理减法也是这样。

结论:

   指针的类型决定了指针向前或者向后后一步有多⼤(距离)。

  • 指针-指针:
代码语言:c
复制
#include <stdio.h>
int my_strlen(char *s)
{
	char *p = s;
	while(*p != '\0' )
	{
	p++;
	}
 return p-s;
}
int main()
{
	printf("%d\n", my_strlen("abc"));
 return 0;
}

  结论:指针-指针的运算得到的结果是两个指针之间的地址差。(得到的是一个整型)

6.二级指针

  当我们知道了一级指针,那么一级指针又是存放在哪里呢?->***当然是存放在二级指针里啦!

代码语言:c
复制
#include<stdio.h>
int main()
{
	int a = 10;
	int *pa = &a;
	int** ppa = &pa;
 return 0;
}
在这里插入图片描述
在这里插入图片描述

  当我们对ppa(*ppa)进行一次解引用的时候,其实拿到的就是pa,在对ppa(**ppa)进行一次解引用,得到的就是a

  通过ppa间接访问pa和a。

7.指针的分类

8. 1. 指针数组

  通过这个名字我们可以知道指针数组是什么。

  指针数组:简单来说就是存放指针的数组。

在这里插入图片描述
在这里插入图片描述

  parr有3个元素,每个元素类型都是int*。指针的每一个元素其实存放的都是地址(也就是指针)。

通过指针数组模拟实现二维数组。

代码语言:c
复制
#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数组中
	int* parr[3] = {arr1, arr2, arr3};
	int i = 0;
	int j = 0;
	for(i = 0; i < 3; i++)
	{
	for(j = 0; j < 5; j++)
	{
	printf("%d ", parr[i][j]);
	}
	printf("\n");
	}
 return 0;
}
在这里插入图片描述
在这里插入图片描述

9. 2. 数组指针

  数组指针和指针数组是两个概念,数组指针是指针变量而不是数组。当时小蟹在学习的时候脑子都要糊掉了,老是将这两个混起来)

代码语言:c
复制
int * p1[10];指针数组
int (*p2)[10];数组指针

  解释:加括号的情况下,编译器会让_和p2先结合,说明p2是一个指针变量,然后再和10结合,指向一个数组。

  注意: 的优先级要高宇 * 号的,所以必须加上()来保证p先和_结合。

数组指针的初始化:

代码语言:c
复制
int main()
{
int arr[10] = {0};
int (*p)[10] = &arr;
 return 0;
}

10.3. 字符串指针变量

  在指针的类型中我们知道有⼀种指针类型为字符指针

代码语言:c
复制
#include<stdio.h>
int main()
{
	char p = 'w';
	char *pc = &p;
	*pc = 'a';
 return 0;
}

  当我们存放字符串的时候。

代码语言:c
复制
#include<stdio.h>
int main()
{
	char p = "abcd";
	char *pc = &p;
	printf("%s\n",pc);
 return 0;
}

  结论:存放字符串的时候本质上是把字符串首元素的地址存放到pc中,通过pc顺藤摸瓜找到字符串的内容。

11.4. 函数指针变量

  函数指针变量:简单来说就是存放函数的地址,通过函数指针变量间接调用函数。

在这里插入图片描述
在这里插入图片描述
代码语言:c
复制
#include<stdio.h>
int add(int x ,int y)
{
 return x+y;
 }
 int sub(int x ,int y)
 {
  return x - y;
 }
int main()
{
	int(*p1)(int x,int y)=&add;
	//或者
	int(*p2)(int x,int y)=sub;
 return 0;
}

  当我们存放函数的时候,函数名就是他的地址,可以写也可以不写。

  那么函数指针怎么用呢?

代码语言:c
复制
#include<stdio.h>
int add(int x, int y)
{
	return x + y;
}
int sub(int x, int y)
{
	return x - y;
}
int main()
{
	int(*p1)(int x, int y) = &add;
	//或者
	int(*p2)(int x, int y) = sub;
	printf("%d\n", p1(2, 1));
	printf("%d\n", p2(2, 1));


	return 0;
}

  结论:当我们通过函数指针来调用 add 函数的时候要么(_p1)(1,2)这样写,要么这样写p1(1,2);

给你们留一道见过的有趣的代码,有兴趣的可以去学习学习:

( * (void (_)())0)();分别代表什么意思?

                                            完!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

目录
  • 1. 内存和地址
  • 2. 取地址操作符
  • 3. 指针变量和解引用操作符
  • 4. 指针变量的意义
  • 5. 指针运算
  • 6.二级指针
  • 7.指针的分类
  • 8. 1. 指针数组
  • 9. 2. 数组指针
  • 10.3. 字符串指针变量
  • 11.4. 函数指针变量
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档