意想不到的 sprintf 函数【入门到进阶】

sprintf 功能的强大不会让你失望,接下来我们先入门sprintf函数

函数介绍

  • C 标准库
  • 描述:C 库函数 int sprintf(char str, const char format, …) 发送格式化输出到 str 所指向 的字符串。
  • 声明:int sprintf(char *str, const char *format, ...)

函数参数介绍

  • str – 这是指向一个字符数组的指针,该数组存储了 C 字符串。
  • format – 这是字符串,包含了要被写入到字符串 str 的文本

函数返回值

如果成功,则返回写入的字符总数,不包括字符串追加在字符串末尾的空字符。如果失败,则返回一个负数

函数使用

  • 将 %f 格式的数据写入到字符串中
#define _USE_MATH_DEFINES 1  //如果要使用里面的宏,需要定义_USE_MATH_DEFINES 
#include 
#include 

int main()
{
	char str[80];
	
	sprintf(str, "Pi 的值 = %f", M_PI);
	puts(str);

	return(0);
}

在这里插入图片描述

  • 字符串写入字符串中
#include 

int main()
{
	char dest[20];
	sprintf(dest, "Hello World!");
	puts(dest);
}

在这里插入图片描述

  • 多个格式的写入
#include 

int main()
{
	int num = 886;
	char str[] = "goodby";
	char dest[20];
	sprintf(dest, "%s is %d", str, num);
	puts(dest);
}

在这里插入图片描述

  • 观察函数的返回值
sprintf函数的返回值不包含目标字符串末尾自动添加的'\0'
#include 

int main()
{
	int num = 886;
	char str[] = "goodby";
	char dest[20];
	int len = sprintf(dest, "%s is %d", str, num);
	puts(dest);
	printf("len = %d\n", len);
}

在这里插入图片描述

函数入门终结训练

产生10个[0, 100)之间的随机数,并将他们打印到一个字符数组s中,以逗号分隔开,最后一个数字后面是换行。

#include 
#include 
#include 

int main()
{
	char dest[40];
	srand(time(NULL));  //置随机数种子
	int offset = 0;
	for (int i = 0; i < 9; i++)
	{
		offset +=sprintf(dest+ offset, "%d,", rand() % 100);
	}
	//最后一个数后面添加一个换行
	offset += sprintf(dest + offset, "%d\n", rand() % 100);
	int len = strlen(dest);
	for (int i = 0; i < len; i++)
	{
		printf("%c", dest[i]);
	}
}

在这里插入图片描述


sprintf函数进阶

spirntf第一个参数注意

注意当你想要在一个字符数组的某个位置开始时,那么第一个参数就要传对应位置的地址。

int main()
{
	char dest[40] = "I love ";
	char str[] = "this world!";
	//sprintf(dest + 7, "%s", str);
	sprintf(dest + 7, str);
	puts(dest);
	return 0;
}

在这里插入图片描述

1、格式化字符数组

int main()
{
	char a[100] = { 0 };
	sprintf(a, "你好,我是%s博主", "PiDan");
	printf("%s\n", a);
	return 0;
}

在这里插入图片描述

2. 字符串的拼接

int main()
{
	char dest[100];
	char str1[] = "Hello";
	char str2[] = "Word!";
	int len1 = sprintf(dest, "%s, % s", str1, str2);
	printf("%s\n%d", dest, len1);
	return 0;
}

在这里插入图片描述

3. 数字转换成字符串 -> sprintf

#include 

void IntToString(int num, char* str)
{
	sprintf(str, "%d", num);
	return str;
}

int main()
{
	int number1 = 123456;
	int number2 = -123456;
	char string[16] = { 0 };
	IntToString(number1, string);
	printf("数字:%d 转换后的字符串为:%s\n", number1, string);
	IntToString(number2, string);
	printf("数字:%d 转换后的字符串为:%s\n", number2, string);
	return 0;
}

在这里插入图片描述

3. 字符串转整数-> atoi

函数原型:int atoi(const char *nptr);//字符串转整数函数,nptr: 要转换的字符串

#include
#include 

int main()
{
	printf("字符串\"123456\"转换为数字:%d\n", atoi("123456"));
	printf("字符串\"-123456\"转换为数字:%d\n", atoi("-123456"));
	return 0;
}

在这里插入图片描述


sprintf缺陷

1、sprintf函数引起的缓冲区溢出
int main()
{
	char src[50] = "abcdefghijklmnopqrstuvwxyz";
	char buf[10] = "";
	int len = sprintf(buf, "%s", src);
	printf("src=%s\n", src);
	printf("len=%d\n", len);
	printf("buf=%s\n", buf);
	return 0;
}

现象&后果

程序运行时,用sprintf函数把字符数组src的内容往字符数组buf复制时会溢出,可能出现段错误(Segmentation fault)。
意想不到的 sprintf 函数【入门到进阶】_第1张图片

Bug分析

上述代码从一个字符数组src复制字符串到另外一个字符数组buf中,src的字符串长度为26,但buf的长度只有10,用sprintf函数进行复制的时候会把src的所有字符往buf里写,从而引起buf溢出。

正确的做法是在复制之前检查buf的长度是否足够,或者直接用更安全的snprintf函数代替sprintf。

正确代码

int main()
{
	char src[50] = "abcdefghijklmnopqrstuvwxyz";
	char buf[10] = "";
	int len = snprintf(buf, sizeof(buf), "%s", src);
	if (len > sizeof(buf) - 1)
	{
		printf("[Error] Source string length is %d. The buf size %d is not enough. Copy incomplete!\n", len, sizeof(buf));
	}
	else
	{
		printf("src=%s\n", src);
		printf("len=%d\n", len);
		printf("buf=%s\n", buf);
	}
	return 0;
}

利用sprintf函数的返回值提前做一个干预
在这里插入图片描述

你可能感兴趣的:(c语言,c语言)