C语言深度剖析--不定期更新的第六弹

extern关键字--最会帽子的关键字

看下面的代码:

test.h

c 复制代码
#pragma once
#include <stdio.h>
extern int x;//声明不要进行初始化,也就是赋值,因为声明不开辟空间

test.c

c 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include "test.h"
int x = 1234;//这里是定义,定义要开辟空间

这是关于变量的

但是在平常读代码的时候,函数没有声明,编译器也没有报错,这是因为编译器看到函数没有函数体,会默认为这是数,不会认为有问题

,不过从规范的角度来说,建议加上extern更好一些

struct关键字

先给出结论:struct关键字,定义结构体,本质是在制作类型

c 复制代码
#define NAME 64
#pragma warning(disable:4996)//用于处理字符串内容的
struct stu
{
	char name[NAME];
	int age;
	char sex;
	char addr[NAME];
};
//a,b,c;
//这个有点类似于定义int a...

int main()
{
	struct stu x;
	//strcpy(x.name, "nayeon");
	return 0;
}

需要注意的是如果直接写x.name,"nayeon",编译器会报错,方法1是用到库函数strcpy去拷贝,方法2是前面加上一个预处理指令

联系到前面学的指针,来看下面一行代码:

c 复制代码
struct stu *p=&x;

这里取地址取的是结构体里面地址最低的

打印的代码:

c 复制代码
printf("%s",(*p).name);

上面是运行结果,我们可以很明白,解引用相当于指向地址所保存的内容,也就是x

但是我们一般不这么写,因为有点复杂

我们一般这么写:

c 复制代码
printf("%s",p->name);

为什么结构体访问会有两种形式?

C语言是面向过程的语言,主要体现在函数,任何函数都需要传参,传参会形成临时变量,临时变量需要向栈帧申请空间,栈帧需要预估所需要的大小,如果结构体过大的话,会导致程序运行效率降低,所以用指针传参可以提高效率

注意点:

VS编译器不允许空结构体的出现,会报错

柔性数组

写法如下:

C 复制代码
struct stu
{
	char name[100];
    int arr[0];
}

柔性数组的应用:用来开辟变长数组

代码如下:

c 复制代码
struct data
{
	int num;
    int arr[0];
};
int main()
{
    printf("%d",sizeof(struct data));//这里不会计算柔性数组的大小
	struct data*p=malloc(sizeof(struct data)+sizeof(int)*10);//开辟变长数组的过程
}

这里的4是int类型的大小

柔性数组的应用:

代码如下:

c 复制代码
struct data* p = malloc(sizeof(struct data) + sizeof(int) * 10);//开辟变长数组的过程
p->num = 10;//设置10个元素
for (int i = 0; i < p->num; i++)//遍历
{
	p->arr[i] = i
}
free(p);

我们发现int先开辟,我们知道编译器从低地址读起。

我们可以做个验证:

很明显发现了不一样,且差距为4,也是int类型的大小,所以int num是低地址。

union关键字

联合体和结构体类似,区别在于计算它的大小:

打比方就像一个家庭里的事情是有谁来决定呢,一般是父亲或母亲,因为他们的权力更大一点,所以union也类似,谁大计算谁的大小

书写格式和struct差不多

c 复制代码
union un
{
	int a;
	char b;
};

这里开辟空间和struct的区别:

拿上面的a和b举例,

b永远在a的低地址==,空间地址存储由低地址向高地址成放射状

每一个都是第一个元素

再来看一种情况:

数据存储很灵活,空间布局很固定

测试代码如下:

c 复制代码
union un x;
x.a = 1;
if (x.b == 1)
{
	printf("小端\n");
}
else
{
	printf("大端\n");
}

来看下面代码:

c 复制代码
union un
{
	int i;
	char a[4];
}*p,u;
int main()
{
p = &u;
p->a[0] =0x39;
p->a[1] = 0x38;
p->a[2] = 0x37;
p->a[3] = 0x36;
printf("%x\n", p->i);
	return 0;
}

读取是按照大小端的方式读的,这里为了验证两个变量共用一块空间,所以用了这样的方式,把char a[4]的值赋给i,编译器在读取地址的时候是按照字节的方式读取的,而且通常情况下是小端读取,小端我们知道一个口诀:小小小。低权值位的数据放在低地址区,所以是这样的。

相关推荐
CoovallyAIHub7 小时前
中科大DSAI Lab团队多篇论文入选ICCV 2025,推动三维视觉与泛化感知技术突破
深度学习·算法·计算机视觉
NAGNIP8 小时前
Serverless 架构下的大模型框架落地实践
算法·架构
moonlifesudo8 小时前
半开区间和开区间的两个二分模版
算法
moonlifesudo8 小时前
300:最长递增子序列
算法
CoovallyAIHub13 小时前
港大&字节重磅发布DanceGRPO:突破视觉生成RLHF瓶颈,多项任务性能提升超180%!
深度学习·算法·计算机视觉
CoovallyAIHub13 小时前
英伟达ViPE重磅发布!解决3D感知难题,SLAM+深度学习完美融合(附带数据集下载地址)
深度学习·算法·计算机视觉
聚客AI1 天前
🙋‍♀️Transformer训练与推理全流程:从输入处理到输出生成
人工智能·算法·llm
大怪v1 天前
前端:人工智能?我也会啊!来个花活,😎😎😎“自动驾驶”整起!
前端·javascript·算法
惯导马工1 天前
【论文导读】ORB-SLAM3:An Accurate Open-Source Library for Visual, Visual-Inertial and
深度学习·算法
骑自行车的码农2 天前
【React用到的一些算法】游标和栈
算法·react.js