(嵌入式八股)No.1 C语言(3)
3.1 指针(重点、重中之重)
指针是 C 语言中一个非常强大且灵活的特性,它允许程序直接操作内存地址。指针可以用于多种用途,包括动态内存分配、访问数组元素、实现数据结构(如链表和树)等。
指针是一个变量,其存储的内容是另一个变量的地址。(好了,你知道指针就是一个地址就学完了(bushi))哈哈哈哈哈开玩笑呢
推荐一本书《C和指针》!!!
int a = 10; int *p = &a; // p 中保存着 a 的地址 a:普通变量,存放的是值 10; p:指针变量,存放的是 a 的地址; *p:解引用操作,取出 p 指向的地址中保存的值(即 a 的值)。
指针的四层关系
表达式 |
含义 |
|
变量本身(值) |
|
变量的地址 |
|
指针变量本身(保存地址) |
|
指针指向的值(间接访问) |
指针声明和类型
int *p1; // 指向 int char *p2; // 指向 char float *p3; // 指向 float void *p4; // 通用指针(不能直接解引用) 指针类型决定了解引用后的数据解释方式(即:从内存中取多少字节、如何解释)。
必考:指针与数组(面试也会问)
指针与数组的区别?( easy)
- 数组名是常量(指向固定内存),不能修改;
- 指针是变量,可以指向别的地址;
- sizeof(arr) 是整个数组大小;
- sizeof(ptr) 是指针大小(通常 4 (32 位系统)或 8 字节(64 位系统))。
一维数组与指针
intarr[3] = {10, 20, 30};
int *p = arr; // arr 等价于 &arr[0]
printf("%d\n", *(p+1)); // 输出 20
- 关系:问的比较多的就是指针和数组的关系!
- arr → 数组首元素地址&arr[0] → 数组首元素地址
- *p → 等价于 arr[0]*(p+i) → 等价于 arr[i]
二维数组与指针
int a[2][3] = {{1,2,3},{4,5,6}};
int (*p)[3] = a; // p 指向含 3 个 int 的一维数组
printf("%d\n", *(*(p+1)+2)); // 输出 6
说明:p 是一个“指向长度为 3 的 int 数组”的指针;
p+1 指向下一行;*(p+1) 是该行的首地址;
*(p+1)+2 指向该行的第 3 个元素。
指针与函数
指针作函数参数(传址调用)
void swap(int *a, int *b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
指针函数(这个面试会和函数指针一起考)
指针函数是一个返回值为指针的函数。它的返回值是一个指针类型。
int* func()
{
static int x = 10;
return &x;
}
函数指针
函数指针是一个指针变量,它指向一个函数的入口地址。通过函数指针,可以像调用普通函数一样调用被指向的函数。
int add(int a, int b) { return a + b; }int (*pf)(int, int) = add;printf("%d\n", pf(3,4)); // 输出 7
函数指针可以用于 回调函数、事件处理(动态选择函数:根据条件动态调用不同的函数)、函数表:将多个函数指针存储在数组中,通过索引调用不同的函数 等。
野指针问题
什么是野指针
(1)野指针就是指向未知位置的指针。
(2)指针局部变量未初始化会造成野指针,使用 free 后没有将指针置为 NULL 也会造成野指针。
野指针的危害
(1)指向不可访问的地址,譬如内核空间:触发段错误。
(2)指向一个可访问的、没什么意义的地址,譬如空闲栈空间:不会触发明显错误,但会留下安全隐患。
(3)指向一个访问的被程序使用的地址,譬如说一个变量:导致数据被损害或者程序崩溃,危害最大。
怎样避免野指针
(1)定义指针时初始化为 NULL 或者绑定一个可用地址空间。
(2)指针使用完之后,将其赋值为 NULL。
#include <stdio.h>
int main() {
int *ptr; // 未初始化,此时 ptr 是一个野指针(指向随机地址)
int *ptr = NULL; // 必须初始化
// 尝试访问野指针指向的内存(危险操作!)
printf("%d\n", *ptr); // 未定义行为:可能打印随机值、崩溃或产生其他不可预料的结果
return 0;
}
/*释放后未置空 */
#include <stdio.h>
#include <stdlib.h>
int main() {
int *ptr = (int*)malloc(sizeof(int));
*ptr = 42;
free(ptr); // 内存已释放,但 ptr 仍指向原地址(此时成为野指针)
// 错误:继续使用已释放的指针 应该先 ptr = NULL ;
printf("%d\n", *ptr); // 未定义行为
return 0;
}
3.2 位运算
(有的面试官会考察,或者笔试题里面会出现)(芯片厂最喜欢考了)
位操作符
1.位与&
(1)注意:位与是&,逻辑与是&&。举例 0xAA&0xF0=0xA0,0xAA && 0xF0=1
2.位或|
(1)注意:位或是 |,逻辑或是||。
3.位取反~
(1)注意:C 语言中位取反是~,逻辑取反是!.
4.位异或^
(1)0 或 1 与 1 位异或就会取反,0 或 1 与 0 位异或则不变。
5.位左移、位右移
(1)对于无符号数:
①左移时右侧补 0,相当于逻辑移位。
②右移时左侧补 0,相当于逻辑移位。
(2)对于有符号数:
①左移时右侧补 0,叫算术移位,相当于逻辑移位。
②有右移时左侧补符号位,正数补 0 负数补 1,叫算术移位。
(3)嵌入式中使用的移位都是无符号数移位。
&,|,^在操作寄存器时的特殊作用
1.寄存器的操作要求
(1)ARM 是内存与 IO 统一编制的(x86 则不是),读写寄存器就是操控硬件。
(2)如何做到设定特定位时不影响其它位?答案是:读-改-写三部曲。
2.特定位清零用&
3.特定位置 1 用|
4.特定位取反
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
从入门到上岸,一站式搞定求职! 本硕纯机械,无竞赛无论文,后转行嵌入式软件开发(因为课题组师哥转嵌入式拿到30Woffer之后狠狠心动),秋招最终收获35W+offer可以为27届或者28届的的UU们提供参考,可以关注一下!!!
