C语言指针

指针

操作系统将硬件和软件结合起来,给程序员提供的一种对内存使用的抽象,这种抽象机制使得程序使用的是虚拟存储器,而不是直接操作和使用真实存在的物理存储器。所有的虚拟地址形成的集合就是虚拟地址空间。

内存是一个很大的线性的字节数组,每个字节固定由 8 个二进制位组成,每个字节都有唯一的编号,一个 4G 的内存,他一共有 4x1024x1024x1024 = 4294967296 个字节,那么它的地址范围就是 0 ~ 4294967296 ,十六进制表示就是 0x00000000~0xFFFFFFFF,当程序使用的数据载入内存时,都有自己唯一的一个编号,这个编号就是这个数据的地址。指针就是这样形成的。
指针的实质就是数据在内存中的地址,而指针变量是用来保存这些地址的变量。

定义指针变量

C语言中,定义变量时,在变量名 前 写一个 * 星号,这个变量就变成了对应变量类型的指针变量。必要时加( ) 来避免优先级的问题。

地址
有了指针变量,那就得让他保存其它变量的地址,使用& 运算符取得一个变量的地址。
特殊的情况,并不一定需要使用&取地址:

数组名的值就是这个数组的第一个元素的地址。
函数名的值就是这个函数的地址。
字符串字面值常量作为右值时,就是这个字符串对应的字符数组的名称,也就是这个字符串在内存中的地址。

解地址
对一个指针解地址,就可以取到这个内存数据,解地址 的写法,就是在指针的前面加一个 * 号。
解指针的实质是:从指针指向的内存块中取出这个内存数据。

空指针
空指针在概念上不同于未初始化的指针。空指针可以确保不指向任何对象或函数;而未初始化的指针则可能指向任何地方。空指针不是野指针。

野指针
野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
野指针成因

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

如何规避野指针

1指针初始化。 2小心指针越界。 3指针指向的空间释放即置NULL。 4指针使用之前检查有效性。

在C语言中,让指针变量赋值为NULL表示一个空指针,而C语言中,NULL实质是 ((void*)0) , 在C++中,NULL实质是0。

void是一种特殊的指针类型,可以用来存放任意对象的地址。一个void指针存放着一个地址,这一点和其他指针类似。不同的是,对它到底储存的是什么对象的地址并不了解。

由于void是空类型,只保存了指针的值,而丢失了类型信息,我们不知道他指向的数据是什么类型的,只指定这个数据在内存中的起始地址,如果想要完整的提取指向的数据,就必须对这个指针做出正确的类型转换,然后再解指针。

数组和指针

同类型指针变量可以相互赋值,数组不行,只能一个一个元素的赋值或拷贝。
数组在内存中是连续存放的,开辟一块连续的内存空间。数组是根据数组的下进行访问的。指针它可以指向任意类型的数据。指针的类型说明了它所指向地址空间的内存。

数组的大小: sizeof(数组名)/sizeof(数据类型 )
数组所占存储空间的内存 : sizeof(数组名
取指针的大小在32位平台是4个字节,在64位平台是8个字节。

数组名作为右值的时候,就是第一个元素的地址。

函数与指针

函数的参数和指针

C语言中,实参传递给形参,是按值传递的,也就是说,函数中的形参是实参的拷贝份,形参和实参只是在值上面一样,而不是同一个内存数据对象。这就意味着:这种数据传递是单向的,即从调用者传递给被调函数,而被调函数无法修改传递的参数达到回传的效果。
传递变量的指针可以轻松解决上述问题.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void swap(int *,int *);
int main()
{
    int a=5,b=10;
    printf("a=%d,b=%d\n",a,b);
    swap(&a,&b);
    printf("a=%d,b=%d\n",a,b);
    return 0;
}
void swap(int *pa,int *pb)
{
    int t=*pa;*pa=*pb;*pb=t;
}

在以上的例子中,swap函数的两个形参pa和pb可以接收两个整型变量的地址,并通过间接访问的方式修改了它指向变量的值。在main函数中调用swap时,提供的实参分别为&a,&b,这样就实现了pa=&a,pb=&b的赋值过程,这样在swap函数中就通过pa修改了 a 的值,通过pb修改了 b 的值。

如果需要在被调函数中修改主调函数中变量的值。

定义函数的形参必须为指针类型,以接收主调函数中传来的变量的地址; 调用函数时实参为变量的地址;
在被调函数中使用*间接访问形参指向的内存空间,实现修改主调函数中变量值的功能。

函数的指针

一个函数总是占用一段连续的内存区域,函数名在表达式中有时也会被转换为该函数所在内存区域的首地址。可以把函数的这个首地址赋予一个指针变量,使指针变量指向函数所在的内存区域,然后通过指针变量就可以找到并调用该函数。这种指针就是函数指针。

returnType (*pointerName)(param list);

returnType 为函数返回值类型,pointerNmae 为指针名称,param list 为函数参数列表。参数列表中可以同时给出参数的类型和名称,也可以只给出参数的类型,省略参数的名称.

结构体和指针

如果p是一个结构体指针,则可以使用 p ->【成员】 的方法访问结构体的成员。
const 和 指针

  • 指向常量的指针,值不能改变,指向可改变
  • 常指针值能改变,指向不可改变
  • 指向常量的常指针,都不能改变

深拷贝和浅拷贝

如果2个程序单元(例如2个函数)是通过拷贝 他们所共享的数据的 指针来工作的,这就是浅拷贝,因为真正要访问的数据并没有被拷贝。如果被访问的数据被拷贝了,在每个单元中都有自己的一份,对目标数据的操作相互 不受影响,则叫做深拷贝。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值