当前位置:网站首页>9.指针(上)
9.指针(上)
2022-07-06 09:19:00 【是王久久阿】
目录
1.指针是什么?
指针?什么是指针?从根本上来看,指针(pointer)是一个值为内存地址的变量(或数据对象)。正如char类型变量的值是字符,int类型变量的值是整数,指针变量的值是地址。平时口语中所说的指针通常指的就是指针变量,用来存放地址的变量。
int main()
{
int num = 10;
int* p = #
printf("%p\n", p);
return 0;
}
- 上述代码中,&为取地址符号,将变量num的地址取出来赋给p。
- *表示声明的变量是一个指针,而int表示指针的类型是整型;int*p的意思是,p是一个指针,*p是int类型。
- 利用printf函数打印地址时,%p对应的是地址。
以X86环境下运行上述代码,结果如下:
009BFA40是以16进制表示的,变量num就存放在该地址中。
就像我们生活中的地址一样,C语言中的地址也是唯一的。
2.指针的大小
既然指针作为存储地址的变量,那么计算机必然也会开辟出一块空间用来存放指针。
以上述代码为例,通过sizeof可以计算指针的大小:
int main()
{
int num = 10;
int* p = #
printf("%d\n", sizeof(p));
return 0;
}
在X86环境下,即32位机器中:指针占4个字节。
在X64环境下,即64位机器中:指针占8个字节。
1个字节等于8个比特位,那么32位机器中,指针可以表示2^32个地址;64位的机器中,则可以表示2^64个地址。
指针中最小的单元是字节,这是经过缜密的思考与权衡的。即我们可以查询一个char类型的字符的地址,但是无法查询这个字符中某一位的地址。
3.指针的类型
在创建一个变量时,我们需要为其声明类型,例如:用整型表示年龄,float类型表示身高、体重等;创建指针时也是如此,针对不同类型的变量,声明对应类型的指针来存放其地址。
char *pc = NULL;
int *pi = NULL;
short *ps = NULL;
long *pl = NULL;
float *pf = NULL;
double *pd = NULL;
(*和指针名之间的空格可有可无,不影响使用)
指针解引用(*)
通过间接运算符 *(indirection operator)可以用过地址来更改变量,该操作也称之为“解引用”。
#include<stdio.h>
int main()
{
int num = 10;
printf("改变前:%d\n", num);
int* p = #
*p = 2;
printf("改变后:%d\n", num);
return 0;
}
我们没有直接改变num的值,而是找到num存放的地址,通过解引用操作间接改变了num的值。
指针+-整数
#include<stdio.h>
int main()
{
int num = 10;
int* pi = #
char* pc = (char*)#
printf("%p\n", &num);
printf("%p\n", pi);
printf("%p\n", pi + 1);
printf("%p\n", pc);
printf("%p\n", pc + 1);
return 0;
}
表达式char* pc = (char*)&num:将整型变量num的地址取出来,强制转换成char*类型,然后赋给char*类型的指针变量pc。
通过测试发现:指针类型对应了指针+-时的跨度,即char类型的指针+1往后访问1个字节,int类型的指针+1往后访问4个字节。
4.野指针
概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
野指针成因
指针未初始化
#include <stdio.h>
int main()
{
int* p;
*p = 10;
return 0;
}
局部变量指针未初始化,默认为随机值。
指针越界访问
#include <stdio.h>
int main()
{
int arr[10] = { 0 };
int* p = arr;
int i = 0;
for (i = 0; i < 11; i++)
{
*(p++) = i;
}
return 0;
}
数组arr的下标为0~9,当指针指向的范围超出数组arr的范围时,p就是野指针。
指针指向的空间释放
当指针指向的变量被释放后,指针就是野指针了。
规避野指针
1. 指针初始化
2. 小心指针越界
3. 指针指向空间释放即使置NULL
4. 避免返回局部变量的地址
5. 指针使用之前检查有效性(avoid)
#include <stdio.h>
#include <assert.h>
int main()
{
int* p = NULL;
int a=10;
int* p = &a;
assert(p != NULL);
*p = 10;
if(p!=NULL)
*p = 20;
return 0;
}
5.指针的运算
指针的运算关系
#include<stdio.h>
#define N 5
int main()
{
int ch[N] = { 0 };
int* vp;
for (vp = &ch[0]; vp < &ch[N];)
{
*vp++ = 1;
}
return 0;
}
- 表达式vp = &ch[0]表示将数组中首元素的地址赋给vp。
- vp < &ch[N]表示将vp中存放的地址与数组后一个元素的地址进行对比,只要vp小于它,就说明依然在数组中访问,没有越界。
- *vp++实际上是*(vp++),每次向后访问一个整型。
指针-指针
#include<stdio.h>
int my_strlen(char* s)
{
char* p = s;
while (*p != '\0')
p++;
return p - s;
}
int main()
{
char ch[]="hello";
printf("%d\n", my_strlen(ch));
return 0;
}
标准规定
允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。
6.指针和数组
这部分内容专门开了一章来讲,请看数组、指针和数组的关系。
7.二级指针
指针变量也是变量,是变量就必然会有存放的地址。那么存放指针变量地址的指针,就称为二级指针。
#include<stdio.h>
int main()
{
int a = 10;
int* p1 = &a;
int** p2 = &p1;
**p2 = 20;
return 0;
}
8.指针数组
指针数组是数组,只不过是用来专门存放指针的数组。
#include<stdio.h>
int main()
{
int arr1[] = {1,2,3};
int arr2[] = {4,5,6};
int arr3[] = {7,8,9};
int* p1 = arr1;
int* p2 = arr2;
int* p3 = arr3;
int* p[] = { p1,p2,p3 };
return 0;
}
int* p[] = { p1,p2,p3 }表示数组中存放数据的类型是int*类型,存放的数据分别是p1,p2,p3。
int i = 0, j = 0;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
printf("%d ", *(*(p + i))+j);
}
putchar('\n');
}
建立两个for循环打印指针数组p,可以发现一维的指针数组实现了二维数组的效果。
边栏推荐
猜你喜欢
[dry goods] cycle slip detection of suggestions to improve the fixed rate of RTK ambiguity
TYUT太原理工大学2022数据库之关系代数小题
Novatel board oem617d configuration step record
RTKLIB: demo5 b34f. 1 vs b33
国企秋招经验总结
MySQL 三万字精华总结 + 面试100 问,吊打面试官绰绰有余(收藏系列
Common method signatures and meanings of Iterable, collection and list
阿里云微服务(三)Sentinel开源流控熔断降级组件
Implementation of Excel import and export functions
121 distributed interview questions and answers
随机推荐
初识指针笔记
继承和多态(下)
[rtklib] preliminary practice of using robust adaptive Kalman filter under RTK
阿里云微服务(三)Sentinel开源流控熔断降级组件
arduino+DS18B20温度传感器(蜂鸣器报警)+LCD1602显示(IIC驱动)
西安电子科技大学22学年上学期《信号与系统》试题及答案
Tyut Taiyuan University of technology 2022 introduction to software engineering summary
Record: solution of 404 error of servlet accessing database in dynamic web project
Atomic and nonatomic
Relational algebra of tyut Taiyuan University of technology 2022 database
Shortest Hamilton path (pressure DP)
10 minutes pour maîtriser complètement la rupture du cache, la pénétration du cache, l'avalanche du cache
[while your roommate plays games, let's see a problem]
2年经验总结,告诉你如何做好项目管理
Record: Navicat premium can't connect to MySQL for the first time
TYUT太原理工大学2022数据库之关系代数小题
TYUT太原理工大学2022“mao gai”必背
(超详细二)onenet数据可视化详解,如何用截取数据流绘图
继承和多态(上)
Experience summary of autumn recruitment of state-owned enterprises