C语言——printf打印字符串(关于数据在内存中存储格式的体现)

int 占4个字节, 这里输入的8位16进制数每相邻两位数代表一个字节。如:44,43,42,41

int b = 0x41424344;
printf("string: %s\n", &b);

注意:%s打印字符串的时候,必须要求printf所传参数必须是一个内存的地址,且一定有一个0(代表字符串结尾标志‘\0’)做为截至条件。而这里并没有以0结尾所以,这两行代码除了输出各个字节的ASCII码对应的字符以外还会输出这片存储区域后面的的内存所存储的数据(是不可预见的)知道遇到0为止。
我的电脑是小端存储系统,所以输出结果为:
这里写图片描述

下面来看看这些代码:

	int b = 0x41424344;
	int b1 = 0x41424300;
	int b2 = 0x00414243;
	int b3 = 0x41004243;

	printf("string: %s\n", &b);
	printf("string: %s\n", &b1);
	printf("string: %s\n", &b2);
	printf("string: %s\n", &b3);

要记住,%s输出字符串的时候遇到0或‘\0’,就会被截断,只输出0或‘\0’前面的字符,所以,这里b1的最低位为0,则b1没有字符可以输出。b2, b3同理。
如图:这里写图片描述

同样的道理,如下代码:

char arr[4] = {0x41, 'X', '0', 'C'};
		printf("string: %s\n", arr);

由于arr[4]数组只有4个元素,由于赋值的时候就给四个元素都赋了值,数组中就没有元素再来存储结束符‘\0’,所以,同样输出完数组后会有乱码产生。
如图:
这里写图片描述

最有意思的是这两行代码:

int arr[] = {0x41, 'm', 'X', '0', 'C', '\0'};
		printf("string: %s\n", arr);

看上去,在数组的末位手动添加了字符串结尾标志符,以为正常输出:AmX0C
其实不然。
这里写图片描述
这里我给出了,前两个数据在内存中存储的格式,由于int占4个字节,所以0x41只是占用了第一个元素4个字节的第一个字节,所以后面的三个字节由系统自动补0,所以编译器在编译的时候,任然是碰到0就截止。就导致,最终程序只能输出,0x41所对应的字符 ‘A’.
如图:
这里写图片描述

下面提供两种可以正确输出的方式:

	char arr[5] = {0x41, 'm', 'X', '0'};
	char arr2[] = "AX0C";
	printf("string: %s\n", arr);
	printf("string: %s\n", arr2);

这里写图片描述

### 如何在C语言中提取字符串中的数字或子串 #### 提取字符串中的数字 为了从字符串中提取所有的数字,在C语言中有多种方法可以实现。一种常见的做法是遍历整个字符串并检测其中的数字字符,将其转换为整数形式存储下来。这种方法可以通过简单的循环结构完成[^3]。 以下是基于此逻辑的一个简单示例: ```c #include <stdio.h> #include <ctype.h> void extractNumbers(const char *str) { int num = 0; int hasNum = 0; while (*str) { if (isdigit(*str)) { // 判断当前字符是否为数字 num = num * 10 + (*str - '0'); // 将字符转成对应的数值 hasNum = 1; // 表明已经找到至少一个数字 } else if (hasNum) { // 如果前面有数字,则打印出来 printf("%d\n", num); num = 0; // 清零以便处理下一个数字 hasNum = 0; // 标志重置 } str++; // 移动到下一位字符 } if (hasNum) { // 处理最后一个可能存在的数字 printf("%d\n", num); } } int main() { const char *inputStr = "abc123def456ghi789"; extractNumbers(inputStr); // 调用函数提取数字 return 0; } ``` 上述代码通过`isdigit()`函数判断字符是否属于数字范围,并逐步构建完整的数字值。当遇到非数字字符时,如果之前存在有效数字则立即输出该数字。 #### 提取字符串中的子串 对于提取字符串中的子串操作,通常需要定义起始位置以及结束条件(比如指定长度或者直到某个特殊字符为止)。下面展示了一个例子,它演示了如何利用指针技术复制一段目标区域内的内容作为新的独立子串[^1]。 ```c #include <stdio.h> #include <string.h> #include <stdlib.h> char* substring(const char* input, size_t startIdx, size_t length) { if (!input || strlen(input) <= startIdx) return NULL; char* result = malloc(length + 1); // 动态分配内存空间保存结果 strncpy(result, input + startIdx, length); // 按照索引和长度截取所需部分 result[length] = '\0'; // 确保新创建的字符串以null结尾 return result; } int main(){ const char original[]="hello world!"; char *sub=substring(original,6,strlen(original)-6); puts(sub); // 输出得到的子串"world!" free(sub); // 记得释放动态申请的空间 return 0; } ``` 在这个程序里,我们自定义了一个名为`substring`的功能模块用来生成任意起点与终点之间的片段副本。注意这里采用了手动管理资源的方式——即先调用`malloc`开辟必要的缓冲区大小再填充实际数据进去;最后别忘了适时销毁不再使用的对象以免造成泄漏问题发生。 另外还有一种更简便的方法就是借助于标准库里的格式化输入功能/sscanf来快速定位感兴趣的部分字段信息[^2]: ```c #include<stdio.h> int main(void){ char buffer[100]; float f; sscanf("pi is approximately %f",&f); printf("%.2f\n",f); return 0; } ``` 在这里面我们可以看到只要合理设置占位符就能轻松捕获匹配模式下的具体成分项啦!
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值