我对C(以及本网站)有些新意,对我正在研究的项目有疑问。我坚持的部分是文件I / O的东西,因为我从来没有在我上一课中学到这一部分。因此,输入(.txt)文件如下所示:
REGISTERS
R5 11
R7 15
R21 4
MEMORY
4 12
12 92
[OTHER STUFF]
该文件为我们提供了任意的寄存器编号,然后是其内容(R0到31,省略了值为0的Regs)。下一节以类似的格式给出内存位置,然后再次显示内容。然后我可以处理更多的部分。
我的问题是:如何读取寄存器/存储器位置及其值?目前我有一个32位数组来存储内容,一个变量用于Reg数和值(例如:寄存器[regNumber] = regValue;),但我不知道如何在单词REGISTERS之后正确读取值。
我尝试了什么:
我做了一些环顾四周,我设法在一个只有一行的测试输入文件中读取:“R5 11”。为此我做了:
fscanf(file_ptr, "R%d %d", ®Number, ®Value);
我打印了变量regNumber,regValue,它们正确地给了我5和11.但是如何在REGISTERS之后的任意行数处执行此操作并停在MEMORY一词?
无论解决方案是什么,我都可以在MEMORY位置和值中读取相同的内容。
答案 0 :(得分:2)
您可以使用fgets()读取文本文件的整行,然后使用strcmp或strncmp读取" REGISTERS"和"记忆"字符串文字。
在" REGISTERS"之后,您的input.txt被格式化的方式具有相同的格式直到" MEMORY"以及" MEMORY"之后的所有内容。是相同的格式。也许以下类似的东西可行,尽管可能有更好的选择:
int main () {
FILE *fp;
char str[60];
int input_type = 0; //you can enum this for the input types you have
int line_num = 0;
/* opening file for reading */
fp = fopen("input.txt" , "r");
if(fp == NULL) {
perror("Error opening file");
return(-1);
}
while( fgets (str, 60, fp)!=NULL ) { // dont really need the != NULL compare here.
line_num++;
/* Parse the next line in the file */
if(strcmp(str,"MEMORY") == 0){
//the next lines will be formatted like memory input lines
input_type = 2; //This should be an enum or macro
continue;
}
if(strcmp(str,"REGISTERS") == 0){
//the next lines will be formatted like register input lines
input_type = 1;//Also should be enum or macro
continue;
}
switch(input_type){
case 0:
fprintf(stderr,"Failed to find REGISTER keyword%d\n",line_num);
break;
case 1:
sscanf(str, "R%d %d", ®Number, ®Value); //parse known string format
do_something(®Number, ®Value);
break;
case 2:
sscanf(str, "%d %d", &memNumber, &memValue); //parse known string format
do_something_else(&memNumber, &memValue);
break;
default:
fprintf(stderr,"Could not find input format at line %d\n",line_num);
break;
}
}
fclose(fp);
return(0);
}
答案 1 :(得分:2)
我不会在这里使用fscanf
,因为你不能向前看,看看下一个
行是REGISTERS
或MEMORY
或其他。从理论上讲,你可以检查一下
返回值为fscanf
但代码会很快变得非常混乱。
更好的解决方案是使用fgets
来获取整行。如果线是相等的
到REGISTERS\n
,然后你知道下一行是寄存器行等
解析本身可以使用sscanf
完成,这类似于fscanf
,而不是FILE*
从enum mode_t {
REGISTERS = 0,
MEMORY,
...,
INVALID
};
int parse_file(FILE *file_ptr, int *registers, int some_other_params)
{
if(file_ptr == NULL || registers == NULL)
return 0;
char line[1024];
enum mode_t mode = INVALID;
while(fgets(line, sizeof line, file_ptr))
{
if(strcmp(line, "REGISTERS\n") == 0)
{
mode = REGISTERS;
continue;
} else if(strcmp(line, "MEMORY\n") == 0) {
mode = MEMORY;
continue;
} // keep adding if(strcmp.... as needed)
if(mode == INVALID)
{
fprintf(stderr, "Invalid file format\n");
return 0; // or a better error handling
}
int ret;
switch(mode)
{
case REGISTERS:
ret = parse_registers(line, registers);
break;
case MEMORY:
ret = parse_memory(line, some_other_args);
break;
...
}
// evaluate ret and do error handling if necessary
}
return 1;
}
缓冲区读取,它从字符串中读取。
所以,我做了:
mode
使用parse_registers
作为解析状态,您可以确定您所在的部分
解析。然后你必须编写像parse_memory
和...这样的函数
int parse_registers(const char *line, int *registers)
{
if(line == NULL || registers == NULL)
return 0;
int regNumber, regValue;
if(sscanf("R%d %d", ®Number, ®Value) != 2)
{
fprintf(stderr, "Invalid format for REGISTER section\n");
return 0;
}
if(regNumber < 0 || regNumber > 31)
{
fprintf(stderr, "Invalid register number %d\n", regNumber);
return 0;
}
registers[regNumber] = regValue;
return 1;
}
用于对行进行真正的解析,例如:
parse_memory
现在,您可以实现parse_xxx
和其他{{1}}函数
该文件的其他部分。