c语言——指针

概念

电脑内存被划分为⼀个个的内存单元,每个内存单元的⼤⼩取1个字节

计算机中的常见单位:

bit——比特位                                                          1byte=8bit

byte——字节                                                           1KB=1024byte

KB                                                                           1MB=1024KB

MB                                                                           1GB=1024MB

GB                                                                           1TB=1024GB

TB                                                                            1PB=1024TB

PB

 每个内存单元能存放8个⽐特位的内容,且每个内存单元也都有⼀个编号,有了这个内存单元的编 号,CPU就可以快速找到⼀个内存空间。我们把这样的内存单元编号叫做地址,也叫做指针

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

CPU访问内存中的某个字节空间,必须知道这个 字节空间在内存的什么位置,⽽因为内存中字节 很多,所以需要给内存进⾏编址。CPU与内存之间存在一组线叫地址总线,我们可以简单理解,32位机器有32根地址总线, 每根线只有两态,表⽰0,1【电脉冲有⽆】,那么 ⼀根线,就能表⽰2种含义,2根线就能表⽰4种含 义,依次类推。32根地址线,就能表⽰2^32种含 义,每⼀种含义都代表⼀个地址。所以32位情况下,指针占32个比特位,也就是4个字节。同理,在64位情况下,指针占8个字节。

指针变量和地址

在C语⾔中创建变量其实就是向内存申请空间,由图可知,现在a变量为整形,地址占4字节的内容,为0x00D3FAB4、0x00D3FAB5、0x00D3FAB6、0x00D3FAB7

c语言中存在一个操作符可以得到变量的地址:&

 &a取出的是a所占4个字节中地址较⼩的字节的地 址也就是最下面的那个(在内存中,地址是由下到上依次变大)虽然整型变量占⽤4个字节,我们只要知道了第⼀个字节地址,顺藤摸⽠访问到4个字节的数据也是可 ⾏的。(字符型变量地址占一个字节,但它所对应的指针变量仍然是4字节大小)

 解引用

int a=10;

int *pa=&a;

 这里pa就是a的指针变量,int *pa中int指a的类型,*表示pa定义为指针变量。

那么pa就是a的指针的意思。

“ * ”是解引用符,*pa就是a的内容。我们可以通过*pa对a的内容进行修改。

指针解引用访问的大小取决于指针类型,int*指针能访问4字节,char*指针只能访问1字节,

我们可以在定义指针式使用强制转换:

int n = 0x11223344;

char *pc = (char *)&n;

这里n是个整型变量,对应指针解引用访问4字节,可以用(char*)强制把地址转换成字符指针形式,解引用访问1字节。

指针+-整数

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);

运行结果:

 说明指针+-整数能控制指针向前、后走一步,而指针类型能决定一步的大小,char*一步1字节,int*一步4字节。

const修饰变量

变量是可以修改的,如果把变量的地址交给⼀个指针变量,通过指针变量的也可以修改这个变量。 但是如果我们希望⼀个变量加上⼀些限制,不能被修改,那么就用到const。

 const int a=10;这里修饰了变量a,所以a就不能被修改了,但还是可以通过指针修改a的内容。

const int *pa=&a;这里修饰了*pa,a的内容无法通过指针更改了,但指针变量pa还是可以修改的。

 int * const pa=&a;这里修饰了指针变量pa,所以pa无法被修改,但可以修改pa所指向的变量a。

指针的关系运算

指针+- 整数(指针向前/后移动整数位)

指针-指针(两个指针之间的距离)

野指针

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

 成因可能为以下几种:

int *p;//局部变量指针未初始化,默认为随机值

—————————————————————— 

int arr[10] = {0};

int *p = &arr[0];

int i=0;

for(i=0;i<11;i++)

{

    *(p++) = i;//当指针指向的范围超出数组arr的范围时,p就是野指针    

}

——————————————————————

int* test()

{

        int n = 100;

        return &n;

}

int main()

{

        int*p = test();

        printf("%d\n", *p);//指针指向的空间释放

        return 0;

}

规避野指针的方法:1.指针初始化   2.⼩⼼指针越界   3.指针变量不再使⽤时,及时置NULL,指针使⽤之前检查有效性   4.避免返回局部变量的地址

(当指针变量指向⼀块区域的时候,我们可以通过指针访问该区域,后期不再使⽤这个指针访问空间的 时候,我们可以把该指针置为NULL。因为约定俗成的⼀个规则就是:只要是NULL指针就不去访问, 同时使⽤指针之前可以判断指针是否为NULL)

assert断⾔

assert.h 头⽂件定义了宏 assert() ,⽤于在运⾏时确保程序符合指定条件,如果不符合,就报 错终⽌运⾏。这个宏常常被称为“断⾔”。

我们可以通过assert(p != NULL);来限制程序的执行,验证变量 p 是否等于 NULL 。如果确实不等于 NULL ,程序 继续运⾏,否则就会终⽌运⾏,并且给出报错信息提⽰。

指针的运用场景

传址调⽤——由于实参传递给形参的时候,形参会单独创建⼀份临时空间来接收实参,对形参的修改不影响实 参,当我们要通过函数改变实参时,就要运用指针。

——————————————————

使⽤指针访问数组:

int arr[10] = {1,2,3,4,5,6,7,8,9,10};

数组名arr本就是数组第一个元素的地址,跟&arr[0]同义。

所以int* p=arr;也可以写成int* p=&arr[0];

arr基本在任何时候都能表示数组首元素的地址,只有两个例外:

sizeof(数组名),sizeof中单独放数组名,这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩, 单位是字节。

&数组名,这⾥的数组名表⽰整个数组,取出的是整个数组的地址(整个数组的地址和数组⾸元素 的地址是有区别的)此时对应的指针移动单位为一个数组长度。

数组名arr是数组⾸元素的地址,可以赋值 给p,其实数组名arr和p在这⾥是等价的。那我们可以使⽤arr[i]可以访问数组的元素,p[i]、*(p+i)也可 以访问数组。甚至i[p]、i[arr].

(一维数组传参的本质传递的是数组⾸元素的地址,所以在函数中能够修改真实的数组数据,而既然传递的是指针,那么在函数中就无法使用sizeof求传入数组的大小)

(同理,二级数组的数组名就是第一排数组的地址)

数组指针变量

定义:存放的是数组的地址,能够指向数组的指针变量。

写法:int (*p1)[10];

int * p2 [10];的区别:p1是指向能存放10个整形变量的数组的指针

                                     p2是能存放10个整形指针变量的数组

像p1这样的就是数组指针

int arr[10] = {0};

int(*p1)[10] = &arr;//初始化p1

函数指针变量

定义:存放函数地址的变量

(函数的地址就是函数名)

 这种变量写起来固然很繁琐,所以我们可以通过typedef关键字进行类型的重命名,比如:

将unsigned int重命名为unit

又比如:将void (*)(int)重命名为pfun_t

函数指针数组

把函数的地址存到⼀个数组中,那这个数组就叫函数指针数组

写法int (*p4[3])();

p4 先和 [] 结合,说明 p4是数组,是 int (*)() 类型的函数指针。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值