嵌软八股大全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、元素访问

两种方式

  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、元素访问

同样也是两种方式

  1. 数组下标
  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 的区别?

  1. num 和 &num 一样,均表示数组的起始地址
  2. 对于一维数组,num+1 表示偏移到数组内下个元素,&num + 1 则表示偏移整个数组
  3. 对于二维数组,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

从输出可以得出

  1. array_1 = &array_1,array_2 = &array_2
  2. array_1+1 偏移了 4 字节,也即一维数组 array_1 内一个元素
  3. &array_1+1 偏移了 12 字节,也即一维数组 array_1 所占字节数
  4. array_2+1 偏移了 12 字节,也即二维数组 array_2 第一行一位数组
  5. &array_2+1 偏移了 36 字节,也即二维数组 array_2 所占字节数

Pointer

1、基本概念

1.1、指针类型、指针指向类型、指针值、指针地址

  1. 指针 ptr 类型为 int*
  2. 指针 ptr 指向类型为 int
  3. 指针 ptr 的值为 &a(变量 a 的地址),就是地址
  4. 指针 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

alt

1.2、求指针占据内存大小

  1. 在 32 位系统中,一个指针变量在内存中占据 4 个字节的空间
  2. 在 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;
}

alt

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;
}

alt

指针常量常常被用在函数参数上,这个函数只需要读取原始数据,不需要(也不可以)改变原始数据

void getData(const int* ptr)
{
	//do somethings
}

2.1.3、简单记忆

  1. 指针本身是一个常量 -> 指针常量 -> 地址不可以修改(error: ptr=&b;)
  2. 指向常量的一个指针 -> 常量指针 -> 值不可以修改(error: *ptr=2;)

2.2、void * 类型指针

  1. 任意类型的指针均可直接赋值给空指针 ptr
  2. 空指针 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%涵盖,但面试可以。

全部评论

相关推荐

评论
点赞
1
分享

创作者周榜

更多
牛客网
牛客企业服务