当前位置: 首页 > news >正文

嵌入式开发学习(第二阶段 C语言笔记)

指针

main函数原型

定义

main函数有多种定义格式,main函数也是函数,函数相关的结论对main函数野有效。

main函数完整写法:

int main(int argc,char *argv[]){...}
int main(int argc,char **argz){...}

扩展写法:

main ()   等价与  int main{}    //C11之后不再支持,省略返回类型
int main(void){}    等价 int main(){}
void main(void){}   等价 void main(){}
int main(int a){}  
int main(int a,int b,int c){}
...
说明

①argc,argv是形参,他们俩可以修改

②main函数的扩展写法有些编译器不支持,编译报警告

③argc和argv的常规写法

  • argc:存储了参数的个数,默认是1个,也就是运行程序的名字

  • argv:存储了所有参数的字符串形式

④main函数是系统通过函数指针的回调调用。

/*************************************************************************> File Name:    demo01.c> Author:       小刘> Description:  > Created Time: 2025年05月23日 星期五 09时19分38秒************************************************************************/#include <stdio.h>int main(int argc,char *argv[])
{//访问参数的个数printf("argc = %d\n",argc);// 遍历参数(每个参数都是字符串常量)for(int i = 0;i < argc ;i ++){printf("%s,%s\n",argv[i],*(argv + i));}printf("\n");return 0;
}

运行结果:

在这里插入图片描述

常量指针与指针变量

常量类型

①字面量:直接使用的固定值(如 12, hello, orange, 李双真帅 )符号常量在编译器转换为了字面量

②只读常量:用const 修饰的变量,初始化后不可修改。

const int a = 10;//只读常量
a = 21;   //编译报错
常量指针
  • 本质:指向常量数据的指针

  • 语法:

    const 数据类型 *变量名;
    const 数据类型* 变量名;
    
  • 举例

    const int *p;
    
  • 特性

    1. 指向的数据不可通过指针修改,指向对象的值不可变*p = x 非法);
    2. 指针本身可指向其他地址,指向可以变p = &b 合法)
  • 应用场景

    函数参数保护数据不被修改,使用率高

    // 遍历数组
    void print_array(const int *arr, int len);
    
  • 案例演示

    #include <stdio.h>int main(int argc,char *aegc[])
    {int a = 10;int *const p = &a;*p = 100;printf("%d\n",*p);int b = 20;p = &b;printf("%d\n");return 0;
    }
    
常量指针常量
  • **本质:**指针本身是常量,指向固定地址

  • 语法:

    数据类型* const 变量名;
    数据类型 *const 变量名;
    
  • 举例

    const int * const p;//p是指针常量
    
  • 特性

    1. 指向的数据可通过指针修改, 指向对象的值可变p= &合法)
    2. 指针本身不可指向其他地址, 指针的指向不变 p = &b 非法)
  • 注意:

    定义时必须初始化

    int a = 10;
    int *const p = &a; // 正确
    
  • 案例演示:

    #include <stdio.h>
    int main(int argc,char *argv[])
    {int a = 10; // 变量int *const p = &a; // 常量指针*p = 100; // 正确,指向对象的值可以改变printf("%d\n",*p); // 100int b = 20; // 变量p = &b; // 错误,指向不可以改变printf("%d\n",*p); return 0;
    }
    
常量指针常量
  • 本质:指针的指向和指向的数据均不可改变

  • 语法:

    const 数据类型* const 变量名;
    const 数据类型 *const 变量名;
    
  • 举例:

    const int* const p; // p是常量指针常量
    
  • 特性:

    1. 指针的指向不可变( p = &b 非法)
    2. 指针指向的数据不可变( *p = x; 非法)
  • 注意:

    定义时必须初始化

    int a = 10;
    const int *const p = &a; // 正确
    

简单理解,不管是常量指针、指针常量,还是常量指针常量,本质上都是一个赋值受到限制的指针变量。

总结对比

在这里插入图片描述

关键点
  1. const*左侧:修饰数据(常量指针)
  2. const*右侧:修饰(指针常量)
  3. 函数参数优先使用常量指针,提高代码安全性
  4. 指针常量必须初始化,且不可重新指向

野指针、空指针、悬空指针

野指针

**定义:**指向无效内存区域(如果未初始化、已释放或访问越界)的指针称为野指针。野指针会导致未定义行为。

危害:

  1. 访问野指针可能引发段错误(segmentation Fault)
  2. 可能破坏关键内存数据,导致程序崩溃。

产生场景

  1. 指针变量未初始化

    int *p;//p未初始化,是野指针
    printf("%d\n",*p); //危险操作
    
  2. 指向已经释放内存

    int fun(int a,int b)
    {int p = a+b;return &p;
    }int main()
    {int *p = fun(5,3);printf("%d\n",*p);//危险操作
    }
    -----------------------------------------------
    int *p = malloc(sizeof(int));
    free(p);
    printf("%d\n",*p);// p称为野指针
    
  3. 返回局部变量的地址

    int *fun(int a,int b)
    {int p = a + b;return &p;
    }
    int main()
    {int *p = fun(5,3);printf("%d\n",*p);//危险操作
    }
    

如何避免野指针

  1. 初始化指针为NULL。
  2. 释放内存后立即置指针NULL。
  3. 避免返回局部变量地址。
  4. 使用前检查指针有效性。
int fun()
{int *p = pt;//校验指针if(p == NUll){printf("错误!");return -1;}printf("%d\n",*p);
}
空指针

定义:值为 NULL 的指针,指向地址0x0000 0000(系统保留,不可访问)

在这里插入图片描述

**作用:**明确表示指针当前不指向有效内存。一般用作指针的初始化

示例:

int *p = NULL;//初始化为空指针free(p);//释放后置空
p = NULL;
空悬指针

定义:指针指向已被释放,但未重新赋值。空悬指针是野指针的一种特例。

示例:

char *p = malloc(100);
free(p);// 释放p指向的空间
// free(p) 一定要置空,否则会产生空悬指针现象,p = NULL
printf("%p\n",p); // p仍保留原地址,称为空悬指针

void 与void * 的区别

定义
  • void:表示“无类型”,用于函数返回类型或参数。

    void func(void );   //没有返回值也没有参数,一般简写,void func()
    
  • void* :通用指针类型(万能指针),可指针指向任意类型数据,但需要强制类型转换后才能解引用。

    void *ptr = mall0c(4);//ptr指向4个字节大小的内存空间
    //存放int
    //int *p (int *)ptr
    //*p = 10;//存放float
    float* p =(float *)ptr;
    *p = 21.5;
    

    注意:只能是具体的类型( int*,double*,float*,char*... )和 void* 之间转换

注意事项

void* 不能直接解引用(如: *ptr 会报错)
函数返回void*需要外部接收的时候明确类型(不明确类型,就无法解引用)

示例
/*************************************************************************> File Name:    demo02.c> Author:       小刘> Description:  > Created Time: 2025年05月23日 星期五 11时34分32秒************************************************************************/#include <stdio.h>
#include <stdlib.h>/*** 定义一个返回为void* 类型的指针函数*/ 
void* proces_data(void* p)
{return p;
}
int main(int argc,char *argv[])
{// int 类型int m = 10;int* p_int = &m;int* result_int = (int*)proces_data(p_int);printf("Integer value:%d\n", *result_int);// double类型double pi = 3.1415926;double* p_double = &pi;double* result_double = (double*)proces_data(p_double);printf("Double value:%.6f\n", *result_double);// void* generic_ptr = process_data(p_int);// *generic_ptr = 30; // 错误:void*不能直接解引用(必须明确类型,才能解引用)return 0;
}

相关文章:

  • Golang | gRPC索引服务
  • Java jdk8版本特性(未完成版)
  • 截图后怎么快速粘贴到notability?
  • 常规算法学习
  • 打印Yolo预训练模型的所有类别及对应的id
  • 基于Unsloth框架快速微调Qwen3-14B模型的全面指南,包括Unsloth框架技术原理与微调代码实现
  • jenkins报错java.lang.OutOfMemoryError: Java heap space
  • 基于bp神经网络的adp算法
  • 创建型设计模式之Singleton(单例)设计模式
  • SMME 2025:创新海洋工程模式,迎接未来挑战
  • Android Compose开发架构选择指南:单Activity vs 多Activity
  • 银河麒麟V10通过制作rpm包升级httpd、php软件修复漏洞
  • Python 训练营打卡 Day 38
  • 浅谈国企数字化转型
  • Jenkins-Pipeline:学习笔记
  • 什么是软件的生命周期,以及常见的开发测试模型
  • 电脑软件管家 免安装便携 四十多种功能系统优化”“磁盘清理”“隐私保护
  • 【行动指南】大一如何高效备考java
  • 密钥管理系统在存储加密场景中的深度实践:以TDE透明加密守护文件服务器安全
  • 十六进制数据转换为对应的字符串
  • 购物网站建设行情/萧山区seo关键词排名
  • 郑州seo顾问热狗hotdoger/seo综合查询怎么用
  • 小米网站建设/做竞价推广大概多少钱
  • 怎么查询网站其他域名/广州seo优化公司
  • 制作网站的程序语言/百度做广告怎么收费
  • gps建站步骤视频/快速网站排名提升