test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
int main(int argc, char const *argv[])
{
char *buf = NULL;
int flen = 0;
int min = INT_MAX;
int max = INT_MIN;
int ret = 0;
FILE *fp = fopen("nums.txt", "r");
if(fp == NULL){
printf("Failed to open file\n");
exit(0);
}
fseek(fp, 0, SEEK_END);
flen = ftell(fp);
buf = malloc(flen+1);
buf[flen] = '\0';
if(buf == NULL)
{
printf("No memory\n");
fclose(fp);
exit(0);
}
fseek(fp,0L,SEEK_SET);
while(fgets(buf, flen+1, fp) != NULL)
{
if(buf[0] == '\n')
{
printf("empty line\n");
free(buf);
fclose(fp);
exit(0);
}
char *temp = strtok(buf, " ");
while(temp){
int value = atoi(temp);
min = min > value ? value : min;
max = max < value ? value : max;
temp = strtok(NULL, " ");
}
}
free(buf);
fclose(fp);
ret = max - min;
printf("ret is %d\n", ret);
return ret;
}
以上代码是从一个txt文件中读取第一行,并返回这一行数字的范围值。
这段代码 函数功能堆砌在一起,函数功能不单一,可阅读性差。
资源管理不清晰(文件打开与关闭、内存分配与释放)。
那么我分成两个文件:
range.h
#ifndef _RANGE_H_
#define _RANGE_H_
#ifdef __cplusplus
extern "C" {
#endif
int range(FILE *fp);
#ifdef __cplusplus
}
#endif
#endif
range.c
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <stdlib.h>
int range(FILE *fp){
int min = INT_MAX;
int max = INT_MIN;
fseek(fp, 0, SEEK_END);
int flen = ftell(fp);
char *buf = malloc(flen+1);
buf[flen] = '\0';
fseek(fp, 0, SEEK_SET);
while((fgets(buf, flen, fp)) != NULL){
if(buf[0] == '\r'){
printf("empty line\n");
free(buf);
fclose(fp);
exit(0);
}
char *temp = strtok(buf," ");
while(temp != NULL){
int value = atoi(temp);
min = min > value ? value : min;
max = max < value ? value : max;
temp = strtok(NULL," ");
}
}
return max - min;
}
range_test.c
#include <stdio.h>
#include <stdlib.h>
#include "range.h"
int main(int argc, char const *argv[])
{
FILE *fp = fopen("nums.txt", "r");
if(fp == NULL){
printf("Failed to open file\n");
exit(0);
}
int ret = range(fp);
printf("ret is %d\n", ret);
fclose(fp);
return 0;
}
这样子,在main 函数里,打开文件 ---- 获取取值范围 ---- 关闭文件。
看起来很清晰,但是在range.c有不得不写的释放资源与关闭文件的地方。
因为在获取取值范围时,需要分配内存,内存一旦分配失败,必须释放内存,同时还要关闭文件,不然会造成内存泄漏。
撇开以上的问题不说,还有一个问题 ---- 在main函数里应该只有一个语句才合适,那就是 range("nums.txt");
至于怎么去打开、关闭文件,怎么分配、释放内存,应该写出阅读性更好的代码。
那么像以下这样子:
range.h
#ifndef _RANGE_H_
#define _RANGE_H_
#ifdef __cplusplus
extern "C" {
#endif
int range(const char* pFname);
#ifdef __cplusplus
}
#endif
#endif
range.c
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <stdlib.h>
#include "file_reader.h"
#include "range.h"
int range_processor(FILE *fp){
int min = INT_MAX;
int max = INT_MIN;
fseek(fp, 0, SEEK_END);
int flen = ftell(fp);
char *buf = malloc(flen+1);
buf[flen] = '\0';
fseek(fp, 0, SEEK_SET);
while((fgets(buf, flen, fp)) != NULL){
if(buf[0] == '\r'){
printf("empty line\n");
free(buf);
fclose(fp);
exit(0);
}
char *temp = strtok(buf," ");
while(temp != NULL){
int value = atoi(temp);
min = min > value ? value : min;
max = max < value ? value : max;
temp = strtok(NULL," ");
}
}
return max - min;
}
int range(const char* pFname){
return read_file(pFname, range_processor);
}
file_reader.h
#ifndef _FILE_READER_H_
#define _FILE_READER_H_
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
int read_file(const char *pFname, int (* const processor)(FILE *fp));
#ifdef __cplusplus
}
#endif
#endif
file_reader.c
#include <stdio.h>
#include "file_reader.h"
int read_file(const char *pFname, int (* const processor)(FILE *fp)){
FILE *fp = fopen(pFname, "r");
if(fp == NULL){
return -1;
}
int ret = processor(fp);
fclose(fp);
return ret;
}
range_test.c
#include <stdio.h>
#include <stdlib.h>
#include "range.h"
int main(int argc, char const *argv[])
{
int ret = range("nums.txt");
printf("ret is %d\n", ret);
return 0;
}
如上: 代码的可阅读性明显变强了。
应用程序main —— 从nums.txt 获取一行数值的范围值。
range.c —— 从打开的文件中获取一行数值的范围值。、
file_reader.c —— 文件的打开、操作 以及 关闭。
但是range.c中仍然存在文件打开、关闭 以及 内存分配、释放的代码。
文件的打开、关闭 以及 内存的分配、释放应该一一对应,不然遗忘一两处将造成内存泄漏。
所以还要继续优化这个代码。