首页 > 其他分享 >C语言之指针

C语言之指针

时间:2024-10-24 09:50:09浏览次数:1  
标签:函数 指向 int C语言 char 数组 指针

C语言之指针

1.指针

内容RAM支持随机寻址,对内存空间的访问通过地址进行

  • 变量名的本质就是地址的别名,编译器根据符号表进行绑定解析。
  • 指针的初衷用途就是通过间接访问的方式支持内存空间的匿名访问

指针的类型与所指向的数据类型相关联,但本质是储存地址,其大小与系统有关,与类型无关

  • 指针类型可以支持编译器类型检查
  • 指针运算与类型相关联

声明

  • 指针的类型

    • 函数指针: void (*f)(int, int);
    • 对象指针: char*, int*
    • 通用指针: void*, 一般作为函数的参数使用,转为其他类型需要强制类型转换,不不会丢失数据
  • 指针相关的运算符,优先级依次递增

    • 类型声明:int *
    • 取址:&
    • 间接访问:*
    • 自增自减:--, ++
    • 成员选择:->
    • 其他:(),[]
  • 易混淆的指针表达式,基于运算符的优先级与结合性

    *p++;       // 间接访问(*p),然后自增p++
    &p++;       // 指针的地址自增(&p)++
    &a.name;    // &(a.name)
    int *a[];   // 指针数组,元素类型 int*
    int (*a)[]; // 数组指针,指向数组 int []
    int *f();   // 指针函数,返回值 int*
    int (*f)(); // 函数指针,指向函数 int f();
    int *(*f)[];// 数组指针,指向 int * a[], 元素类型 int*
    

运算

所有指针运算都会自动考虑所指向对象的长度

  • 有效的初始化:NULL或者表示地址的表达式
  • 有效的运算
    • 相同类型指针之间的赋值
    • 指针与整数之间的加减法
    • 数组或链表中相同类型的两个指针之间的减法和比较
      • 允许赋值但不可访问最后一个元素的下一个元素的位置
      • 减法的单位是数据类型的长度而不是字节
    • 将指针赋值为0或者与0进行比较

2.指针与函数

指针作为函数参数

  • C语言基于传值方式将参数传递给函数,将指针作为函数参数可以实现在函数内修改实参

指针函数

  • 函数的返回值类型是指针

函数指针

  • 指向函数的指针

    int func(void);   // 声明函数
    int (*fp)(void);   // 声明函数指针
    fp = func;         // 等价于 f = &func;
    fp();              // 调用函数,等价于 (*f)();
    
  • 类似于数组名,函数名就是指向函数的指针常量,即函数的入口地址。

  • 主要用途

    • 回调函数
    • 转换表

3.指针与数组

  • 数组下标操作 E1[E2] 等价于指针操作 *(E1+E2)

    • 一般后者效率稍好,但前者更具可读性
    • 具体可参考 《C和指针》8.1.3和8.1.4中关于二者的效率对比
  • 数组名与数组指针:

    • 数组名表示数组首个元素的地址

      int a[5];   // 声明数组,分配5个整型空间
      int *p;     // 声明指针变量,并未初始化
      
      // 情景1 赋值给字符指针
      p = a; // 等价于 p = &a[0]; 
      
      // 情景2 将数组名作为参数,实际传递的是指针
      int f(int *a); // 等价于 int f(int a[]); 但更推荐指针类型的写法
      
    • 数组名表示整个数组

      // 情景1 声明一个数组
      int a[3] = {1, 2, 3};
      
      // 情景2 使用sizeof计算整个数组的大小
      #define NKEYS (sizeof(a) / sizeof(a[0]))
      
      // 情景2 取址运算
      int (*pa)[3];
      pa = &a;    // 将数组的地址赋值给数组指针
      
  • 注意指针的合法运算

指针与字符串

字符指针

字符串本质是一个字符数组常量,一般通过字符指针进行访问。

// 只是字符指针的赋值,不涉及字符串的复制
char p1 = "hello";
char p2  = p1;

4.指针与结构体

  • 将指向结构体的指针传递给函数优化效率,使用->间接访问成员

  • 利用指针实现引用声明

    // 自引用结构
    struct tnode {
        struct *tnode left;
        struct *tnode right;
    }
    // 所有指针大小一致,编译期间即可确定长度
    
    // 互引用结构
    struct B;   // imcomplete declaration
    
    struct A {
        struct B *ref;
    }
    
    struct B {
        struct A *ref;
    }
    
  • 结构体地址与其第一个成员的地址相同,但是类型不同

    类似于数组与其首元素

    typedef struct A {
        int a;
    } T_A, *PT_A;
    
    T_A ta = {100};
    PT_A pa = &ta;      // pa是指向结构体的指针,*pa表示结构体ta
    int *p = &pa->a;    // p是指向整型的指针,*p表示ta.a
    // pa和p的值相等,因为ta和ta.a的地址相同,但是二者的类型并不相同
    
  • 经典应用:链表

5.二级指针

  • 修改指针变量的值

  • 指针数组传参

    // 指针数组和二维指针作为函数参数是等价的
    int main(int argc, char *argv[]);
    int main(int argc, char **argv);
    
  • 操作二维数组

    void array_print(int a[][5]);
    void array_print(int (*a)[5]);
    

6.辨析

指针与常量

int const *p = &a;  // 指向常量的指针,const修饰(*p), 改向不改值
int * const p = &a;  // 指针类型的常量,const修饰p, 改值不改向

字符指针与字符数组

char a[] = "hello"; // 字符数组,字符元素可以修改,数组位置不可变
// 等价于 char a[] = {'h', 'e', 'l', 'l', 'o', '\0'};

char *p = "world";   // 字符指针,指向字符串常量,字符不可修改,指向的位置可以改变

数组名

int a[] = "hello";
printf("%p\n", a+1);    // 首元素的下一个元素的地址
printf("%p\n", &a+1);   // 下一个数组的地址  // TODO 等于a[5]的地址吗?

指针数组与数组指针

// 指针数组用于传递命令行参数,数组保存不等长字符串
// 数组指针用于参数传递二维数组,更方面体现其行数组等长的结构
char a[2][3] = {"abc", "def"};
char (*p)[3] = a;
char **pp = &a[0][0];
int f1(char **p1);      // pointer to pointer to char
int f2(char *p2[]);     // array of pointer to char
int f3(char (*p3)[3]);  // pointer to array[3] of char
int f4(char p4[][3]);   // array of array[3] of char

指针数组与二维数组

int a[5][10];   // 二维数组,分配50个int类型长度空间
int *p[10];     // 指针数组,仅分配了10个指针,且没有初始化,但是指针所指向的长度无需相同
// 后续都可以通过 a[i][j]的形式访问,本质上还是指针运算

int (*p1)[10] = a; // 数组指针,指向int array[10]的数组 a[0]
// 数组指针作为参数传递二维数组需要显式说明长度 int f(int (*p)[10]);

7.参考

  • 《C程序设计语言》-2th
    • 5.指针和数组
    • 6.4 指向结构的指针
      • 6.2 结构与函数
      • 6.3 结构数组
      • 6.5 自引用结构
  • 《C和指针》
    • 6.指针
    • 8.数组
    • 9.字符串、字符和字节
    • 10.结构体和联合
    • 13.高级指针话题
  • 《嵌入式C语言的自我修养》
    • 7.8从变量到指针
    • 7.9指针与数组的暧昧关系
    • 7.10指针与结构体
    • 7.11二级指针
    • 7.12函数指针

标签:函数,指向,int,C语言,char,数组,指针
From: https://www.cnblogs.com/libq8/p/18498911

相关文章

  • C语言之static关键字
    C语言之static和extern关键字1.作用域标识符可见的区域,访问和重名由声明的位置所决定1.1代码块作用域BlockScope花括号{}之内函数形参(不会为函数内同名变量所隐藏)```CvoidmyFunction(intx){intx=10;//这里的x不会隐藏形参xprintf("%d......
  • C语言之声明
    C语言之声明1.声明与定义声明语法说明符(说明类型或修改缺省属性)声明表达式列表说明符类型说明:int,float存储属性:static,auto类型限定:const,volatile声明VS定义说明类型:取值范围和合法操作定义:分配存储空间2.初始化显式初始化静态变量(含全局变量):使用常......
  • 一分钟分辨常量指针和指针常量,再也不会忘记的那种
    你只需要记住下面这句话就可以了:**将变量定义式从右往左翻译为英文,其中的"*"译为pointerto**下面开始实践。常量指针/指向常量的指针(PointertoConstant)这种指针不能通过它修改所指向的字符内容,但指针本身可以指向其他地址。constchar*p1;p1isapointertochar......
  • 实验三蕉 C语言函数应用编程蕉
    实验三蕉C语言函数应用编程蕉可恶,是原始博士!什么时候!?......
  • C++中指针、引用与const的深入解析
    一、对数组的引用constintn=10;intar[n]={12,23,34,45,56,67,78,89,100};描述数组:类型加上原始空间大小。​int&ra=ar[1];​int&br=ar;//errorint(&br)[n]=ar;//okint*pa[10];int&pr[10];//error;为什么不能编译成功引用数组的概念:在C++中,......
  • 20241022_095024 c语言 字符串的方法
    源始字符串strlen方法strcat方法strcpy方法strcmp方法大小写转换......
  • 20241022_105024 c语言 模拟用户登陆
    需求代码......
  • [数据结构] 删除单链表中最小值结点(C语言版本)
    如果对单链表基本操作或概念不理解的可以跳转:单链表的基本操作(C语言版)-CSDN博客https://blog.csdn.net/m0_74181956/article/details/143082621?spm=1001.2014.3001.5501算法思想:如图所示:定义指针p为L的第一个结点,pre为L的头结点,min为记录每次遍历的最小值结点,minpre为记......
  • 数据结构C语言版_队列笔记||已测试所有代码均可运行
    队列源文件使用markdown编写,CSDN文章发布好像有部分语法改变。每一部分我都有加一个返回标题好像不能使用了。但是CSDN自带一个目录总结,你们无视掉我写的目录直接用CSDN的吧。总结笔记不易,如果有帮助到你希望点个赞。所有代码均已在VScode中运行过,部分代码块因为格式原因......
  • C语言趣味编程100例源码分享
    C语言趣味编程100例是学习路上必不可缺的示例,话不多说直接看代码1,百钱百鸡问题include<stdio.h>main(){intcock,hen,chicken;for(cock=0;cock<=20;cock++) /外层循环控制公鸡数量取值范围0~20/for(hen=0;hen<=33;hen++) /内层循环控制母鸡数量取值范围0~30/for(chic......