C语言指针详解(嵌入式开发)

指针的优点

  1. 使程序更加简洁、紧凑、高效
  2. 表示更加复杂的数据
  3. 动态内存分配
  4. 得到多于1个的返回值

1.概念

地址:内存中每个字节单位都有一个编号

指针:指针就是地址

指针变量:存放地址的变量

2.定义格式

存储类型 数据类型 *变量名;

int a=3;

int *p=&a;

char ch = ‘a’;

char *p = &ch;

3.指针操作符

&:取变量的地址

*:取地址里面的内容

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5dZMlvwm-1675324148118)(assets/image-20230131100811-hibc4g2.png)]

&和*是互逆的

4.初始化

指针变量使用前不仅要定义还要初始化,未经初始化的指针变量不能随便使用,可能会产生野指针。

  1. 将普通变量的地址赋值给指针变量
    //a)已有空间
    int a = 10;
    int *p =&a;
    printf("%d %d\n",a,*p);//10 10
    printf("%p %p\n",&a,p);//地址
     *p = 20;
    printf("%d %d\n",a,*p);//20 20
    //b)备用指针
    int *p = NULL;
    p = &a;
    
  2. 将数组首地址赋值给指针变量
    char s[10] = "hello";
    char *p = s;
    printf("%s %s %c\n", s, p,*p);//hello hello h
    
  3. 指针变量里面保存的地址赋值给另一个指针变量
    int a =10;
    int * p = &a;
    int *q = NULL;
    q=p;
    

5.指针运算

char buf[32] = "hello";
char *p = buf;
  1. 算术运算

    p++:指针向高地址方向移动一个数据单位,指针的指向发生变化

    p–:指针向低地址方向移动一个数据单位,指针的指向发生变化

    p+n: 访问了高地址方向第n个数据的地址,指针的指向没有变化

    p-n: 访问了低地址方向第n个数据的地址,指针的指向没有变化

    两个地址之间的差=两个地址之间相隔数据元素的个数,p-q=相隔元素的个数

    //1
    char *p = s;
    printf("%c %p %p\n",*p,p,s);//h 0xbfd8b392 0xbfd8b392
    p++;
    printf("%c %p %p\n", *p,p,s);//e 0xbfd8b393 0xbfd8b392
    int a[32]={1,2,3,4,5};
    int *q=a;
    printf("%d %p %p\n",*q,q,a);//1 0xbfd8b310 0xbfd8b310
    q++;
    printf("%d %p %p\n",*q,q,a);//2 0xbfd8b314 0xbfd8b310
    //2
    char s[10] = "hello";
    char *p = s;
    printf("%c %p %p\n",*p,p,s);//h 0xbffeebf2 0xbffeebf2
    printf("%c %p %p\n", *(p+1),p+1,s);//e 0xbffeebf3 0xbffeebf2
    int a[32]={1,2,3,4,5};
    int *q=a;
    printf("%d %p %p\n",*q,q,a);//1 0xbffeeb70 0xbffeeb70
    printf("%d %p %p\n",*(q+1),q+1,a);//2 0xbffeeb74 0xbffeeb70
    //3
    int m = 100;
    double n = 200;
    int *p1 = NULL,*p2 = NULL;
    double *q1=NULL,*q2=NULL;
    p1 = &m;
    p2 = p1 + 2;
    q1 = &n;
    q2 = q1 + 2;
    printf("p1=%p p2=%p\n",p1,p2);//p1=0xbfa238bc p2=0xbfa238c4
    printf("p2-p1=%d\n",p2-p1);//p2-p1=2
    printf("q1=%p q2=%p\n",q1,q2);//q1=0xbfa238d0 q2=0xbfa238e0
    printf("q2-q1=%d\n",p2-p1);//q2-q1=2
    
  2. 关系运算

    < > == !=
    指针之间的关系运算比较的是指针指向地址的高低
    注意:指向不同数据类型的指针关系运算没有意义,指向不同区域的指针关系运算没有意义,一般在同一个数组中进行比较

6.指针的大小

int a=5;
int *p = &a;//sizeof(p)=4
char ch = 'a';
char *q = &ch;//sizeof(q)=4
int a[5]={1,2,3,4,5};
int *k = a;//sizeof(k)=4
//和地址有关

总结:

  1. 32位操作系统:指针大小4字节;64位操作系统:指针大小8字节
  2. 内存地址是固定的,但是变量的地址是不固定的,由栈区随机分配
  3. 指针类型根据指向空间的数据类型来确定的

7.段错误

Segmentation fault (core dumped)

  1. 野指针:

    1. 产生原因:

      1. 没有初始化
      2. 指针被free后没有置位NULL
    2. 解决方式:int *p =NULL;//NULL系统宏,空指针

  2. 内存泄漏,对非法空间赋值

8.指针修饰

1.const常量化
  1.  const int a = 10;
     a=20;//报错,因为a被const修饰所以不能被赋值但是可以通过指针间接更改a的值
     int *p = &a;
     printf("%d\n",a);
    

在这里插入图片描述

  1.  const int *p;//指针指向的内容不能修改,但是指针的指向可以修改
     int a=10;
     const int * p = &a;
    
     //1)
     *p  = 20;//无法写入
     printf("%d\n",*p);
    
     //2)
     int b=30;
     p=&b;//改变指向
     printf("%d\n",*p);
    
  2.  int *const p;//修饰p,指针指向
     不能修改,指针指向的内容可以修改
     int a=10;
     int b=20;
     int * const p = &a;
     1)*p = 20;//正确
     2)p = &b;//报错,指针指向不能修改
    
2.void
void a;//不可以,不能修饰变量
void * p //任意类型的指针int *)p

9.大小端

大端:地地址存放高字节数据,高地址存放低字节数据

小端:地地址存放低字节数据,高地址存放高字节数据

举例:0x12345678 起始地址0x4000

0x40000x40010x40020x4003
大端0x12345678
小端0x78563412

10.二级指针

一级指针:存放变量的地址

二级指针:存放一级指针的地址
在这里插入图片描述

int a= 10;
int *p = &a;
int **q = &p;
//访问a的值:a  *p  **q
//访问a的地址:&a  p  *q
//访问p的地址:&p  q

11.指针和数组

直接访问:按变量的地址存取变量的值(通过数组名访问)

间接访问:通过存取变量地址的变量来访问变量的值(通过指针访问)

1.指针和一维数组
int a[5]={1,12,3,4,5};//a是数组名也是首地址,地址常量
int *p=a;

int a[5]={1,12,3,4,5};
printf("%d %d\n",a[0],*a);// 1 1
printf("%d %d\n",*a,*(a+1));// 1 12
printf("%d %d\n",*a,*a+1);// 1 2
地址元素
pa1a[0]*a*pp[0]
p+1a+112
a[1]*(a+1)*(p+1)p[1]
p+2a+23a[2]*(a+2)*(p+2)p[2]
p+3a+34a[3]*(a+3)*(p+3)p[3]
p+4a+45a[4]*(a+4)*(p+4)p[4]

直接访问:

在这里插入图片描述

间接访问:

在这里插入图片描述

访问数组元素a[i]的值:

直接访问:a[i] *(a+i)

间接访问:p [i] *(p+i)

访问数组元素a[i]的地址:

直接访问:&a[i] a+i

间接访问:&p[i] p+i

举例:


int a[10]={1,2,3,4,5};

int * p = a;

printf("%d\n",*p++);//1

printf("%d\n",*a++);//报错,a是地址常量

*p++ :先取p的值,再对p向后移动一个单位

*(p++):先取p的值,再对p向后移动一个单位

(*p)++ :先取p的值,然后对值进行自加操作,指向不变

++*p :先取p的值,然后对值进行自加操作

++(*p) :先取p的值,然后对值进行自加操作

*++p :p自加(向后移动一个数据),然后取内容

*(++p) :p自加(向后移动一个数据),然后取内容

2.二维数组
int a[2][3]={1,2,3,4,5,6};//a:数组名,第一行的首地址,a+1:第二行的首地址
//*:表示降级,将行地址降级为列地址
//*a:第一行第一列的地址
//*a+1:第一行第二列地址
//*(a+1):第二行第一列地址
//*(a+1)+1:第二行第二列地址
int a[2][3] = {1, 12, 3, 4, 5};
printf("%p %p %p %p\n", a, a[0], a[0] + 1, a[1]);
printf("%p %p %p %p\n", a, *a, *a + 1, *(a + 1));

在这里插入图片描述

在这里插入图片描述

访问a[i][j]的地址:

a[i]+j *(a+i)+j

访问a[i][j]的值

*(a[i]+j ) *((a+i)+j)

12.数组指针

  1. 定义:指向数组的指针

  2. 格式:存储类型 数据类型 (*指针变量名) [列数]

    int a[2][3]={1,2,3,4,5,6};
    int (*p) [3]= a;//sizeof(p)=4  32位操作系统
    //int (*)[3]  3:表示三个三个数据的运算
    

    访问a[i][j]地址:

    p[i]+j *(p+i)+j

    访问a[i][j]值:

    *(p[i]+j) *( *(p+i)+j)

13.指针数组

  1. 定义:本质是数组,数组里面存放指针

  2. 格式:存储类型 数据类型 *数组名 [元素个数]

    int *arr[5];
    
  3. 应用实例:

    1. 存放普通变量地址

      int a = 10,b=20,c=30;
      int *p[3]={&a,&b,&c};
      //访问b的值?
      *p[1]  **(p+1)
      //访问b的地址?
      p[1]   *(p+1)
      
    2. 用于存放二维数组每行第一列地址

      int a[2][3]={1,2,3,4,5,6};
      int *p[2]={a[0],a[1]};
      //访问a[1][2]的地址
      p[1]+2   *(p+1)+2
      //访问a[1][2]的数据
      printf("%d %d\n",*(p[1]+2),*(*(p+1)+2));
      
    3. 用于存放字符串

      char *p[3]={"hello","world","hqyj"};
      //打印"world"?
      printf("%s\n",p[1]);//world
      printf("%s\n",*(p+1));//world
      //打印字符'd'
      printf("%c\n%c\n",*(p[1]+4),**(p+1)));//d d
      
    4. 命令行参数

      int main(int argc, char const *argv[]){
      	printf("%s %s %s\n",argv[0],argv[1],argv[2]);
      	printf("%d\n",argc);
      	return 0;
      }
      
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值