所以我正在慢慢地继续学习C。现在,我有一个任务,要从文件中读取数据并对其进行排序。
文件数据:
House naming 1 30 300
House naming 2 45 450
.......
House naming 10 5 120
因此,第一个值:House naming
,可以是任何名称,例如Empire state building
第二个值是:住所地址(我仅选择了integer
个值)
第三个值是:建筑物的年龄
第四个值是:千瓦时/年
程序必须从文件中获取数据->打印出来->排序(如何?见下文)->再次打印出来,进行排序。
排序:
这里是代码:
#include <stdio.h>
#include <stdlib.h>
#include "input.h"
int main(void) {
int kwh;
int age;
char building[SIZE];
int addr;
char buff[SIZE];
FILE *fi;
// opening the files and checking if it succeeded
fi = fopen(F_INPUT, "r");
if (fi == NULL) {
printf("Error opening input file \"%s\"", F_INPUT);
exit(EXIT_INPUT_FAIL);
}
while (fgets(buff, sizeof(buff), fi) != NULL) {
sscanf(buff, "%s %d %d %d", building, &addr,&age,&kwh);
if (kwh < 200) {
puts(buff);
printf("Sustainable\n");
} else
if (kwh < 300 && age < 40) {
puts(buff);
printf("Needs renovation\n");
} else
if (kwh > 300 && age > 40) {
puts(buff);
printf("IN DEMOLITION LIST\n");
}
}
/* close the files when they're not needed anymore */
fclose(fi);
return 0;
}
我已经结合了一些步骤,使其变得更容易一些,读取数据->输出已经标记为1)可持续,2)需要翻新,3)准备拆除。
问题出在while
循环中的某处,我认为它在sscanf
函数中。按照我的逻辑,如果我没有记错的话,它必须使用逻辑(请看sscanf
和输入文件)从文件中读取字符串:char value
,integer
,integer
,integer
。程序读取文件,输出数据,但将所有建筑物标记为sustainable
。
您建议更仔细阅读的内容或为读取多个字符串而更好地选择的逻辑。
输出:
House naming 1 30 300
Sustainable
House naming 2 45 450
Sustainable
........
House naming 10 5 120
Sustainable
[OP]完成后,通过fgets()
从文件中将line读取到string是很好的第一步。
“房屋名称”可以包含数字吗?像“ Stdio 54”?是的,它可以包含数字,不能包含数字。如果我是对的,那么任务对命名没有任何帮助。
下一部分很棘手,因为房屋名称与后面的3个整数之间没有唯一的分隔符。
一种方法是找到3个尾随的整数,然后将其余的开始文本作为房屋名称。
while (fgets(buff, sizeof(buff), fi) != NULL) {
int address, age, power;
char *p = buff + strlen(buff); // start as buff end
p = reverse_scan_int(buff, p, &power);
p = reverse_scan_int(buff, p, &age);
p = reverse_scan_int(buff, p, &address);
if (p) {
*p = '\0';
trim(buff); // remove leading trailing white-space
printf("house_name:'%s', address:%d age:%d power:%d\n", buff, address,
age, power);
} else {
printf("Failed to parse '%s'\n", buff);
}
}
现在我们只需要reverse_scan_int()
。示例未经测试的代码提示:
#include <ctype.h>
#include <stdbool.h>
char *reverse_scan_int(const char *begin, char *one_past, int *i) {
if (one_past == NULL) {
return NULL;
}
// is...() functions work best with unsigned char
unsigned char *p = (unsigned char *) one_past;
// Skip trailing whitespace;
while (p > begin && isspace(p[-1])) {
p--;
}
// Skip digits;
bool digit_found = false;
while (p > begin && isdigit(p[-1])) {
p--;
digit_found = true;
}
if (!digit_found)
return NULL;
if (p > begin && (p[-1] == '-' || p[-1] == '+')) {
p--;
}
*i = atoi(p); // More roubust code would use `strtol()`, leave for OP.
return (char *) p;
}
[trim a string包括this one的方法很多。
您的问题很难用sscanf()
解决,因为房屋名称和3个数字字段之间没有明确的分隔符。 %s
是不合适的:它解析一个单词。在您的程序中,sscanf()
实际上无法转换数字并为所有行返回1,从而在您比较实际未初始化的数值时导致未定义的行为。
这里是使用%[
转换规范的修改版本:
#include <stdio.h>
#include <stdlib.h>
#define F_INPUT "input.txt"
#define EXIT_INPUT_FAIL 1
int main(void) {
char buff[256];
char building[100];
int addr, age, kwh;
FILE *fi;
// opening the files and checking if it succeeded
fi = fopen(F_INPUT, "r");
if (fi == NULL) {
printf("Error opening input file \"%s\"", F_INPUT);
exit(EXIT_INPUT_FAIL);
}
while (fgets(buff, sizeof(buff), fi) != NULL) {
/* parse the building name upto and excluding any digit,
then accept 3 integral numbers for the address, age and power */
if (sscanf(buff, "%99[^0-9]%d%d%d", building, &addr, &age, &kwh) != 4) {
printf("parsing error: %s", buff);
continue;
}
if (kwh < 200) {
puts(buff);
printf("Sustainable\n");
} else
if (kwh < 300 && age < 40) {
puts(buff);
printf("Needs renovation\n");
} else
if (kwh > 300 && age > 40) {
puts(buff);
printf("IN DEMOLITION LIST\n");
}
// allocate structure with building details and append it to the list or array of buildings
}
/* close the files when they're not needed anymore */
fclose(fi);
// sort the list or array and print it
// free the list or array
return 0;
}