栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C - 指针

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C - 指针

C语言–备忘

C 指针
  • C语言--备忘
  • 一、指针定义
  • 二、指针语法
  • 三、指针初始化
  • 四、解引用
  • 五、空指针和野指针
    • 1. 空指针
    • 2. 野指针
    • 3. 合理使用
  • 六、指针运算
  • 七、指针与数组
  • 八、指针类型
    • 1. 常量指针
    • 2. 指针常量
    • 3. 常量指针常量
    • 4. 无数据类型指针:void *
  • 九、指针与函数
  • 十、指针 函数 数组
  • 总结


一、指针定义

指针的本质就是一个变量,永远只能存储一个地址【编号】

  1. 通过指针变量保存的变量的地址可以对这块内存区域任意访问;
  2. 指针指向的内存区域可以保存一个数字,而这个数字有数据类型;
二、指针语法
  1. 指针变量定义的语法格式:
    2.1 定义指针变量后,这个变量 pa 能保存一块内存区域的首地址,这块内存区域保存着int 类型的数据;
    2.2 由于指针也是变量,也需要分配内存,与计算机硬件相关 [固定]。32位系统:一个地址值32位,4字节;64位系统,一个地址为64位,8字节;

结论: 指针变量本身没有数据类型,它指向的内存区域有数据类型,所以int 不是给指针变量用,而是给指针指向的内存区域保存的数字用;

// 形式一:int * 变量名;
    int * pa;//定义一个指针变量
    
// 形式二:int* 变量名;
    int* pa;//定义一种指针变量
    
// 形式三:int *变量名
    int *p;//定义一个指针变量***推荐

//连续定义指针
int *pa,*pb;//两个指针变量
int *pa, pb;//pa为指针,pb为普通int 变量

若指针不初始化,地址值为任意值,危险,此指针为野指针;

三、指针初始化

初始化:

  1. 指针变量初始化通过取地址&来进行;
  2. 函数定义语法:
//分配四字节
int a=250;	

//定义指针变量[4字节内存空间]//"*"为形式上的*
int *pa=&a; 

// "*"为解运算符
printf("请打印%d",*pa);//

代码对应图例:

开辟4字节地址空间,指向整型变量;

四、解引用
  1. 通过解引用运算符:’ * ’ 和指针变量对指向内存区域进行查看和修改。
char a= 100;
char *pa=&a;
//结果pa=&a, &pa 指向pa地址, *pa=a。
printf("%p,%p,%p,%hhd,%cn",pa,&a,&pa,*pa,a);

//分别为1、4,指针永远为4个字节
printf("sizeof(a)=%d,sizeof(pa)=%d",sizeof(a),sizeof(pa));

sizeof(指针变量名)=4B(永远)//和硬件相关,32位

五、空指针和野指针 1. 空指针

定义: 空指针变量:保存空地址,用NULL表示,其实就是编号为0的地址;NULL=0地址;不可随意访问,否则程序崩溃;

short *pb=NULL;

//报错,无法调出空指针指向的内容
printf("PB指向0地址保存的数据为:%#x",*pb); 

*pb=20;
printf("测试信息为.b");
2. 野指针

**定义:**没有初始化的指针变量,保存着随机地址,指向一块无效的内存,这块内存操作系统并没有给你分配;

int *pc;
printf("PB指向0地址保存的数据为:%#x",*pc);

*pc=250; //向随机地址写入数据
printf("测试信息");
return 0; 
3. 合理使用
  1. 如果定义一个指针标量,不清楚指向谁,一定需要初始化NULL,否则野指针。
  2. 如果初始化为空指针,后续使用指针时需要对指针变量安全判断,判断是否为NULL。
  3. 若为NULL,让程序结束或者返回,如果有效,程序才能通过指针进行操作。
int *p=NULL;//赋值为空指针
int a=250;
p=&a;//p指向a

if(NULL==pa){
    printf("pa指向空指针,不能继续访问.n");
    return -1;//exit(0)程序返回和退出
}else{
    printf("pa指向一块有效内存,可以继续访问");
    printf("%dn",*pa);
    *pa=250;
}
六、指针运算
  1. 指针可以和一个整数做加减运算,简称地址运算
    切记:计算结果和指针指向的变量数据类型有关系
指针类型实际地址
(char*)p +1+1
(short*)p +1+2
(int*)p +1+4
(long*)p +1+4
char *pa=0x1000;//pa指向0x1000
pa++;//pa=0x1001,实际地址+1

short *pa=0x1000;//pa指向0x1000
pa++;//pa=0x1002,实际地址+2

long *pa=0x1000;//假设pa指向0x1000//[int/long]型指针+1
pa++;//pa=0x1004,表示实际地址+4
七、指针与数组
  1. 数组名就是数组的首地址;
  2. 遵循数组的首地址,遵循运算公式
  3. &a[2],实际为第3个元素的首地址
  4. a+2也是第3个元素的首地址
int a[4]={1,2,3,4,5};
int *p=a;//定义指针变量保存整个数组的首地址

//写法1---规矩
for(int i=0;i
    printf("%dn",*(p+i));//查看所有元素的值//i为元素+1,如上图
    *(p+i) *=10;
}

//写法2
int length=sizeof(a)/sizeof(a[0]);//元素多少
for(pa=a;pa    printf("%dn",*p);
    *pa++ *=10;//先算*p,后面再做P++
}

//写法3
// 切记:"[]"运算符经过两步运算;  例:a[2]: 1.先计算地址:a+2  2.取值*(a+2) 等价于  p[2]: 1.先算地址:p+2  2.取值*(p+2)
// 申请一个数组,等价于给一个指针~首地址
p=a;//p指向数组,此时p为数组a首地址
for(int i=0;i
    printf("%dn",p[i]);//查看所有元素的值//i为元素,如上图
    p[i] *=10;
}

公式:a[i] = p[i] = *(a+i) =*(p+i)

八、指针类型 1. 常量指针

定义:不能通过指针变量来修改指向的内存区域的值;

//指向的内存变量不可改变,指针地址可变

int a=250;
const int *p=&a; //初始化定义一个常量指针
//或
int const *p=&a;//初始化定义一个常量指针,


//若尝试修改
// *p=200; //gcc编译报错
printf("%dn",*p);//仅仅是查看没问题,打印250
2. 指针常量

定义:指针永远指向一块内存,不可能指向别的地方(保护指针不可乱指向),指针不变;

int a;

// 指针指向的内存空间包含的内容可以改变, 指针的固定地址不可改变
int* const p=&a;

*p=300;//可以,可以修改指向的内存区域

int b=200;
p=&b;//不可以修改地址,gcc报错
3. 常量指针常量

定义:代表p本身不可改变,同事指向p的目标也不能改变;

//const int* const p;//用法

int a=100;
const int* const p=&a;

*p=300;//gcc报错,不可修改指向内容

p=&b;//gcc报错,p地址无法修改
4. 无数据类型指针:void *
  1. 无数据类型指针(void*):是一个指针变量,只是指向的内存区域的数据类型是不可知的
  2. 无法直接对无类型指针进行解引用操作‘ * ’,因为不知道指向的内存区域数据类型,不知道几个字节
  3. 如果想要无类型指针获取内存的数据,不许进行数据转换(推荐强制转换)
int a=250;
void *p=&a;//虽然p指向a,但是通过p无法获取a变量的数据类型
*p=300;    //gcc报错 error
//通过一个指针来获取a的数值


//传统一次性获取4字节方法 
int a=0x12345678;
int *p=&a
printf("%d",*p);
//此种方法虽然能一次性获取4字节数据,
//但若不想获取四字节,获取其中的1、2、4字节的话,这种方式无法实现


//通过有类型的指针变量来获取1、2、4字节指针
int a=0x12345678;
//char *p=&a;//隐式转换,可读性差,gcc还要警告
char *p=(char *)&a;//把&a的类型 int 强制转换为 char*,把0x1000~0x1004分段为0x1000~0x1001~0x1002~0x1003~0x1004
printf("%d",*p++);//结果0x78
printf("%d",*p++);//结果0x56
printf("%d",*p++);//结果0x34
printf("%d",*p++);//结果0x12

short *p=(short *)&a;//强制转换,将&a的int类型转换为short*
printf("%d",*p++);//结果0x5678,先解运算符,++运算直接+2字节
printf("%d",*p++);//结果0x1234
return 0;

//结论:此方法虽然满足要求,但是隐式转换,gcc警告,去掉指针变量++时类型相关问题


// 通过无类型指针来获取1字节,2字节,4字节
int a=0x12345678;
void *p= &a;
char *p1=(char *)p; 
printf("%#xn",*p1++);//0x78 //++直接+1个字节
printf("%#xn",*p1++);//0x56
printf("%#xn",*p1++);//0x34
printf("%#xn",*p1++);//0x12

//或者省略p1 //p为无类型指针,加1就是加1字节,加2就是加2字节....
int a=0x12345678;
void *p= &a;
printf("%#xn",*(char *)(p+0));//0x78 //空指针,+1就是加1个字节,为步长
printf("%#xn",*(char *)(p+1));//0x56
printf("%#xn",*(char *)(p+2));//0x34
printf("%#xn",*(char *)(p+3));//0x12

//若为short 
void *p= &a;
printf("%#xn",*(short *)(p+0));//0x5678
printf("%#xn",*(short *)(p+2));//0x1234//p需要+2字节才到下一个元素//需要人为对内存空间有清晰的认知
九、指针与函数

形式一:指针作为函数的形参,函数通过指针能够访问操作指向的内存;

void A(int *px,int *py,int *pm,int *pn)
{
    ...;
}

形式二:指针作为函数的返回值,函数的返回值是一个指针,千万注意别返回一个野指针;
语法格式:返回值数据类型 *函数名(形参表){函数体语句}

int g_a=250;		//全局非静态
static int g_b=250; //全局静态,生命周期等程序结束,全局使用范围
 
 int *A(void)//指针函数返回的地址值只和变量生命周期有关系,与范围无关
 {
       int a=200; 		//局部非静态
       static int b=100;//局部静态
 
//1. 花括号消失时,200被抹去,内存回收,无指向后变为野指针 
       return &a; 

//2. 静态变量生命周期:一次分配,终生适用;虽然使用范围在A,但是在main函数可以修改
       return &b;

//3. 可以,一次分配终生使用
       return &g_a;
       
//4. 全局存在,可以,一次分配终生使用,
       return &g_b;
 }
 
 int main(void)
 {
     int *p=A();//切记勿返回局部非静态指针,报错
     *p=30000;
      printf("%dn",*p);
      return 0; 
 }
十、指针 函数 数组

函数访问数组的公式:

  1. void A(int a[ ], int length); //其中a是数组的地址
  2. void A(int *p,int length); //两者等价
#include 
extern void print(int *p,int len);
int main(void)
{
    int a[]={1,2,3,4};
    int len=sizeof(a)/sizeof(a[0]);
    print(a,len);
    return 0;
}

void print(int *p,int length)
{
     for(int i=0;i
        p[i] +=2;//两者等价,两步走
    }
    for(int i=0;i
        printf("my a[]_number_is %dn",p[i]);//两者等价,两步走
    }
}
总结
  1. 本章节完整讲述指针的声明,初始化,基本用法,复习备用;
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/983704.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号