admin管理员组

文章数量:1794759

C语言——指针(1)

一.地址与指针

在计算机中,数据都是存放在内存中的,不同的数据类型所占用的内存空间并不相同。内存的单位是字节,1个字节就是1个内存单元,每个内存单元对应着一个独一无二的编号,而这个编号就是地址

在C语言中,指针其实就是内存的地址,我们使用指针变量来存放指针(一般来说,没有特别说明,大家都是默认“指针”就是“指针变量”)。我们可以通过指针(地址)找到对应的内存空间里存放的数据。

所以总的来说,我们可以这样理解,内存单元的编号==地址==指针。

二.指针的使用

在C语言中,我们使用取地址操作符&来获取变量的地址。我们将其地址存放到指针当中。

值得注意得是,变量的类型不同,也就是字节数不同。比如说int类型得变量大小是4个字节,而取地址操作符&取出的地址是首个字节的地址 ,换句话说,也就是地址较小的字节的地址。

当我们想要使用这个指针时,我们用解引用操作符*,通过指针找到指向的空间。

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

int* pa = &a : 取出 a 的地址并存储到指针变量 pa 中,pa的类型是int*,说明pa是指针变量。

printf("%p\n", pa) :在运行结果中,我们看到pa的值是00D8FA18,就是存放a变量内存的内存编号

*pa = 0 :*pa 的意思就是通过pa中存放的地址,找到指向的空间,也就是变量a。(*pa其实就是a),把0的值赋给a。

三.指针大小

指针变量的⼤⼩取决于地址的⼤⼩ 32 位平台下地址是 32 个 bit 位(即 4 个字节) 64 位平台下地址是 64 个 bit 位(即 8 个字节)

X86(32位)环境下:

X64环境下:

指针变量的大小与其类型是无关的, 只与运行环境有关。

同样的环境下(32位或64位),不同类型的指针变量大小一样的

四.指针类型的意义

1.指针的类型决定了对指针解引⽤的时能访问多少个字节。 2.指针的类型决定了指针+-1跳过多少个字节。

我们看下面两段代码。

代码一:

代码二:

调试我们可以看到,代码1会将n的4个字节全部改为0,但是代码2只是将n的第⼀个字节改为0。

所以这刚好证明了指针的类型决定了对指针解引⽤的时能访问多少个字节。

我们再看下面的代码及其结果

char* 类型的指针变量+1跳过1个字节int* 类型的指针变量+1跳过了4个字节

所以指针的类型决定了指针+-1跳过多少个字节。


在指针中有一种特殊类型的指针,void*类型的指针,也叫做泛型指针

1.void*指针可以⽤来接受任意类型地址。

2.void*指针不能直接进行指针的+-整数解引⽤的运算。

void*指针一般用于函数参数部分,接收不同类型的地址,实现泛型编程的效果。这样一个函数就能处理多种类型的数据。

五.const修饰指针

1.const如果放在*的左边,修饰指针指向的内容,指针指向的内容不能通过指针来改变。但是指针本身的内容可变。 2.const如果放在*的右边,修饰的是指针本⾝,指针的内容不能修改。但是指针指向的内容可以通过指针来修改。

六.指针运算

1.指针+-整数 2.指针 - 指针 3.指针的关系运算

关于指针加减整数,上面已经提及,这里不过过多赘述,可以看下下面具体的例子。

打印数组:


指针减指针得到的是两个指针指向内存之间元素的个数。

模拟实现strlen函数:


指针的关系运算:指针与指针比较大小。

可以用下面的例子辅助了解。

七.野指针

野指针形成原因:

1.指针未初始化。 2.指针越界访问。 3.指针指向的空间释放。


1.

切记指针要初始化!!!

2.

关于指针的越界访问,可以通过下面指针访问数组的例子说明。

从上面图可知,这里如果通过p+sz这个指针访问数组,那么这个指针就越界访问了。

所以在上面提及的访问数组时设置p < arr +sz这个条件,防止指针访问越界。

3.

对于指针指向的空间释放,我们看下面这个关于函数的例子。

上面的p指针就是野指针,其指向的内存已经释放。为什么?

原因就是,test()函数返回的是函数内部临时创建变量n的地址,而当test()函数被调用完之后,其占用的内存就会被回收变量n就被销毁了。但是p指针接收了n的地址,其指向的空间已经被释放了,所以p指针就成了野指针。


如何避免野指针?

从上面野指针的成因不难知道相对应的措施。

1.指针初始化

在实际写代码过程中,如果我们知道指针指向哪里,那就直接让指针接收地址。

如果不知道,可以给指针赋值NULLNULL是空指针,它是C语言定义的标识符常量,其值为0,地址0是无法使用的,强行使用编译器会报错。


2.谨防指针越界访问

当我们调用指针时,要知道指针的允许访问的范围,杜绝越界访问,最好设置访问条件来确保指针不会越界访问。


3.不要接收局部变量的地址

用指针接收局部变量的地址会造成野指针。


4.指针不使用时,置NULL,使用前检查其有效性

当指针不再使用时,我们要及时把其置为NULL指针。指针其实给予了我们直接掌控内存的权利,胡乱使用指针是非常危险的,有可能直接导致代码崩溃

下面介绍下宏 assert()

头文件:assert.h

assert() 接收表达式,表达式结果为真,不会产生作用。表达式结果为假,程序就会报错。

如下图:

由此可知,我们可以使用assert()来检查指针是否为空指针

想要关闭assert()的功能也非常简单,只需在头文件(assert.h)前加上宏 NDEBUG。


关于指针就先写到这里了,希望可以帮助到有需要的人。

我们下一篇指针再见!!!(摸鱼摸鱼

本文标签: C语言指针(1)