exercise25

1. 研究
sscanf
sprintf
面向控制台标准输入输出的scanf printf
面向字符串的输入输出函数sscanf sprintf
面向文件的流的输入输出函数fscanf fprintf
sprintf函数原型
 int sprintf(char *str,const char *format,...)
 作用:格式化字符串
 1、将数字变量转化为字符串
     sprintf(str, "%d", 12345); //->"12345"
 2、得到整形变量的8进制和16进制字符串
    sprintf(str,"0%o",12345);
    sprintf(str,"0x%X",12345);
 3、连接多个字符串
    sprintf(str,"%s %s",s1,s2);
sscanf函数原型
 int sscanf(const char *str,const char *format,...)
 作用:将参数str的字符串根据参数format字符串来转换并格式化数据,转换后的结果存于对应的参数内。
 1、根据格式从字符串中提取数据。如提取出整数、浮点数和字符串等。
 2、取指定长度的字符串
 3、取到指定字符为止的字符串
 4、取仅包含指定字符集的字符串
 5、取到指定字符集为止的字符串
     const char *str = "http://www.baidu.com:1234";
     sscanf(str,"%[^:]://%[^:]:%[1-9]",str1,str2,str3);
 1、-: 表示范围,如:%[1-9]表示只读取1-9这几个数字 %[a-z]表示只读取a-z小写字母,类似地 %[A-Z]只读取大写字母
 2、^: 表示不取,如:%[^1]表示读取除'1'以外的所有字符 %[^/]表示除/以外的所有字符
 3、,: 范围可以用","相连接 如%[1-9,a-z]表示同时取1-9数字和a-z小写字母
2.研究
fread
fwrite  专门处理二进制
fread函数原型
 size_t fread(void *buffer, size_t size, size_t count, FILE *stream);
fwrite函数原型
 size_t fwrite(const void *buffer, size_t size, size_t count, FILE *stream);
fwrite参数
 1、要写入的数据地址,二进制无类型
 2、一次写入的基本单位
 3、写入几个基本单位
 4、从哪里写
fread参数
 1、要读的数据放在哪里,指向缓冲区
 2、读的基本单位
 3、要读多少个基本单位
 4、要从哪里读入

例如实现拷贝命令,支持文本和二进制,源文件以二进制方式打开

#include<stdio.h>
#include<stdlib.h>
#pragma warning(disable:4996)

int main(int argc, char *argv[])
{
	if (argc != 3){
		printf("Usage:%s src dst\n",argv[0]);
		return 1;
	}
	FILE *srcp = fopen(argv[1], "rb");
	if (!srcp){
		perror("fopen");
		goto end;
	}
	FILE *dstp = fopen(argv[2], "wb");
	if (!dstp){
		perror("fopen");
		goto end;
	}
	//获取文件大小
	fseek(srcp, 0, SEEK_END);
	long size = ftell(srcp);
	rewind(srcp);

	char *buf = (char *)malloc(size);
	if (!buf){
		perror("malloc");
		goto end;
	}
	fread(buf, 1, size, srcp);//直接获得整个文件大小,读入内存
	fwrite(buf, 1, size, dstp);//将整个文件写入硬盘

end:
	if (srcp){
		fclose(srcp);
		srcp = NULL;
	}
	if (dstp){
		fclose(dstp);
		dstp = NULL;
	}
	if (buf){
		free(buf);
		buf = NULL;
	}

}



### 解决 Exercise 4B 和 4C #### Exercise 4B: Counting Linked List Nodes **问题描述:** 给定一个链表的字符串表示,实现一个函数来计算链表中节点的数量。如果链表中存在环,检测环并避免重复计数环中的节点。 **约束条件:** - 对于50%的测试用例,链表中没有环。 - 对于50%的测试用例,链表中存在环。 **虚拟输入:** - 样例1:`1 -> 2 -> 3 -> 4 -> 5 -> NULL` - 样例2:`1 -> 2 -> 3 -> 4 -> 5 -> 2` **输出:** - 样例1:`5` - 样例2:`5` **解释:** - 样例1中,链表没有环,直接计数所有节点。 - 样例2中,链表包含5个唯一节点,即使有环,环中的节点也只计数一次。 **解决方案:** ```c #include "4B.h" typedef struct Node { int data; struct Node* next; } Node; int Count(Node* head) { if (head == NULL) return 0; Node* slow = head; Node* fast = head; Node* entry = head; bool hasCycle = false; // Detect cycle using Floyd's Tortoise and Hare algorithm while (fast != NULL && fast->next != NULL) { slow = slow->next; fast = fast->next->next; if (slow == fast) { hasCycle = true; break; } } if (!hasCycle) { // No cycle, count all nodes int count = 0; while (head != NULL) { count++; head = head->next; } return count; } else { // Cycle detected, find the entry point of the cycle while (entry != slow) { entry = entry->next; slow = slow->next; } // Count unique nodes in the cycle int cycleCount = 1; slow = slow->next; while (slow != entry) { cycleCount++; slow = slow->next; } // Count nodes before the cycle int preCycleCount = 0; Node* temp = head; while (temp != entry) { preCycleCount++; temp = temp->next; } return preCycleCount + cycleCount; } } ``` #### Exercise 4C: Pixel Frequency **问题描述:** 在数字成像中,图像由称为像素的小单位组成。每个像素包含颜色或亮度信息。给定一个文本文件,文件中的每个像素由两个十六进制数字表示。读取文件中的像素数据,统计每个像素值的频率,并将出现频率最高的像素值及其频率输出到另一个文件中。如果有多个像素值出现相同的最高频率,输出最小的那个像素值。 **约束条件:** - 图像的宽度和高度在1到256之间。 - 像素值范围从00到FF。 **输入:** - 输入文件名,文件内容为h行,每行包含w个空格分隔的两位十六进制数。 **输出:** - 将出现频率最高的像素值及其频率输出到文件`output.txt`中。如果有多个像素值出现相同的最高频率,输出最小的那个像素值。 **样例输入1:** - 文件名:`image0.txt` - 文件内容: ``` 77C0AA6A307134EAFBF9 86E6CDB3887DC9B8E711 12157D28AA6AEE018E73 5C0533066F6377A44D72 9DD3596B86E1E84F99CF 61ACE5DED48F48C390D7 36ECDC69F24CCC69F019 DB8DEC34F87216E0C2AF B0235B950130244AF3B4 2129A0FD9292495EFB39 ``` **样例输出1:** - `output.txt`内容: ``` 01 2 ``` **样例输入2:** - 文件名:`image1.txt` - 文件内容: ``` 53AABF9E7A025A432C371B784DFF5C6ED836E4AC 06E37DCAE55833E1DC66D62F1195CE8B9828CEC4 5FE93CACE9981AC1CEFE6DD5E1EB9FC643D2A71F 397E4F4A131DD5AB45A36FA48DAB5176446B3712 6AA4E74B8F8712D259B9F2923741DC4B5EB1F6A3 556647E211985855048F686E334FB9C3D6CB9530 8587C2BCC89F072650FEC9A564118775A9DFCBAD 6E331BA282D56559A0FA8925824BE24AEAE9713B E73AE04B4B68C1F5478CA2B6BFBE584193BD9A33 B72359396F3B845924F5940C2F75577BDD187024 A412DA63D032A563EF3F97A763F0E0D22B642B4F 59C05B8935B30412CB7436708611D3574378BA33 B851DA1B41BAED6C1F18BC78D817010DCA051F96 7956060067D957AA5211DD0A63B725A472121191 2ACD0903E40B10AF1030458A864B8AED24E19776 F27580552CA5FA9EB70B2FE2D839E5BC44F56B54 25B0DEABFB6898204930963CA51791D1BC8B7074 969F566ED83B2B1C30967156474F0142B89A6201 CAF93D6F10CF40CC5AB040F150965F28D18A4502 21B658680559AABDF30DBFBD06FC2C16CB6DE226 ``` **样例输出2:** - `output.txt`内容: ``` 01 2 11 6 ``` **解决方案:** ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_PIXEL_VALUE 256 int main() { char filename[20]; scanf("%s", filename); FILE *inputFile = fopen(filename, "r"); if (inputFile == NULL) { perror("Failed to open input file"); return 1; } int frequency[MAX_PIXEL_VALUE] = {0}; char buffer[1024]; while (fgets(buffer, sizeof(buffer), inputFile)) { char *token = strtok(buffer, " "); while (token != NULL) { int pixel = (int)strtol(token, NULL, 16); frequency[pixel]++; token = strtok(NULL, " "); } } fclose(inputFile); int maxFrequency = 0; int mostFrequentPixel = -1; for (int i = 0; i < MAX_PIXEL_VALUE; i++) { if (frequency[i] > maxFrequency || (frequency[i] == maxFrequency && i < mostFrequentPixel)) { maxFrequency = frequency[i]; mostFrequentPixel = i; } } FILE *outputFile = fopen("output.txt", "a"); if (outputFile == NULL) { perror("Failed to open output file"); return 1; } fprintf(outputFile, "%02X %d\n", mostFrequentPixel, maxFrequency); fclose(outputFile); return 0; } ``` ### 总结 - **Exercise 4B**:使用Floyd的乌龟和兔子算法检测链表中的环,并计算链表中唯一节点的数量。 - **Exercise 4C**:读取文件中的像素数据,统计每个像素值的频率,并将出现频率最高的像素值及其频率输出到另一个文件中。如果有多个像素值出现相同的最高频率,输出最小的那个像素值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值