嵌入式开发学习(第二阶段 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;
-
特性
- 指向的数据不可通过指针修改,指向对象的值不可变(
*p = x
非法); - 指针本身可指向其他地址,指向可以变(
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是指针常量
-
特性
- 指向的数据可通过指针修改, 指向对象的值可变 (
p= &
合法) - 指针本身不可指向其他地址, 指针的指向不变(
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是常量指针常量
-
特性:
- 指针的指向不可变(
p = &b
非法) - 指针指向的数据不可变(
*p = x;
非法)
- 指针的指向不可变(
-
注意:
定义时必须初始化
int a = 10; const int *const p = &a; // 正确
简单理解,不管是常量指针、指针常量,还是常量指针常量,本质上都是一个赋值受到限制的指针变量。
总结对比
关键点
const
在*
左侧:修饰数据(常量指针)const
在*
右侧:修饰(指针常量)- 函数参数优先使用常量指针,提高代码安全性
- 指针常量必须初始化,且不可重新指向
野指针、空指针、悬空指针
野指针
**定义:**指向无效内存区域(如果未初始化、已释放或访问越界)的指针称为野指针。野指针会导致未定义行为。
危害:
- 访问野指针可能引发段错误(segmentation Fault)
- 可能破坏关键内存数据,导致程序崩溃。
产生场景
-
指针变量未初始化
int *p;//p未初始化,是野指针 printf("%d\n",*p); //危险操作
-
指向已经释放内存
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称为野指针
-
返回局部变量的地址
int *fun(int a,int b) {int p = a + b;return &p; } int main() {int *p = fun(5,3);printf("%d\n",*p);//危险操作 }
如何避免野指针
- 初始化指针为NULL。
- 释放内存后立即置指针NULL。
- 避免返回局部变量地址。
- 使用前检查指针有效性。
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 = π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;
}