系列文章目录
本文主要面向C语言初学者及新手,属于系列文章,笔者借此巩固自身同时也希望帮助更多新人更快的入门,如有不当或错误,欢迎指正。
过往系列可查阅:
C语言基础入门----(1)C语言知识储备
C语言基础入门----(2)变量、数据类型及初识函数
C语言基础入门----(3)垃圾字符回收及程序的三大基本结构
C语言基础入门----(4)常见分支语句与循环语句
C语言基础入门----(5)数组详解
本文目录
目录
前言
C语言很多人都说它是最接近底层的编程语言,其魅力所在之处就包括着今天要讲解的“指针”,这是C编程它的魅力,也是它的难点,初学者可能会在此遇到很多疑惑的地方,遇到很多问题,希望大家可以沉下心来学习这一专题。
一、指针是什么?
既然要讲指针(Pointer),那我们就需要引进一个计算机内存的概念。
在计算机中, 所有的数据都是存放在存储器中的, 不同的数据类型占有的内存空间的大小各不相同。内存是以字节为单位的连续编址空间, 每一个字节单元对应着一个唯一的编号, 这个编号被称为内存单元的地址。比如: int类型占4个字节, char类型占1个字节等。
内存为变量分配存储空间的首个字节单元的地址, 称之为该变量的地址。地址用来标识每一个存储单元, 方便用户对存储单元中的数据进行正确的访问。
C语言用变量来存储数据,用函数来定义一段可以重复使用的代码,它们最终都要放到计算机的内存中才能供 CPU 使用。数据和代码都以二进制的形式存储在内存中,CPU 只能通过地址来取得内存中的代码和数据,程序在执行过程中会告知 CPU 要执行的代码以及要读写的数据的地址。如果在这个过程中程序不小心出错,需要读写数据的地址结果给CPU的是程序代码的地址,这种情况就会发生内存访问错误。这种内存访问错误会被硬件和操作系统拦截,强制程序崩溃,常见的有段错误(Segmentation fault)和内存泄漏(一般不会报错,但是有安全隐患),堆栈粉碎(stack smashing detected)三种情况。
CPU 访问内存时需要的是地址,而不是变量名和函数名。变量名和函数名只是我们人为规定的一个名字,是地址的一种助记符,当源文件被编译和链接成可执行程序后,这些变量和函数等都会被编译器替换成地址。
假设变量 a、b、c 在内存中的地址分别是 0X1000、0X2000、0X3000,那么加法运算c=a+b将会被转换成类似下面的形式:
0X3000 = (0X1000) + (0X2000);
( )
表示取值操作,整个表达式的意思是,取出地址 0X1000 和 0X2000 上的值,将它们相加,把相加的结果赋值给地址为 0X3000 的内存
需要注意的是,虽然变量名、函数名、字符串名和数组名在本质上是一样的,它们都是地址的助记符,但在编写代码的过程中,我们认为变量名表示的是数据本身,而函数名、字符串名和数组名表示的是代码块或数据块的首地址。
至此,我们知道了在计算机中的数据存储方式,也接触到了“地址”的概念,而在C中,储存这些地址的变量就是我们所谓的指针变量,也就是说,指针的本质是一个地址。可能这么说比较抽象,那我们再来贴近下生活来说一下。
城市的楼房居住都是有门派号的,例如说小明住在xx小区10号搂3单元804,我们如果要去找小明这个人,那我们就按照这个地址去找。
放在C编程中,小明相当于是一个变量,而我们去找这个变量,就跟随着它的地址去查询即可,而记录着小明家庭地址的东西,就对应着我们编程中的指针变量。
地址:内存中每个字节单位都有一个编号(门牌号)
指针:指针就是地址
指针变量:用于存放地址的变量就叫做指针变量
二、指针的定义与使用
1.如何定义指针?
事实上,C定义一个指针的方式很简单。我们一般采取以下方式去定义一个指针。
存储方式 数据类型 *指针变量名int *pint* p
这与我们普通变量的定义方式唯一的区别就是多了一个 * ,当未定义存储方式的时候,默认是auto型。需要注意的一点是,指针的类型应该是 数据类型* 的形式,但是 * 可以依据个人编程习惯放在数据类型后紧跟着,亦或是写在变量前面。
#include <stdio.h>
int main()
{
//定义变量a,b
int a = 10;
int b = 5;
//定义一个指针变量p
int *p = &a;
//更改p的指向
p = &b;
//输出检测
printf("a=%d b=%d ptr=%d\n",a,b,*p);
printf("%p %p\n",&a,p);
printf("%p %p\n",&b,p);
printf("p_addr:%p\n",&p);
}
运行结果如图所示,借着输出检测,我们可以知道以下几点:
1.指针的本质是个地址,进行定义时候需要对其指向的变量进行取地址&操作
2.指针本身存储的是地址,但是可以通过 *指针变量 的方式获得地址内的内容
3.指针的指向可以更改(与C++的引用有所区别)
4.指针变量本身有自己的地址,与指向的变量存储空间无直接关系。
2.指针的优点
1)有效的表达更复杂的数据结构
指针我们可以让它指向任意类型的数据,灵活运用指针是一个C程序员的基本功和逻辑思维的体现。
#include <stdio.h>
struct STU
{
int age ;
char name[32];
};
int main()
{
int *p1 = NULL;
char *p2 = NULL;
float *p3 = NULL;
double *p4 = NULL;
struct STU *p5 = NULL;
}
2)动态分配内存
一般动态分配内存常用于我们进行数组扩充或者需要连续malloc()时使用,我们使用指针指向一个数组或者指向malloc开辟的空间,即可实现对内存的动态分配管理。
3)得到多于一个数的函数返回值
在我们之前的例程中,我们大多定义的函数返回值类型为void或者int,但是学习指针以后,我们便可以将字符串等多于一个数的数据作为返回值使用。
4)使程序更简洁、紧凑、高效
由于指针是对于内存地址的操作管理,所以更贴近于底层,计算机在运行程序时会更快的查找到指定的寄存器等来进行数据的计算,传输,这也是为什么C语言是处理程序最快的编程语言的原因。
至此本系列基础文章结束,下图为C基础阶段需要掌握的技能,各位读者可以学习查漏补缺。
总结
以上就是今天要讲的内容,本文仅仅简单介绍了指针,而在开发中指针实际上有着更高阶的使用,例如二级指针,多级指针;再例如算法中常见的双指针法等,灵活运用指针是一个C编程人员进阶必须掌握的一项技能。