C语言有关指针的详解笔记

article/2025/8/29 7:26:07

指针

文章目录

  • 指针
    • 1.指针是什么
    • 2.指针类型
    • 3.野指针
      • 野指针成因
    • 4.指针运算
    • 5.指针和数组
    • 6.二级指针
    • 7.指针数组

1.指针是什么

在计算机科学中,指针是编程语言中的一个对象,利用地址,他的值直接指向存在电脑存储器中另一个地方的值。由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元。因此,将地址形象化的称为"指针"。意思是通过它能找到以它为地址的内存单元。

内存

image-20210407213020311

如何使用内存呢?

生活中,房子对应编号,编号-就为地址,将内存单元划分为一个一个格子,给每个格子编号

1.一个内存单元该是多大的空间?

计算机的单位:

bit 比特位 1个比特位存一个二进制位1/0
Byte—字节
1Byte=8bit
1KB=1024Byte
1MB=1024KB
1GB=1024MB
1TB=1024GB
1PB=1024TB

1Kb=1024bit=128Byte(这里要注意大写B和小写b是有区别的,B代表Byte,b代表bit)

计算机处理的是二进制的指令 0/1

32位机器上产生232个地址,假设一个bit位给一个地址,则管理232个bit位的空间,如下方图,232个bit位空间对应十进制位4294967296个bit空间,最后换算为gb为0.5gb,是比较小的。

我们都知道char为1个字节=8bit,如果用一个bit位代表一个地址,就需要8个地址,有点浪费

如果一个字节给一个地址,则管理2^32个字节的空间=4GB,比较合理,所以,最后把一个内存单元定为一个字节。

image-20210407220213712

2.内存单元的编号怎么产生?

32位电脑

电脑有32根地址线/数据线,电线-通电-(正电)-1/(负电)-0

如果32根地址线都通电,具有32个01组成序列:

00000000000000000000000000000000

00000000000000000000000000000001

00000000000000000000000000000010

……

10000000000000000000000000000000

10000000000000000000000000000001

11111111111111111111111111111111

具有2^32种序列,一个格子为一个内存单元,将每一个这样的序列编号对应一个格子,编号称为内存单元的地址。

int main()
{	char ch ='w';//向内存申请1个字节的空间存放'w'printf("%p\n",&a);//取地址char* pc=&ch;int a=10;//向内存申请4个字节的空间,存放10这个数字int* pa=&a;//地址也是一个值,可以存储到pa变量中 - pa就是指针变量*pa=20;//解引用操作符printf("%d\n",a);//20,通过解引用找到a改为20return 0;
}

指针就是变量,用来存放地址的变量

32位机器上的地址:

32bit的地址-4byte–指针就是地址 - 一个指针变量的大小就是4个字节

64位机器上的地址:

64bit的地址-8byte–指针就是地址 - 一个指针变量的大小就是8个字节

2.指针类型

指针类型的意义

1.指针进行解引用操作时候,能一次性访问几个字节

int mian()
{int a=0x11223344; //16进制数字一位相当于4位2进制数字,11对应为8位二进制数字-对应1个字节,所以第一个字节存储的是11,依次类推,内存如下图int* pa=&a;*pa=0;//访问4个字节char* pc=&a;*pc=0;//访问1个字节  当为int*时,解引用将四个字节内容都改为0;当为char*时只改变了一个字节的内容return 0;
}

int类型指针,将a的存入pa中,内容存储如下

image-20210509123823087

int类型指针*pa找到a,改a的值为0,能访问4个字节

image-20210509124224667

char类型指针*pa找到a,改a的值为0,能访问1个字节

image-20210509123943109

2.指针进行±整数的时候,步幅不一样,指针的类型决定了指针向前走一步或向后走一步有多大

int main()
{int a=0x11223344;int* pa=&a;char* pc=&a;printf("pa:%p\n",pa);printf("pa+1:%p\n",pa+1);printf("pc:%p\n",pc);printf("pc+1:%p\n",pc+1);  return 0;
}

image-20210408165844911

pa与pa+1相差了4个字节,pc与pc+1相差了一个字节。

下面我们看一个例子

int main()
{int arr[10]={1,2,3,4,5,6,7,8,9,10};int* pa=arr;int i=0;for(i=0;i<10;i++){printf("%d\n",*(pa+i)); }return 0;
}

image-20210408171355119

int main()
{int arr[10]={1,2,3,4,5,6,7,8,9,10};char* pa=arr;int i=0;for(i=0;i<10;i++){printf("%d\n",*(pa+i)); }return 0;
}

当把int类型指针改为char类型时,pa+i时,每次加的是一字节,而数组类型为int,pa+1时访问的是数组中1的地址加1字节的地址,而1的地址四个字节的存储分别为01,00,00,00;2的地址四个字节的存储分别为02,00,00,00;3的地址四个字节的存储分别为03,00,00,00;所以以下访问到的只能是以下屏幕输出。

image-20210408171434891

总结:

char*+1 跳过一个字节

short*+!跳过2个字节

int*+1 跳过4个字节

float*+1 跳过4个字节

double*+2 跳过16个字节

3.野指针

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

野指针成因

1.指针未初始化

int main()
{int *p;//p是指针变量,也是局部变量,局部变量指针未初始化,默认为随机值*p=20;//随机一个地址放在p中,给p里面放个20return 0;
}

2.指针越界访问

int main()
{int arr[10]={1,2,3,45,6,7,8,9,10};//越界访问了int *p=arr;int i=0;for(i=0;i<=10;i++){*p=0;p++;//当指针指向的范围超过数组arr的范围时,p就是野指针}return 0;
}

3.指针指向的空间释放

int* test()
{int a=10;//a是局部变量,进函数创建,出函数应该销毁,销毁之前将地址返回//假设a的地址为0x0012ff44return &a;
}
int main()
{int*p=test();//p就是一个野指针//p指向a的地址0x0012ff44,a已经销毁了,非法访问return 0;
}

如何规避野指针

1.指针初始化

int main()
{int a=10;int*p=&a;//初始化int*pa=NULL;//当前指针不知道初始化为什么时,先初始化为NULLreturn 0; 
}

(1)当前指针不知道初始化为什么时

初始化为NULL

(2)明确知道初始化的值

​ 初始化为确定变量的地址

2.小心指针越界

3.指针指向空间释放及时置NULL

4.指针使用之前检查有效性

int main()
{int *p=NULL;if(p!=NULL){*p=20;}return 0;
}

4.指针运算

1.指针±整数

举个例子

int main()
{char arr[]={'a','b','c','d'};//0    1   2   3char* p=arr;int i=0;for(i=0;i<4;i++){printf("%c\n",*(p+i);//p+0指向下标为0的位置//p+1指向下标为1的位...p+3指向下标为3的位置}//另一种方法     /*int i=0;for(i=0;i<4;i++){printf("%c\n",*p++);}*/return 0;
}

2.指针-指针

int main()
{int arr[10]={1,2,3,4,5,6,7,8,9,10};printf("%d\n",&arr[9]-&arr[0]);//9return 0;
}

指针-指针求字符串长度

int my_strlen(char* str)
{char* start=str;while(*str!='\0'){str++;}return str-start;
}
int main()
{char arr[]="abcdef";int len=my_strlen(arr);printf("%d\n",len);//6return 0;
}

指针-指针 得到的是指针和指针之间的元素个数

前提:两个指针指向同一块空间的

求字符串长度

//1.函数求字符串长度
int main()
{char arr[]="abcdef";int len=strlen(arr);printf("%d\n",len);//6return 0;
}
//2.计数求字符串长度
int my_strlen(char* str)
{int count=0;while(str!='\0'){count++;str++;}return count;
}
int main()
{char arr[]="abc";int len=my_strlen(arr);printf("%d\n",len);//3return 0;
}
//3.指针-指针求字符串长度
int my_strlen(char* str)
{char* start=str;while(*str!='\0'){str++;}return str-strart;
}
int main()
{char arr[]="abcdef";int len=my_strlen(arr);printf("%d\n",len);//6return 0;
}
//4.递归求字符串长度
int my_strlen(char* str)
{while (*str != '\0'){return 1 + my_strlen(str + 1);}return 0;
}
int main()
{char arr[] = "abcdef";int len = my_strlen(arr);printf("%d\n", len);//6return 0;
}

3.指针的关系运算(比较大小)

int main()
{int arr[]={1,2,3,4,5,6,7,8,9,10};int i=0;for(i=0;i<10;i++){printf("%d\n",&arr[i]);}
}

image-20210408215517817

由输出可见,随着下标的增长,地址由低到高变化

#define N_VALUES 5
float values[N_VALUES];
float *vp;
for(vp=&values[N_VALUES];vp>&values[0];)
{*--vp=0;
}

改进后:

#define N_VALUES 5
float values[N_VALUES];
float *vp;
for(vp=&values[N_VALUES-1];vp>=&values[0];vp--)
{*vp=0;
}

允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。

5.指针和数组

int main()
{int arr[]={1,2,3,4,5,6,7,8,9,10};int* p=arr;int i=0;for(i=0;i<10;i++){printf("%d",*(p+i));}printf("%p\n",arr);printf("%p\n",&arr[0]);//打印第一个元素的地址//绝大部分情况下:数组名就是数组首元素的地址//数组名不是数组首元素的地址的情况://1.&数组名//2.sizeof(数组名)return 0;
}

绝大部分情况下:数组名就是数组首元素的地址
数组名不是数组首元素的地址的情况:
1.&数组名
2.sizeof(数组名)

数组是指针吗?NO

指针是数组吗?NO

数组是可以通过指针来访问的

int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10};int* p = arr;printf("%d\n", p[2]);//p[2]-->*(p+2)printf("%d\n", 2[arr]);//arr[2]-->*(arr+2)-->*(2+arr)-->2[arr]//arr[2]<==>*(arr+2)<==>*(p+2)<==>*(2+p)<==>*(2+arr)==2[arr]//*(2 + arr) == 2[arr]return 0;
}

6.二级指针

int main()
{int a=10;int*pa =&a;int**ppa=&pa;//ppa就是二级指针,ppa用来存放pa的地址return 0;}
//对于二级指针的运算://1、*ppa通过对ppa中的地址进行解引用,这样找到的是pa,*ppa其实访问的就是pa
//2、**ppa先通过*ppa找到pa,然后对pa进行解引用操作:*pa,找到的是a。

7.指针数组

int main()
{int arr[10];//整形数组--存放整形的数组char ch[10];//字符数组--存放字符的数组int* parr[5];//存放整形指针的数组 数组名为parr  元素类型为int*return 0;
}

指针数组

存放指针的数组

int* arr[10];

char* arr2[5];

整形数组

int arr[10];//存放整形

字符数组

char ch[6];//存放字符

int main()
{int a=10;int b=20;int c=30;int* arr[5]={&a,&b,&c};int i=0;for(i=0;i<3;i++){printf("%d",*(arr[i]));//arr[i]访问到地址,解引用访问到a,b,c}return 0;
}

http://chatgpt.dhexx.cn/article/VkTxoLYG.shtml

相关文章

初阶C语言——指针【详解】

文章目录 1.指针是什么2.指针和指针类型2.1 指针的解引用2.2 指针 -整数 3.野指针3.1 野指针成因3.2 如何规避野指针 4. 指针运算4.1 指针-整数4.2 指针-指针4.3 指针的关系运算 5. 指针和数组6. 二级指针7. 指针数组 1.指针是什么 指针理解的2个要点&#xff1a; 指针是内存中…

C语言——指针初阶详解

&#x1f412;博客名&#xff1a;平凡的小苏 &#x1f4da;学习格言&#xff1a;别人可以拷贝我的模式&#xff0c;但不能拷贝我不断往前的激情 目录 1. 指针是什么 2. 指针和指针类型 2.1指针类型的第一个意义 2.2指针类型的第二个意义 3. 野指针 3.1 野指针成因 3.2 如何…

C语言中指针的详解

文章目录 前提一.指针基础1.1 变量指针1.2 数据指针1.3 指针的本质1.4 指针数组1.5 指针的移动1.5 Scanf函数的解释 二.指针的进阶玩法2.1 二维指针2.2 结构体指针 结语 前提 指针&#xff0c;是C语言中的一个重要概念及其特点&#xff0c;也是掌握C语言比较困难的部分。指针也…

C语言:指针详解

目录 指针就是地址&#xff0c;口语中说的指针通常指的是指针变量 指针的定义以及指针类型 野指针 指针运算 a.指针/-整数 b.指针只能-指针&#xff0c;不能指针 指针与数组 二级指针 指针数组 指针的大小是固定的4/8个字节&#xff08;32位平台/64位平台&#xff09…

C语言,指针详解

1. 指针是什么&#xff1f; 1. 指针是内存中一个最小单元的编号 2. 口头上的“指针”&#xff0c;指的是指针变量 #include<stdio.h>int main() {int a10;int * pa&a;// pa 是一个指针变量,用来存放 a 的地址//int ——> pa 所指向对象的类型//* 代表 pa是个指针…

C语言指针详细解析

C语言指针详细解析 概述指针指针运算符示例 指针类型示例 指针变量的初始化关系运算示例 数组一维数组示例 二维数组示例 字符串指针示例示例 指针函数示例 函数指针示例 指针函数和函数指针定义写法用途 最后 概述 指针也就是内存地址&#xff0c;指针变量是用来存放内存地址…

C语言:详解指针

本人录制技术视频地址&#xff1a;https://edu.csdn.net/lecturer/1899 欢迎观看。 指针应该算得上是c语言的精华&#xff0c;但也是难点。很多教程或者博客都有对其详细的讲解与分析。我这一节的内容&#xff0c;也是讲解指针&#xff0c;但我会尽量使用图解的方式&#xff0…

【C语言】指针(详解)

文章目录 前言1.字符指针2. 指针数组3. 数组指针3.1 数组指针的定义3.2 &数组名VS数组名3.3 数组指针的使用 4. 数组参数、指针参数4.1 一维数组传参4.2 二维数组传参4.3 一级指针传参4.4 二级指针传参 5. 函数指针6. 函数指针数组7. 指向函数指针数组的指针8. 回调函数8.1…

【c语言】 指针详解 【图文+代码】

指针 前言一、指针是什么&#xff1f;1.1 认识指针1.2 变量1.3 变量放在哪&#xff1f;1.4 指针的本质1.5 解引用 二、指针类型2.1指针有类型吗&#xff1f;2.2指针类型的意义是什么&#xff1f; 三. 野指针3.1什么是野指针3.2野指针成因3.2.1指针未初始化3.2.2 指针越界访问3.…

【初阶】C语言指针详解——指针必备的7大知识点

文章目录 前言一、指针是什么&#x1f351;1、浅谈指针&#x1f351;2、内存&#x1f351;3、指针变量 二、指针和指针类型&#x1f351;1、指针类型&#x1f351;2、指针-整数&#x1f351;3、指针的解引用 三、野指针&#x1f351;1、野指针成因&#x1f333;(1) 指针未初始化…

详解C语言指针

文章目录 1.字符指针2.指针数组3.数组指针3.1 数组指针的定义3.2 &数组名和数组名的区别3.3 数组指针的使用 4.数组参数&#xff0c;指针参数4.1 一维数组传参4.2 二维数组传参4.3 一级指针传参4.4 二级指针传参 5.函数指针6.函数指针数组7.指向函数指针数组的指针8.回调函…

C语言——指针(入门详解)

文章目录 1.什么是指针&#xff1f;1.1.理解指针的两个要点&#xff1a;1.2.指针变量&#xff1a;1.3.内存是如何编址&#xff1f; 2.指针和指针类型2.1指针的创建与初始化2.2.指针类型 3.野指针3.1.什么视野指针&#xff1f;3.2.野指针成因3.3.规避野指针 4.指针运算4.1.指针-…

c语言指针用法详解,通俗易懂超详细!

文章转自&#xff1a;无际单片机 大家好&#xff0c;我是无际。 今天给大家来讲解一下指针。 我会由浅到深&#xff0c;最后结合实际应用讲解&#xff0c;让大家学会指针的同时&#xff0c;知道大佬们都用指针来干嘛&#xff01; 长文预警&#xff01;全文大约5200多字&#xf…

C语言指针详解(超级详细)

C语言指针精解 前言 这不是我第一次写关于C指针的文章了&#xff0c;只是因为指针对于C来说太重要&#xff0c;而且随着自己编程经历越多&#xff0c;对指针的理解越多&#xff0c;因此有了本文。然而&#xff0c;想要全面理解指针&#xff0c;除了要对C语言有熟练的掌握外&…

C语言中的指针详解

1. 什么是指针 C语言中指针是一种数据类型,指针是存放数据的内存单元地址。 计算机系统的内存拥有大量的存储单元,每个存储单元的大小为1字节,为了便于管理,必须为每个存储单元编号,该编号就是存储单元的“地址”,每个存储单元拥有一个唯一的地址。 指针变量除了可以存…

C语言——指针详解(必收藏)

目录 1.什么是指针&#xff1f; 1.1概念 1.2指针的大小 ​ 1.3指针类型的作用 2.野指针 2.1野指针产生的原因 2.2 如何规避野指针 3.指针运算 3.1指针-整数 3.2指针-指针 3.3 指针的关系运算 4. 二级指针 5. 数组名 *6.指针数组和数组指针 6.1指针数组 *6.…

C语言指针详解

一、什么是指针 C语言里&#xff0c;变量存放在内存中&#xff0c;而内存其实就是一组有序字节组成的数组&#xff0c;每个字节有唯一的内存地址。CPU 通过内存寻址对存储在内存中的某个指定数据对象的地址进行定位。这里&#xff0c;数据对象是指存储在内存中的一个指定数据类…

C语言之指针详解

文章目录 1 指针1.1 简介1.2 什么是指针1.2.1 定义1.2.2 指针表示1.2.3 为什么*p&a不正确 1.3 使用指针1.3.1 简单使用1.3.2 NULL 指针1.3.3 指针算术运算1.3.3.1 定义1.3.3.2 遍历数组&#xff1a;递增一个指针1.3.3.3 遍历数组&#xff1a;递减一个指针1.3.3.4 指针的比较…

c语言—指针详解

文章目录 一、指针是什么二、指针和指针变量1.左值与右值2.两者的区别 三、指针和指针类型1.定义指针2.大小端3.指针的解引用 四、野指针野指针成因如何规避野指针 五、指针运算1.指针- 整数2.指针-指针3.指针的关系运算 六、指针和数组七、二级指针八、指针数组和数组指针1.指…

机器学习主动学习和半监督学习

一、主动学习&#xff08;active learning&#xff09; 学习器能够主动选择包含信息量大的未标注的样例并将其交由专家进行标注&#xff0c;然后置入训练集进行训练&#xff0c;从而在训练集较小的情况下获得较高的分类正确率&#xff0c;这样可以有效的降低构建高性能分类器的…