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

【C语言】第七期——字符数组、字符串、类型转换

目录

1 定义初始化字符数组

2 用字符数组来存储字符串

3 strlen 计算字符串有效长度

4 sprintf 字符串格式化函数

函数原型

参数说明

返回值

功能描述

示例代码 

5 snprintf 防溢出格式化函数

函数原型

参数说明

返回值

示例代码

内存分配

6 类型转换

6.1 整数类型转换成字符串

6.2 字符串转换成整数类型(atoi函数)

6.3 整数类型之间的相互转换


在软件开发中字符串的应用非常广泛,但是C语言却没有字符串类型,为了解决这个问题,我们可以使用字符数组来存储字符串

1 定义初始化字符数组

字符数组的定义和普通数组一样,通过char关键字可以定义字符数组

方法1:

 char chs1[6] = {'i', 't', 'y', 'i', 'n', 'g'};    

方法2:

char chs2[] = {'l', 'i', 's', 'i'};

2 用字符数组来存储字符串

C语言中没有专门的字符串类型,通常使用字符数组来存储字符串。为了区分普通字符数组和字符串,C 语言规定以字符“\0“作为字符串的结束标志,例如:

//字符串
char chs1[] = {'i', 't', 'y', 'i', 'n', 'g','\0'};

//普通字符数组
char chs1[] = {'i', 't', 'y', 'i', 'n', 'g'};

除了以上初始化方式,也可以采用字符串对字符数组进行初始化,例如:

char c[]="user_a001"

使用字符串方式进行赋值时,系统会自动在字符串末尾添加“\0"

实例:

定义一个字符串并输出 

#include <stdio.h>
int main()
{
	char chs1[] = { 'i', 't', 'y', 'i', 'n', 'g', '\0' };
	char chs2[] = "itying";
	printf("字符\" % s \"的长度:%d\n", chs1, sizeof(chs1));
	printf("字符\" % s \"的长度:%d", chs2, sizeof(chs2));
	return 0;
}

 输出结果:

字符" itying "的长度:7
字符" itying "的长度:7

由于一个字符占用1个字节,所以可以通过字符串总长度/单个字符的长度求出总字符数

如下:

#include <stdio.h>
int main()
{
	char chs1[] = { 'i', 't', 'y', 'i', 'n', 'g', '\0' };
	char chs2[] = "itying";
	printf("字符\" % s \"的长度:%d\n", chs1, sizeof(chs1) / sizeof(chs1[0]));
	printf("字符\" % s \"的长度:%d\n", chs2, sizeof(chs2) / sizeof(chs2[0]));
	return 0;
}

注意:通过此方法得到的长度为实际字符串长度+1,因为末尾的"/0"也算,而下文的strlen函数计算的长度为字符串真实长度 


3 strlen 计算字符串有效长度

C语言中通过strlen 可以计算字符串的有效长度

strlen 函数在 "<string.h>"标准库里面,使用前需要先引入库文件

#include <stdio.h>
#include <string.h>
int main()
{
	char chs1[] = { 'i', 't', 'y', 'i', 'n', 'g', '\0' };
	char chs2[] = "itying.com";
	int length1 = strlen(chs1);
	int length2 = strlen(chs2);
	printf("%d\n", length1);
	printf("%d\n", length2);
	return 0;
}

输出结果:

6

10


4 sprintf 字符串格式化函数

sprintf 是 C 语言中的一个函数,用于将格式化的文本写入到指定的缓冲区中,该函数使用格式化字符串作为输入参数,并在输出时自动添加所需的分隔符和换行符等

函数原型

int sprintf(char *str, const char *format, ...);

参数说明

  • str:指向用于存储格式化后字符串的字符数组的指针。这个数组必须足够大,以容纳格式化后的字符串,包括字符串结束符 '\0'
  • format:这是一个格式化字符串,它指定了输出的格式。格式化字符串可以包含普通字符和格式说明符,格式说明符以 % 开头,用于指定后续参数的输出格式
  • ...:可变参数列表,这些参数将按照 format 字符串中的格式说明符进行格式化

返回值

在未发生重大错误(如传入 NULL 指针作为目标缓冲区)的前提下,无论写入内容是否超出目标字符数组的大小,sprintf 函数都会返回按照格式化规则将所有参数转换为字符串后拼接起来的总字符数量(不包括字符串结束符 '\0')

功能描述

sprintf 函数的主要功能是将格式化的数据写入到指定的字符数组中,而不是像 printf 函数那样直接输出到标准输出设备(如屏幕)

这使得它在需要将格式化数据存储到字符串中时非常有用,例如在构建动态字符串、生成日志信息等场景中经常会用到 

示例代码 

#include <stdio.h>

int main() {
    char str[100];
    int num = 123;
    float f = 3.14;
    char ch = 'A';

    // 使用sprintf将不同类型的数据格式化为字符串
    sprintf(str, "整数: %d, 浮点数: %.2f, 字符: %c", num, f, ch);

    // 输出格式化后的字符串
    printf("格式化后的字符串: %s\n", str);

    return 0;
}

运行结果:

格式化后的字符串: 整数: 123, 浮点数: 3.14, 字符: A

❗注意:

缓冲区溢出风险:由于 sprintf 函数不会检查目标字符数组的大小,因此如果格式化后的字符串长度超过了数组的大小,就会发生缓冲区溢出,可能导致程序崩溃或产生安全漏洞

为了避免这种情况,可以使用 snprintf 函数,它可以指定最大写入的字符数


5 snprintf 防溢出格式化函数

snprintf 是 C 语言标准库中的一个函数,同样声明在 <stdio.h> 头文件中。它是 sprintf 的安全版本,主要用于解决 sprintf 可能存在的缓冲区溢出问题

函数原型

int snprintf(char *str, size_t size, const char *format, ...);

参数说明

  • str:指向用于存储格式化后字符串的字符数组的指针。格式化后的字符串将被写入该数组
  • size:指定了 str 数组的最大可写入字节数,包含字符串结束符 '\0',这是 snprintf 与 sprintf 的关键区别,snprintf 会根据这个参数来防止缓冲区溢出
  • format:格式化字符串,用于指定输出的格式。它可以包含普通字符和格式说明符,格式说明符以  % 开头,用于指定后续可变参数的输出格式
  • ...:可变参数列表,这些参数会按照 format 字符串中的格式说明符进行格式化

返回值

  • 如果格式化后的字符串长度小于 size,snprintf 会将整个格式化字符串(包括字符串结束符 '\0')写入 str 数组,并返回实际写入的字符数(不包括字符串结束符)
  • 如果格式化后的字符串长度大于或等于 size,snprintf 会将 size - 1 个字符写入 str 数组,并在末尾添加字符串结束符 '\0',此时返回值为格式化字符串原本应有的长度(不包括字符串结束符)。这个返回值可以用于判断是否发生了截断

示例代码

#include <stdio.h>

int main() {
    char str[20];
    int num = 123456;
    int result;

    // 使用 snprintf 进行格式化
    result = snprintf(str, sizeof(str), "数字是: %d", num);

    if (result >= sizeof(str)) {
        printf("发生截断,格式化字符串原本长度为 %d 字节。\n", result);
    } else {
        printf("格式化后的字符串为: %s\n", str);
    }

    return 0;
}

代码解释

  • 定义字符数组和变量:定义了一个长度为 20 的字符数组 str,用于存储格式化后的字符串,同时定义了一个整数 num 和一个用于存储 snprintf 返回值的变量 result
  • 调用 snprintf 函数:将整数 num 按照指定格式组合成字符串,并尝试写入 str 数组。sizeof(str) 用于指定 str 数组的最大可写入字节数
  • 根据返回值判断是否发生截断:如果 result 大于或等于 sizeof(str),说明发生了截断;否则,正常输出格式化后的字符串

内存分配

如果需要存储完整的格式化字符串,可以根据 snprintf 的返回值动态分配足够的内存。例如:

注意:malloc、free函数在第十三期讲解,此处可先跳过

#include <stdio.h>
#include <stdlib.h>

int main() {
    int num = 123456;
    int len;
    char *str;

    // 先计算格式化字符串的长度
    len = snprintf(NULL, 0, "数字是: %d", num);
    // 动态分配足够的内存
    str = (char *)malloc((len + 1) * sizeof(char));
    if (str != NULL) {
        // 将格式化后的字符串写入分配的内存
        snprintf(str, len + 1, "数字是: %d", num);
        printf("格式化后的字符串为: %s\n", str);
        // 释放分配的内存
        free(str);
    }

    return 0;
}

在这个示例中,首先使用 snprintf(NULL, 0, ...) 计算格式化字符串的长度,然后根据这个长度动态分配足够的内存,最后再次调用 snprintf 将格式化后的字符串写入分配的内存中,使用完内存后,记得使用 free 函数释放内存,避免内存泄漏


6 类型转换

6.1 整数类型转换成字符串

使用sprintf

#include <stdio.h>
int main(void)
{
	char buffer_int[10] = { 0 };
	char buffer_float[10] = { 0 };
	sprintf(buffer_int, "%d", 100);
	sprintf(buffer_float, "%f", 3.14);
	printf("%s\n", buffer_int);
	printf("%s\n", buffer_float);
	return 0;
}

6.2 字符串转换成整数类型(atoi函数)

函数原型:

int atoi (const char * str);

头文件:

 #include<stdlib.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
	char s1[] = "123";
	int num1 = atoi(s1); // 将字符串 "123" 转化为整数 123
	printf("%d\n", num1);

	char s2[] = "2.123";
	double num2 = atof(s2); // 将字符串 "2.123" 转化为doblue 2.123
	printf("%lf\n", num2);
	return 0;
}

其他:字符串转成双精度浮点型用atof函数

#include <stdio.h>
#include <stdlib.h>

int main() {
    char str[] = "3.14";
    double num = atof(str);  // 将字符串 "3.14" 转换为双精度浮点数 3.14
    printf("Converted number: %lf\n", num);
    return 0;
}

6.3 整数类型之间的相互转换

显示转换(强制转化): 

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
	int a = 123;
	double b = (double)a;
	printf("b=%lf\n", b);

	float c = 123.4f;
	int d = (int)c;
	printf("d=%d\n", d);

	return 0;
}

隐式转换:

#include <stdio.h>

int main() {
    int a;
    float b = 3.14;
    a = b;  // 浮点数b隐式转换为整数类型赋给a
    printf("a = %d\n", a);
    return 0;
}

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

相关文章:

  • 3D Gaussian Splatting(3DGS)的核心原理
  • ubuntu中打包与压缩命令详解
  • 【js逆向入门】图灵爬虫练习平台 第七题
  • 【大模型】蓝耘智算平台部署DeepSeek-R1大模型使用详解
  • Linux-C-函数栈-SP寄存器
  • vim 多个关键字高亮插件介绍
  • 设计模式-adapter模式(适配器)
  • 一文讲解Redis中的集群数据分区相关问题
  • java后端开发day19--学生管理系统升级
  • [MDM 2024]Spatial-Temporal Large Language Model for Traffic Prediction
  • Linux命令大全完整版(02)
  • 【漫话机器学习系列】101.特征选择法之Lasso(Lasso For Feature Selection)
  • 【力扣Hot 100】堆
  • 【uni-app】对齐胶囊容器组件
  • Future和FutureTask实现类详解以及使用。
  • 阿里云CDN转https个人测试证书过期更换
  • CentOS 7.9 解决 python3 报错 ModuleNotFoundError: No module named ‘_ssl‘ 的问题
  • Gradio全解11——使用transformers.agents构建Gradio UI(6)
  • 字节跳动2面、美团2面Java面试真题总结
  • 跟着 Lua 5.1 官方参考文档学习 Lua (7)