| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> C++知识库 -> C语言——初阶指针 -> 正文阅读 |
|
[C++知识库]C语言——初阶指针 |
目录:
1. 指针是什么?
2. 指针和指针类型?
3. 野指针?
4. 指针运算?
5. 指针和数组?
6. 二级指针?
7. 指针数组
1.指针是什么:
1. 指针是内存中一个最小单元的
编号,也就是
地址 。
2. 平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量。
总结:指针就是地址,口语中说的指针通常指的是指针变量。
内存被划分为一个个小的内存单元。
一个基本的内存单元的大小时一个字节。
内存单元的编号-->地址。
内存单元的编号是如何产生的呢?
机器分为30位或64位:? ? ? ? ? ? ? ? ? ? ? (
电信号转换为数字信号)
32位 - 32跟地址线 - 物理电线 - 通电 - 高电频/低电频 - 1/0
64位......
电信号产生的数字信号二进制序列作为内存单元的编号-->内存单元的地址:
00000000000000000000000000000000
00000000000000000000000000000001
......
11111111111111111111111111111111
共有2^32个地址,每个地址标一个字节,可以给4G的空闲内存编址(32位下)(2^32Byte == 2^32/1024KB == 2^32/1024/1024MB==2^32/1024/1024/1024GB == 4GB)。
所以:
内存单元 -- 编号 -- 地址 -- 指针
指针变量:是用来存放地址的变量(
存放在指针中的值都被当成地址处理)。
int a = 10;
int *pa = &a;
//pa是指针变量,pa的类型是int*
//pa中存放的是a的地址
前面说到一个地址占32bit=4byte,所以一个指针变量pa占4个字节。
因为一个地址占4个字节,要存起来这个地址,需要一个4字节的内存空间。(32位下,64位需要8个字节)
总结:
指针是用来存放地址的,地址是唯一标示一块地址空间的。?
指针的大小在32位平台是4个字节,在64位平台是8个字节。
2.指针和指针类型
指针类型的大小都是一样的,都占4个字节(double*、int*、short*......)
那么指针类型的意义是什么呢?
int a = 0x11223344;
int *pa=&a;
*pa = 0;
//得出的结果是让a中的4个字节存的数都变为0;
//11 22 33 44-->00 00 00 00
但是,当为:
int a = 0x11223344;
char *pa = &a;
*pa = 0;
//得出的是让a中的4个字节中的1个字节内存的数变为0;
//11 22 33 44-->11 22 33 00
总结:
1.指针类型的意义:
指针的解引用:
指针类型决定了在解引用的时候一次能访问几个字节(指针的权限)
int* --> 4
char* --> 1
couble* --> 8
2.指针类型决定了指针向前走一步或向后走一步,走多大距离(单位字节)
int a = 10;
int *pa = &a;
char *pc = &a;
printf("%p\n",pa);
printf("%p\n",pa+1);//打印的地址+1跳过4个字节(int型)
printf("%p\n",pc);
printf("%p\n",pc+1);//打印的地址+1跳过1个字节(char型)
强制转换:
int arr[10]={0};
char* p=(char*)arr;
return 0;
强制类型转换后大小并没有变,还是4个字节,只是一次访问由4字节改为1字节。
3.野指针
野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
野指针的成因:
1.指针未初始化
int *p;//局部变量未初始化,是随机值
*p = 20;
补充:全局变量未初始化默认为0,局部变量未初始化为随机值。
2.指针越界访问
int arr[10] = { 0 };
int *p = arr;
int i = 0;
for(i = 0;i <= 10;i ++)
{
? ? ?*p = i;
? ? ? p ++;
}
当i=10的时候,*p=10,但是数组中一共只有0~9这10位,i=10时多出一位,这一位就造成数组越界,会出现野指针。
3. 指针指向的空间释放
int* test()
{
? ?int a=100;
? ?return *a;
}
int main()
{
? ?int *p=test();
? ?printf("%d",*p);
? ?return 0;
}
函数运行时开辟内存存放100,有一个对应的地址,返回的时候返回的就是当时存放100的那个内存地址,p指向的就是当时存放a的地址,但是a有生命周期,函数调用完出去的时候,a就销毁了(不是说这块孔家不在了,而是
这一块内存空间的使用权限
不再属于
test函数了),但是p里面还是存了这一块空间的地址,p就成为了一个野指针。(如果这个空间里存的东西没改过,去访问的时候里面还是a的值,但是如果被用过了,就不是a的值了。)
4.如何规避野指针
1. 指针初始化?
(当p不知道指向谁的时候就给它附一个空指针 int *p = NULL ;)
2. 小心指针越界?
3. 指针指向空间释放即使置NULL?
4. 避免返回局部变量的地址?
5.
指针使用之前检查有效
if(pa != NUULL)
{
}
//检查指针pa的有效性,当pa不等于空指针的时候再去使用它
4.指针运算
4.1指针+-运算
指针+-整数i跳过i个相应的类型个数。
for(i=0;i<sz;i++)
{
? ? printf("%d",*(p+i));
}
//sz为数组中元素的个数
//用指针依次打印数组中的元素个数
int *p = arr + sz - 1;//p指向arr的最后一个元素
for(i=0;i<sz;i++)
{
????printf("%d",*p--);
}
//反向打印数组中的元素
4.2指针-指针
int main()
{
? ? int a[10]={0};
? ? printf("%d\n",&a[9]-&a[0]);
? ? printf("%d\n",&a[9]-&a[0]);
? ? return 0;
}
输出结果为
? ? ? ? ? ? ? ? ? 9
? ? ? ? ? ? ? ? ?-9
解析:
地址由低到高排列,当两个地址相减的绝对值,得到的是两个地址之间元素的个数(不是字节个数)
(
大地址-小地址--正数;小地址-大地址--负数)
注:指针-指针的前提是:两个指针指向同一块空间。
补充:
实现my_strlen的
三种方法:
1.计数器
2.递归
3.指针-指针
这次展开讲指针-指针的方法
int my_strlen(char *s)
{
? ? char *strart = s;//strart指向首元素
? ? while(*s !='\0')
? ? {
? ? ?s++;
? ? }
? ? return s-start;//指针的减法,课算出两地址之间元素个数
}
4.3指针的关系运算
#define N_VALUES 5?
float values[N_VALUES];?
float *vp;
for(vp = &values[N_VALUES]; vp > &values[0];)?
{????
? ? *--vp = 0;?
}
//把数组中的元素都赋值为0;
values:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?vp?(通过for循环中--向左赋值)
上面的代码可以进行简化:
for(vp = &values[N_VALUES-1]; vp >= &values[0];vp--)?
{????
? ? *vp = 0;?
}
注意:
标准规定:
允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。
5.指针和数组
指针——地址(4字节/8字节)
数组——一组相同类型的数据(多大自己创建)
数组和指针是两种概念
我们可以通过指针访问数组。
6.二级指针
int main()
{
? ? int a = 10;
? ? int *pa = &a;
? ? //pa中存放a的地址,占用4字节,而pa本身也有自己的地址
? ? int **ppa = &pa;
? ? //ppa就是二级指针,指向pa,ppa也有自己的地址
? ? int ***pppa = &ppa;
? ? //pppa是三级指针
对二级指针中*的
理解:
int *pa=&a;? 中 * 表示pa是一个指针,由于a的类型是int,pa指向的对象是int型,所以用int。
int **ppa=&pa;? 中? **中的第二个*表示ppa是指针变量,第一个*和int组成int*,由于pa的类型是int*,ppa指向pa,所以这里是int*。
(指针指向谁,定义的时候就写什么类型,指向int就写int,指向int*就写int*)
*ppa找到的是pa,所以**ppa找到的就是a,可以通过**ppa修改a的值
**ppa=20;//把a中的值改为20
(*ppa=pa,**ppa=*pa=a)
总结:
二级指针是用来存放一级指针变量的地址的。
7.指针数组
?指针数组是数组——存放指针的数组
int a = 10;
int b = 20;
int c = 30;
int *arr[5] = { &a , &b , &c };//存放整型指针的数组
arr中存放的都是int*型。
上面arr中不完全初始化,未定义的初始化为0,是空指针。
*(arr[0]) = a;
|
|
C++知识库 最新文章 |
【C++】友元、嵌套类、异常、RTTI、类型转换 |
通讯录的思路与实现(C语言) |
C++PrimerPlus 第七章 函数-C++的编程模块( |
Problem C: 算法9-9~9-12:平衡二叉树的基本 |
MSVC C++ UTF-8编程 |
C++进阶 多态原理 |
简单string类c++实现 |
我的年度总结 |
【C语言】以深厚地基筑伟岸高楼-基础篇(六 |
c语言常见错误合集 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 7:46:36- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |