嵌软八股大全4 - C 数组与指针
Array
1、一维数组
1.1、初始化
// 1
int a[5] = {1,2,3,4,5};
// 2
int a[]={1,2,3,4,5};
1.2、元素访问
两种方式
- 数组下标
- 指针计算 (
+
与*
同等优先级,从右向左结合)
#include <stdio.h>
#define arr_length(a) (sizeof(a)/sizeof(a[0]))
int main()
{
int a[4] = {1,2,3,4};
int *p1 = a;
int (*p2)[4] = &a;
for(int i = 0;i < arr_length(a);i++)
{
// 1. 数组下标的方式
printf("%d ", a[i]);
// 2. 指针计算的方式
printf("%d ", *a+i);
printf("%d ", *p1+i);
printf("%d ", *(*p2+i));
printf("\n");
}
}
2、二维数组
2.1、初始化
// 1
int a[3][2] = {1,2,3,4,5,6};
// 2
int a[3][2] = {{1,2},{3,4},{5,6}};
// 3
int a[][2] = {1,2,3,4,5,6};
// 4
int a[][2] = {{1,2},{3,4},{5,6}};
2.2、元素访问
同样也是两种方式
- 数组下标
- 指针计算
直接看程序
#include <stdio.h>
int main()
{
int a[3][2] = {1,2,3,4,5,6};
int *p1 = &a[0][0];
int (*p3)[3][2] = &a;
for(int i = 0;i < 3;i++)
for(int j = 0;j < 2;j++)
{
// 1. 数组下标的方式
printf("%d ", a[i][j]);
// 2. 指针计算的方式
// 一维指针
printf("%d ", *(p1+i*2+j));
// 二维指针
printf("%d ", *(*(a+i)+j));
printf("%d ", *(*(*p3+i)+j));
printf("\n");
}
}
3、问题
3.1、数组名 num / &num 的区别?
- num 和 &num 一样,均表示数组的起始地址
- 对于一维数组,num+1 表示偏移到数组内下个元素,&num + 1 则表示偏移整个数组
- 对于二维数组,num+1 表示偏移一个一维数组,&num + 1 则表示偏移整个数组
#include <stdio.h>
int main(void)
{
//一维数组
int array_1[3]={1,2,3};
// array = &array, 均表示数组起始地址
printf("array_1=%p,&array_1=%p\n",array_1,&array_1);
printf("array_1+1=%p,&array_1+1=%p\n",array_1+1,&array_1+1);
//二维数组
int array_2[3][3]={{1,2,3},{4,5,6},{7,8,9}};
printf("array_2=%p,&array_2=%p\n",array_2,&array_2);
printf("array_2+1=%p,&array_2+1=%p\n",array_2+1,&array_2+1);
return 0;
}
output:
array_1=00000022d47ffba4,&array_1=00000022d47ffba4
array_1+1=00000022d47ffba8,&array_1+1=00000022d47ffbb0
array_2=00000022d47ffb80,&array_2=00000022d47ffb80
array_2+1=00000022d47ffb8c,&array_2+1=00000022d47ffba4
从输出可以得出
- array_1 = &array_1,array_2 = &array_2
- array_1+1 偏移了 4 字节,也即一维数组 array_1 内一个元素
- &array_1+1 偏移了 12 字节,也即一维数组 array_1 所占字节数
- array_2+1 偏移了 12 字节,也即二维数组 array_2 第一行一位数组
- &array_2+1 偏移了 36 字节,也即二维数组 array_2 所占字节数
Pointer
1、基本概念
1.1、指针类型、指针指向类型、指针值、指针地址
- 指针 ptr 类型为 int*
- 指针 ptr 指向类型为 int
- 指针 ptr 的值为 &a(变量 a 的地址),就是地址
- 指针 ptr 地址为 &ptr
#include <stdio.h>
int main(void)
{
int a = 99;
int* ptr =& a;
printf("&a=%p,&ptr=%p,ptr=0x%x,a=%d,*ptr=%d\n", &a, &ptr, a, ptr, *ptr);
}
pc output:
&a=0x605ff6e8,&ptr=0x605ff6e0,ptr=0x605ff6e8,a=99,*ptr=99
stm32f407 output:
&a=0x20000564,&ptr=0x20000560,ptr=0x20000564,a=99,*ptr=99
1.2、求指针占据内存大小
- 在 32 位系统中,一个指针变量在内存中占据 4 个字节的空间
- 在 64 位系统中,一个指针变量在内存中占据 8 个字节的空间
#include <stdio.h>
int main(void)
{
char *a;
printf("%llu",sizeof(a));
}
output:
8
2、相关操作
2.1、const 属性 (指针常量、常量指针)
const 属性表示只读,不可修改
2.1.1、指针常量 int* const ptr;
const 修饰指针 ptr,表示指针变量内容为只读,不可修改(指针常量),因此只能指向第一次赋值的变量
#include <stdio.h>
int main(void)
{
int a = 99;
int b = 11;
int* const ptr = &a;
// ❌,指针指向的地址不可修改
ptr = &b;
// ✅
*ptr = 22;
}
2.1.2、常量指针 const int *ptr;
const 修饰指针 ptr 指向的那个变量,表示指针指向的变量内容为只读,不可修改(常量指针),因此可以更改指针 ptr 指向的地址,但是不能修改指针指向地址变量的内容
#include <stdio.h>
int main(void)
{
int a = 99;
int b = 11;
const int *ptr = &a;
//int const *ptr = &a;
// ✅
ptr = &b;
// ❌,指针指向的变量值不可修改
*ptr = 22;
}
指针常量常常被用在函数参数上,这个函数只需要读取原始数据,不需要(也不可以)改变原始数据
void getData(const int* ptr)
{
//do somethings
}
2.1.3、简单记忆
- 指针本身是一个常量 -> 指针常量 -> 地址不可以修改(error: ptr=&b;)
- 指向常量的一个指针 -> 常量指针 -> 值不可以修改(error: *ptr=2;)
2.2、void * 类型指针
- 任意类型的指针均可直接赋值给空指针 ptr
- 空指针 ptr 赋值给其他类型的指针时需要强制类型转换
void *ptr;
2.3、空指针、野指针
2.3.1、空指针
不指向任何东西的指针 -> 空指针
int *ptr = NULL;
NULL 在 C 中实质为 void* 类型,在 C++ 中实质为 0
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
2.3.2、野指针
地址已经失效的指针 -> 野指针
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
// 申请一字节内存写入20
int *p = (int *)malloc(4);
*p = 20;
printf("*p=%d\n",*p);
// 释放掉申请的内存
free(p);
// 查看野指针
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
嵌入式软件名企笔/面试真题合集 文章被收录于专栏
欢迎来到我的专栏,在这里,我将整理并分享2024年各大企业的真实笔试/面试真题,帮助求职者了解考试趋势和嵌入式常见考点。无论你是准备面试,还是希望提升自己的专业知识,这里都能为你提供宝贵的参考和学习资源。//即将开始更新八股知识,预计增加12篇左右文章,内容涵盖C/C++基础、嵌软常见通信协议、ARM、FreeRTOS、Linux OS相关问题汇总,本人能力有限,虽不能100%涵盖,但面试可以。