15.C与指针--超全总结

简介: 15.C与指针--超全总结

一. 指针与地址

1. 指针简介

定义:指针是用来访问内存的,相当于房间的房间号便于查询,提高效率

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

大小:4/8个字节,只要是指针变量就是,和类型无关

x86(32位机器,32根总线||二进制,32个比特位) 所以需要4个字节

x64  8个字节

常见单位

int/float==4个字节

short==2个字节

char==1个字节

一个字节==八个比特

引言:编址的理解

可以理解为CpU传地址给内存获得信息,再通过数据总线传回CPU

2. 指针变量

取地址&

及Pa向内存申请一块空间来储存a的地址

int类型是四个字节,&a会输出四个中较小的字节,可通过%p来打印

定义指针变量与解引用 *

因为都用到了*这个符号,所以对比讲解一下

定义:int *    p=&a,

其中用到的*为定义类型,代表P为指针变量的标志,

int是所取的a的数据类型为int类型

前面提到了指针大小和类型无关,那么为什么要定义指针类型呢?

1.决定了解引用可以访问几个字节,例如int可以访问4个,而char解引用后只能访问1个

2.决定了指针变量+或-1 一次所走的距离

解引用(后才可赋值):* p=0,

就是对所取出的a的地址进行了解引用,就可以对a重新赋值了

触发连招:* & a=0  取出a的地址再解引用

void* 指针

无具体类型的指针

作用:

优点:可以接收不同类型的地址,使用在函数参数的一部分

缺点:无法直接进行指针运算

const 修饰指针

const   *p   内容不可改 //可以将这个*p理解为解引用之后的内容了,然后const放在其之前了

*  const p  对象//p指向的地址  不可改

指针运算

指针+-整数  如:p+n——跳过n*sizeof(type)//跳过n个指针类型

指针-指针   可以模拟实现strlen

让p获得s首地址后,自加直到遇见\0,用p-首地址得到长度

指针关系运算  实现字符串输出 如p<arr+sz的话p自加

3. 野指针

成因:

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

(到arr[11]了,越界

p得不到100,test可以,离开函数无法访问,还回去了

避免NULL

1.指针初始化  int* p=NULL  (值是0,0也是地址)

2.注意不能超出访问申请的空间

  野指针像野狗一样,NULL像树可以把它拴起来,运用了if

3.不要返回局部变量

assert断言

运用:assert(p!=NULL)

好处:1.为假返回零,会报错文件名和行号

        2.可取消 在#include<assert.h>前面定义一个宏 #define NDEBUG

          (在release版本中会自动优化掉)

4. 传值和传址调用

strlen的模拟实现

用const使内容不可改

无符号整型可变为size_t   %zd

传值调用:

调试观察如下代码:

这是一种传值调用,a,b无法实现交换效果

因为可以发现a,b和x,y地址不一样,x,y又是两个相对独立的空间了

实参a,b只能将数值传给形参

所以实参传递给形参的时候,形参会单独创建一份临时空间来接收实参,对形参的修改不影响实参

这就需要应用传址调用了,可以让函数和主函数之间建立真正联系

在函数中定义参数为指针类型,取a,b地址传入,交换解引用的值

二. 数组与地址

1. 数组名的理解

数组名是首元素的地址&a[0],除了

1.sizeof(数组名) 代表整个数组

2.&数组名  整个数组的地址

 &arr+1跳过的是整个数组

2.数组与指针辨析

1.数组就是数组,是一块连续的空间(大小和1.个数2.类型都有关)

2.指针变量就是一个变量(4/8个字节)

3.数组名是地址,首元素地址

4.可用指针来访问数组

int* p=arr        *(p+i)==*(&arr[0]+i)

扬科维奇   i[arr]==arr[i]  

[ ]==*的含义

一维数组传参的本质:传的为首元素的地址

一维数组传参,形参的部分可以写成数组的形式,也可以写成指针的形式(首元素地址)。

3.冒泡排序

核心:一趟搞定一个,两两相邻比较

设立flag判断函数,实现优化

4.二级指针

指针变量也是变量,是变量就有地址,存放指针的地址--二级指针

int* * ppa=&pa

指向int*类, 最后面的* 指针变量的标志

解引用方框内所存放的地址,就能得到该地址内的内容

5. 指针  [数组]

好-孩子,也是个孩子,指针-数组,是个数组,看后缀

数组的每个元素都是指针类型

指针数组模拟二维数组

parr[i][j]==*(*(arr+i)+j)

三. 深入指针

1.字符指针变量

%s字符串不用*,给个首地址及可自动往后

和数组引用的区别:直接用指针的常量字符串不可修改

本质:把字符串首字符放到pstr中了,但会自动往后读字符串

常量字符串是不可被修改的,相同的%s没必要存2份

2.数组(指针)变量

如果要存放整个数组的地址,就得存放在数组指针变量中

int (*p)[10] = &arr           指针要括起来

p==&arr完全一致

二维数组传参的本质

本质:是传递了地址,传递的是第一行这个一维数组的地址

二维数组传参,形参的部分可以写成数组,也可以指针,但都要带列

加1来使数组指针,跳过整个指向的数组,来到下一行

3. 函数指针变量

函数名带不带&,都是函数的地址

数组和函数指针都要(指针)

4. 函数指针数组
转移表

四. 深入函数指针

1. 回调函数
定义:把函数A的指针作为参数传递给另一函数B—实现B(A),A是被调用函数,就是回调函数
模拟实现计算器

2. qsort函数
排序整型数据

void qsort(void* base,//指针,指向待排序数组首元素

                 size_t num//数组元素个数

                  size_t size//数组元素大小

                  int (* cmp)( const void*,const void *)//函数指针--进行两两相邻的比较函数

排列结构数据

注释:e1是一个指针,而不是一个结构体本身。因此,如果要访问结构体中的成员,需要使用箭头运算符'->',以此来得到该元素

3. 用冒泡模拟实现qsort
通用的实现:

通过 void* 来接收各种数据类型,局部变量中通过 强制类型转化 实现比较等操作

代码如下:

补充:

1. 如何输入未知长度字符串

char str(10000);

gets(str);

len=strl指针en  #stdlib

//如果看完感觉还不错,感谢点赞支持一下啦,欢迎留言 互相关注交流~


相关文章
C 中的 NULL 指针
C 中的 NULL 指针。
38 0
|
7月前
C中的NULL指针
C中的NULL指针。
26 1
|
7月前
指针指向数组
指针指向数组
39 0
|
7月前
利用指针方法
利用指针方法。
30 1
|
7月前
指向结构体类型数据的指针
指向结构体类型数据的指针。
45 3
|
7月前
|
JavaScript
this指向
this指向
44 0
|
存储 C语言
指针--基础篇
指针--基础篇
61 0
|
编译器 C++
C++使用new来初始化指向类的指针
C++使用new来初始化类的指针 1.ClassName * p = new ClassName; 调用默认构造函数。 如果类里没有写默认构造函数,会使用编译器帮我们生成的,但不会初始化成员变量,如 class NoConstructor    //没写构造函数的类 { public:     ~NoConstructor() {}     void printVal()      {          cout << m_val << endl;      } private:     int m_val; }; NoConstructor* p1 = new NoConstruct
|
C语言
指向数组的指针
以下是 int a[5],以及其各个元素的地址 a[0] 0019FF1C a[1] 0019FF20 a[2] 0019FF24 a[5] 0019FF28 a[4] 0019FF2C
105 0
指向数组的指针