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

嵌入式学习---在 Linux 下的 C 语言学习 Day9

Day9

指针(Pointer)

指针与二维数组

二维数组在内存中是按行存储的。

二维数组存储形态如下图所示:

在这里插入图片描述

#include <stdio.h>int main()
{short a[][3] = {1,2,3,-4,-5,-6};*((short*)((short(*)[3])(&a + 1) - 1) + 1);/** a        --> short(*)[3] 和下面的 &a[0] 一样* &a       --> short(*)a[2][3]* a[0]     --> *(a + 0) short* 和下面 &a[0][0] 一样* &a[0]    --> short(*)[3]* &a[0][0] --> short**/short *p = (short*)a;//short *p = &a[2][3];for(int i = 0;i < 6;i++){printf("%hd ",*(p + i));if(i == 2){printf("\n");}}printf("\n");for(int i = 0;i < 2;i++){for(int j = 0;j < 3;j++){printf("%hd ",*(*(a + i) + j));}printf("\n");}return 0;
}

字符型指针

C 语言没有提供专门的字符串(String)类型,可以使用字符型指针(char*)表示一个字符串。所以字符型指针有两个用途:

  • 指向一个字符
  • 代表一个字符串(首字符指针可以代表整个字符串,因为首字符指针确定了,末尾字符又是’\0’,整个字符串就确定了)
// 字符型指针的常规用法
char c = 'a';
char* p = &c;(*p)++;
printf("%c\n",*p); // b// 字符型指针表示字符串
char s1[] = "abc";
printf("%c\n",*s1); // a
printf("%c\n",*(s1 + 2)); // cchar* p1 = s1;
printf("%s\n",p1); // abc
printf("%s\n",p1 + 1);// bc
printf("%c\n",p1[2]); // cchar* s2 = "abc";
s2 = "qzp";

在这里插入图片描述

typedef unsigned long size_t

strlen 的源码:

size_t strlen(const char* s)
{size_t len = 0;while(s[len] != '\0') len++;return len;
}
#include <stdio.h>
#include <string.h>int main()
{char   s1[] = "abc"; // char s1[] = {'a','b','c','\0'};char*  s2 = "abc";char*  s3 = "fasdjaisdjiahfjsi,,.,-=\nsdddddddsadasd";/*int    s3 = 3;double s4 = 3.14;*/printf("%lu\n",sizeof(s1));printf("%lu\n",sizeof(s2));printf("%lu\n",sizeof(s3));printf("%lu\n",strlen(s1));printf("%lu\n",strlen(s2));printf("%lu\n",strlen(s3));return 0;
}

一个 char* 可以表示一个字符串,多个 char* 可以表示多个字符串,即使用字符型指针数组(char* 数组)可以表示多个字符串

野指针:指向不确定位置的指针

#include <stdio.h>
#include <string.h>int main()
{char* s1; // 野指针// oks1++;s1 -= 3;// 访问野指针指向的数据,会发生不可预知的结果(*s1)++;(*s1) -= 3;char ss[100];s1 = ss;// s1 = "qzp"; // okstrcpy(s1,"qzp");char* s2 = NULL;printf("%c\n",*s2);return 0;
}

结构体(Struct)

若干个相同或不同类型数据数据的集合

数据成员(成员变量):Member Variables,构成结构体的数据

结构体是一种自定义数据类型,必须先声明,再使用

声明结构体类型的语法规则:

struct student
{// 定义各个数据成员(成员变量),也称为字段(Field)int sno;int height;char name[10];char sex;		// 0 - 女 1 - 男 2 - 未知 3 - 保密float sight;char* addr;    // 家庭住址// ......
};typedef struct
{int isbn;char name[50];float price;
} book;

通过使用已声明的结构体类型定义变量或常量

struct student s1;				 // 定义 student 类型的变量 s1,未初始化
const struct student s2 = {1001,180,"张三",1,4.8,"广东深圳"};  // 定义 student 类型的常量 s2,必须初始化struct student s3 = {1002,"张四",0,4.5,"北京"};// 结构体指定初始化,(不是 C 语言标准语法,只有 gcc 支持,属于 gcc 编译器扩展的语法特性)
struct student s4 = {.name = "王五",.sno = 1003,.sight = 4.3};book b1;
const book b2 = {1000,"计算机组成原理",35.5);
book b3 - {100002,"C语言",32.2};

中文编程语言:易语言等

不能直接访问整个结构体,只能访问结构体的数据成员:

s1.sno = 1009;
strcpy(s1.name,"张三");
s1.addr = "湖北武汉";//s2.sno = 1010; // error,因为 s2 是常量,也就是说它的所有数据成员都是只读的printf("书号:%d\n书名:%s\n单价:%g\n",b3.isbn,b3.name,b3.price);// 通过结构体指针访问它指向的结构体的数据成员要使用指向运算符(->)
struct student* p1 = &s1; // 定义一个 student 类型的指针变量 p1,初始值为 s1 的指针
p1 -> sno = 1009;
strcpy(p1->name,"张三");
p1->addr = "湖北武汉";book* p2 = &b3;
printf("书号:%d\n书名:%s\n单价:%g\n",p2->isbn,p2->ame,p2->price);

举例:

#include <stdio.h>
#include <string.h>typedef struct
{int isbn;char name[50];float price;} book;int main()
{book b1;printf("请依次输入图书的各项信息:\n");printf("书号:");scanf("%d",&b1.isbn);printf("书名:");scanf("%s",b1.name);printf("单价:");scanf("%f",&b1.price);b1.price += 5;printf("\n图书信息如下:\n");printf("书号:%d\n书名:%s\n单价:%g\n",b1.isbn,b1.name,b1.price);book* p1 = &b1;strcat(p1->name,"(牛逼)");p1->price += 5;printf("书号:%d\n书名:%s\n单价:%g\n",p1->isbn,p1->name,p1->price);return 0;
}

位域成员

结构体嵌套:结构体的数据成员也是结构体类型

struct wheel
{int id;char model[100];float price;
};struct car
{int num;char model[100];struct wheel w;  // 结构体嵌套float price;
};struct car c1 = {1001,"宝马X6",{2001,"米其林",200},180000};
c1.w.price += 10;struct car* p1 = &c1;
p1->w.price += 10;printf("汽车轮胎品牌:%s\n轮胎单价:%g\n",p1->w.model,c1.w.price);

如果需要表示多个结构体类型的数据,就用结构体数组

typedef struct
{int isbn;char name[50];float price;
} book;book bs[100] = {{1001"计算机组成原理",35.5},{1002,"C语言",40.5}} // 结构体数组bs[3].isbn = 1003;
strcpy(bs[3].name,"操作系统");
// 下面三种写法完全等效
bs[3].price = 45.5;
(*(bs + 3)).price = 45.5
(bs + 3)->price = 45.5for(int i = 0;i < sizeof(bs) / sizeof(bs[0]);i++)
{printf("\n第 %d 本图书的信息如下:\n",i);  printf("书号:%d\n书名:%s\n单价:%g\n",bs[i].isbn,bs[i].name,bs[i].price);
}

在实际开发中,结构体往往很大(几十个或上百个数据成员都是常态),如果函数的返回值和形参需要使用结构体,强烈建议使用结构体指针,这样做效率更高,占用的内存空间也更小。

struct student
{// 定义各个数据成员(成员变量),也称为字段(Field)int sno;int height;char name[10];char sex;		// 0 - 女 1 - 男 2 - 未知 3 - 保密float sight;char* addr;    // 家庭住址// ......
};void set_stu(struct student* s)
{s->sight++;printf("%s\n",s->name);
}void show_stu(const struct student* s)
{printf("%d\n",s->sno);printf("%s\n",s->name);
}

结构体的数据成员按照定义顺序连续存储,先定义的地址小,后定义的地址大,但它们不一定相邻,因为受到内存对齐机制的影响,所以结构体总大小会大于或等于它的所有数据成员的宽度之和

结构体大小计算规则:

  • 每个数据成员的相对地址必须是其类型宽度和内存对齐系数二者中较小值的整数倍
  • 结构体总大小必须为所有数据成员中的最大宽度和内存对齐系数二者中较小值的整数倍
  • 数组类型的数据成员就将它看作多个同类型数据成员处理就行,还是遵守上面两条规则
  • 结构体类型的数据成员的自身大小还是按照上面的三条规则计算,但是它的类型宽度应该用它内部最大数据成员的宽度计算

64 位系统上默认内存对齐系数是 8 字节,可以使用 #pragma pack 预处理命令修改内存对齐系数,内存对齐系数必须为 2^n,比如:1、2、4、8

#include <stdio.h>// #pragma pack(1)
struct person
{char sex;int num;short height;double sight;char state;
};int main()
{printf("%lu\n",sizeof(struct person));return 0;
}

在这里插入图片描述

内存对齐机制虽然浪费了一些内存空间(中间会填充若干空闲字节),但换来了内存读写效率的提升

http://www.lryc.cn/news/612569.html

相关文章:

  • 河南萌新联赛2025第(四)场【补题】
  • 云端软件工程智能代理:任务委托与自动化实践全解
  • 【golang】基于redis zset实现并行流量控制(计数锁)
  • 【AI智能编程】Trae-IDE工具学习
  • javascript常用实例
  • Dart语言语法与技术重点
  • InfluxDB 集群部署与高可用方案(一)
  • 解决Node.js v12在Apple Silicon(M1/M2)上的安装问题
  • css怪异模式(Quirks Mode)和标准模式(Standards Mode)最明显的区别
  • Java零基础笔记13(Java编程核心:异常、泛型)
  • 数据结构 二叉树(1)二叉树简单了解
  • Python数据可视化:从基础到高级实战指南
  • Pytorch-07 如何快速把已经有的视觉模型权重扒拉过来为己所用
  • C语言的数组与字符串练习题1
  • VINS-Fusion+UWB辅助算法高精度实现
  • KNN算法:从原理到实战应用
  • 人工智能——深度学习——认识Tensor
  • k8s的存储之statefulset控制器
  • 数据结构(4)
  • 图解 Claude Code 子智能体 Sub-agent
  • Verilog 仿真问题:打拍失败
  • C语言高级编程技巧与最佳实践
  • 如何给小语种视频生成字幕?我的实测方法分享
  • docker-compose部署file browser
  • P1983 [NOIP 2013 普及组] 车站分级
  • Spring文件泄露与修复方案总结
  • Unity 调节 Rigidbody2D 响应速度的解决方案【资料】
  • 聚合链接网站源码部署教程
  • 【开源分享】can-utils:深入解析 Linux CAN 工具集
  • 面试经典150道之多数元素