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

2025_2_2 C语言中字符串库函数,结构体,结构体内存对齐

字符串相关库函数大多数都是需要字符串数组作为参数,因为它是可变的,但是有些参数也是不可变的const,即字符串常量。所以声明定义的时候需要区分清楚

1.strcpy

int main() {
	char p[15];
	strcpy(p, "Hello world");
	return 0;
}

strcpy()函数就是字符串复制函数,第一个参数是需要复制的内存空间,第二个参数是需要被复制的字符串值。

缺点:不能判断数组是否越界

2.strncpy

strncpy 用于将源字符串的前 n 个字符复制到目标字符串 中。如果 src 的长度小于 n,则会用空字符(\0)填充 dest,直到复制的字符总数达到 n

int main() {
	char str[10];
	int size = sizeof(str) / sizeof(str[0]);
	strncpy(str, "Hello world", size - 1);
	str[size - 1] = '\0';

	return 0;
}
  • 当需要复制的字符串长度大于给定数组空间时,只复制第三个参数给定的长度,但是最后没有空间加上\0了,所以传第三个参数时需要留一个位置存放\0。
  • 当需要复制的字符串长度小于给定数组空间时,strcpy后面剩余的所有位置都会被设置为\0.

3.strlen

strlen函数用于计算字符串的长度。不计算\0的长度。

4.strcat

strcat函数时字符串拼接函数

int main() {
	char str[20] = "Hello ";
	strcat(str, "world");
	return 0;
}

strcat函数第一个参数是需要改变的被拼接字符数组,第二个参数是需要拼接上去的字符串值
缺点:不能判断字符数组是否越界

5.strncat

strcat函数时字符串拼接函数,但是有了越界检测的机制。
第三个参数是需要改变的字符数组还剩下多少空间
strncat 会在追加完成后自动在目标字符串的末尾添加空字符(\0),因此目标字符串始终是有效的以空字符结尾的字符串。所以设置长度时一般留一个位置存储\0

int main() {
	char c[20] = "Hello ";
	int sz = sizeof(c) / sizeof(c[0]);
	strncat(c, "world", sz - strlen(c) - 1);
	return 0;
}

6.strcmp

strcmp 按字典顺序比较两个字符串 s1 和 s2。比较是基于字符的 ASCII 值进行的,从第一个字符开始逐个比较,直到遇到不同的字符或字符串结束符(\0)为止。

int main() {
	printf("%d\n", strcmp("abc", "abd"));
	printf("%d\n", strcmp("abc", "abc"));
	printf("%d\n", strcmp("abc", "ABC"));
	return 0;
}

在这里插入图片描述
因为这个函数不会改变参数的值,即传入的都是const的字符指针
所以可以使用字符常量进行比较

7.结构体

结构体和数组都是存储数据的类型,数组存储相同数据类型的数据,结构体可以存储不同数据类型的数据。

struct student_s {
	char name[10];
	char gender;//f:female m:male
};

8.结构体的内存对齐规则

结构体的内存对齐规则非常重要,可以提高访问内存的效率

  1. 看数据类型占几个字节,内存以0开始计算
  2. 如果当前位置不是数据类型所占字节数的倍数,就需要填充字节数,以实现该变量的存储位置序号是它所占字节数的整数倍
  3. 总共的字节数是最大字节数的整数倍
typedef struct student_s {
	int num;
	char name[10];
	char gender;//f:female m:male
}stu;
int main() {
	stu stu1 ;
	printf("%zd", sizeof(stu1));
	return 0;
}

首先,num占4个字节,序号是0—3;name[10]占10个字节,数据类型是char,首地址应该存放在1的倍数位置上,即随便放,序号是4—14;gender占一个字节数据类型是char,首地址应该存放在1的倍数位置上,即随便放;最后一共占用15个字节,其中最大数据类型为int,占4个字节,所以最后的字节数应该是4的倍数,取最小是16.
在这里插入图片描述

typedef struct Test {
	int num;
	char c;
	int n[5];
	double d;
}test;
int main() {
	test te;
	printf("%zd", sizeof(te));
	return 0;
}

int num;
占用4个字节。
由于它是结构体的第一个成员,它可以从任何地址开始(通常是0)。
char c;
占用1个字节。
紧接着num之后。由于char通常不需要对齐,它可以直接跟在num后面。
填充字节
在char c和接下来的int n[5]之间,编译器可能会插入填充字节以确保n[0](即数组的第一个元素)的地址是4的倍数。因为c位于地址4(num之后),所以编译器可能会插入3个填充字节(地址5-7)。
int n[5];
占用20个字节(5个int,每个4字节)。
从一个4字节对齐的地址开始(在这里是地址8)。
double d;
占用8个字节。
需要8字节对齐(在64位系统上通常是这样,32位系统可能只需要4字节对齐,但这里我们假设是64位系统或32位系统使用了更严格的对齐规则)。
n[4](数组的最后一个元素)结束于地址27。为了确保double d从8字节对齐的地址开始,编译器可能会在n[4]和d之间插入填充字节。从地址28到下一个8字节对齐的地址是32(因为32是8的倍数),所以编译器会插入4个填充字节(地址28-31)。
这样,结构体的内存布局如下:

int num;:地址0-3
char c;:地址4
填充字节:地址5-7
int n[5];:地址8-27
填充字节:地址28-31
double d;:地址32-39
总共为40字节
在这里插入图片描述


http://www.kler.cn/a/530049.html

相关文章:

  • SOME/IP--协议英文原文讲解3
  • 高阶C语言|深入理解字符串函数和内存函数
  • 一文了解DeepSeek
  • QT知识点复习
  • 一文讲解Java中的ArrayList和LinkedList
  • CAN总线数据采集与分析
  • RocketMQ中的NameServer主要数据结构
  • 网站快速收录:利用网站作者信息提升权重
  • ROS-SLAM
  • DeepSeek-R1模型1.5b、7b、8b、14b、32b、70b和671b有啥区别?
  • 25.2.2学习内容
  • C++11新特性之范围for循环
  • 使用 HTTP::Server::Simple 实现轻量级 HTTP 服务器
  • kamailio-kamctl monitor解释
  • 面经--C语言——sizeof和strlen,数组和链表,#include <>和 #include ““ #define 和typedef 内存对齐概述
  • Pluto固件编译笔记
  • C#,shell32 + 调用控制面板项(.Cpl)实现“新建快捷方式对话框”(全网首发)
  • Rust 函数使用详解
  • solidity高阶 -- Eth支付
  • 快速提升网站收录:利用网站用户反馈机制
  • Python函数基础
  • 系统思考—决策
  • Python 深拷贝与浅拷贝:数据复制的奥秘及回溯算法中的应用
  • deepseek+vscode自动化测试脚本生成
  • Error: Expected a mutable image
  • C++:抽象类习题