【问题标题】:Using fscanf to store floats and strings into an array of structures in C使用 fscanf 将浮点数和字符串存储到 C 中的结构数组中
【发布时间】:2016-12-13 16:36:14
【问题描述】:

我正在处理的程序应该从预先存在的文本文件中提取数据,编辑数据,然后将其重写到新的文本文件中。我已经完成了大部分工作,但它不会将任何扫描的数据存储到我的阵列中。当我调用我的打印到文件功能(我相当肯定它可以正常工作)时,没有任何内容打印到新文件中。

整个代码文件相当长,所以我只包括其中的一部分。如果您需要任何澄清,请告诉我;任何建议或想法都会有很大帮助!提前谢谢!

它应该从中提取的文件具有默认格式

Name:\n\t Hours Worked: \n\tWeekly Pay: \n\tTaxes Paid: \n\tTake-home Wage:

代码

    // in main (already declared and initialized all variables
    printf("Please enter the name of the text file you'd like to read from: ");
    scanf(" %s",fileName);
    fp= (fopen(&fileName, "r+"));
    if (fp ==NULL)
    {
        printf("Unable to open %s", fileName);
        exit(1);
    }

    for(int i=0; i<10; i++){
        loadFromFile(&employeeInfo[i],fp);
    }
    fclose(fp);
    break;

int loadFromFile(struct Employee *employee,FILE *fp){
    static int employeeNumb;
    fscanf(fp, " %*[^:]: %s", employee->name);
    if ((*employee).name==feof(fp))
        printf("fscanf did not store properly");
    fscanf(fp," %*[^:]: %f", &employee->hoursWorked);
    fscanf(fp," %*[^$]$ %f", &employee->weeklyPay);
    fscanf(fp, " %*[^$]$ %f",  &employee->taxesPaid);
    fscanf(fp, " %*[^$]$ %*s");
    employeeNumb++;
    return employeeNumb;
}

编辑:添加了我的打印到文件功能

void saveToFile(struct Employee employee[], int employeeNumb){
FILE *fp;
char newFile[40];
printf("Please enter the name of the text file you'd like to create or overwrite: ");
scanf(" %s",newFile);
fp= fopen(newFile, "w+");//r+ if do NOT want to overwrite or a+ if append
if (fp ==NULL)
{
    printf("Unable to open %s", newFile);
    exit(1);
}
for(int i=0; i<employeeNumb; i++){
    printToFile(fp,&employee[i]);
}
fclose(fp);}

 void printToFile(FILE *fp,struct Employee *employee){
fprintf(fp, "\nName: %s", (*employee).name);
fprintf(fp,"\n\tHours Worked: %g", (*employee).hoursWorked);
fprintf(fp,"\n\tWeekly Wage: $%.2f", (*employee).weeklyPay);
fprintf(fp, "\n\tTaxes Paid: $%.2f", (*employee).taxesPaid);
fprintf(fp, "\n\tTake-home Wage: $%.2f", ((*employee).weeklyPay)-(*employee).taxesPaid);

}

编辑 2:添加结构定义

struct Employee {
char name[40];
float weeklyPay;
float hoursWorked;
float taxesPaid;};

【问题讨论】:

  • fopen(&amp;fileName, "r+") --> fopen(fileName, "r+")
  • fscanf(fp," %*[^:], %f", employee-&gt;weeklyPay);,例如,期望读取一个逗号(并且不会读取冒号或美元符号)......当你应该传递一个指针时,你正在传递一个 float到一个。
  • 另外,fscanf()%s 不会读取包含空格的字符串(只会读取第一个单词),所以如果你有例如。您的姓名字段中的名字和姓氏会出现问题。此外,您的读取代码预计每条记录恰好有四行/字段,因此希望输出中的最后一个字段不在您的输入文件中。
  • 考虑fscanf(fp, " %*[^:]: %s", employee-&gt;name);。当输入以':' 开头时会发生什么? --> employee-&gt;name 中没有保存任何内容,':' 没有被消耗。当输入位于文件末尾时会发生什么?以前的feof() 没有帮助。 employee-&gt;name 中没有保存任何内容,因此第 1 步 - 检查 fscanf() 的结果与预期的返回值(在这些情况下通常为 1)。
  • feof() 并不完全表示文件结束...它表示先前的读取失败是否是由文件结束(种类)引起的。您需要检查来自 fscanf() 的返回以查看它是否读取了字段...如果 fscanf() 返回 EOF,那么您可以使用 feof() 如果您想知道它是否到达文件末尾或点击一些其他错误。

标签: c arrays file struct scanf


【解决方案1】:

我试图将所有人聚集在一起。 我的testfile(你给的格式很难理解(更有可能:我太笨了,看不懂),相应调整即可)

Name: 6ZjQPZJniP
        Hours Worked: 35.0
        Weekly Wage: $12.0
        Taxes Paid: $65.0
Name: pOmMgjgPHD
        Hours Worked: 20.0
        Weekly Wage: $49.0
        Taxes Paid: $85.0
Name: TRTxUptiD2
        Hours Worked: 43.0
        Weekly Wage: $23.0
        Taxes Paid: $42.0
Name: q5mQ5Yy0QA
        Hours Worked: 22.0
        Weekly Wage: $97.0
        Taxes Paid: $67.0
Name: saiZAKNJSy
        Hours Worked: 59.0
        Weekly Wage: $99.0
        Taxes Paid: $70.0
Name: lh3ZnB81jI
        Hours Worked: 19.0
        Weekly Wage: $36.0
        Taxes Paid: $49.0
Name: H8mw8eckfB
        Hours Worked: 35.0
        Weekly Wage: $24.0
        Taxes Paid: $45.0
Name: t9E4sQnmlG
        Hours Worked: 64.0
        Weekly Wage: $14.0
        Taxes Paid: $63.0
Name: KggqJYULf5
        Hours Worked: 84.0
        Weekly Wage: $80.0
        Taxes Paid: $15.0
Name: Emov5IhBce
        Hours Worked: 24.0
        Weekly Wage: $35.0
        Taxes Paid: $74.0

(以换行符结尾!)

代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

    // ALL CHECKS OMMITTED!

typedef struct Employee {
  char name[40];
  float hoursWorked;
  float weeklyPay;
  float taxesPaid;
} Employee;
// all structs
void saveToFile(Employee ** employee, int employeeNumb);
// one struct
void printToFile(FILE * fp, Employee * employee);
// one struct
int loadFromFile(Employee * employee, FILE * fp);

static int employeeNumb;

void saveToFile(Employee ** employee, int employeeNumb)
{
  FILE *fp;
  char newFile[128];
  printf
      ("Please enter the name of the text file you'd like to create or overwrite: ");
  scanf(" %s", newFile);
  fp = fopen(newFile, "w+");    //r+ if do NOT want to overwrite or a+ if append
  if (fp == NULL) {
    printf("Unable to open %s", newFile);
    exit(1);
  }
  for (int i = 0; i < employeeNumb; i++) {
    printToFile(fp, employee[i]);
  }
  fclose(fp);
}

void printToFile(FILE * fp, Employee * employee)
{
  fprintf(fp, "\nName: %s", employee->name);
  fprintf(fp, "\n\tHours Worked: %f", employee->hoursWorked);
  fprintf(fp, "\n\tWeekly Wage: $%.2f", employee->weeklyPay);
  fprintf(fp, "\n\tTaxes Paid: $%.2f", employee->taxesPaid);
  fprintf(fp, "\n\tTake-home Wage: $%.2f",
      (employee->weeklyPay) - employee->taxesPaid);
}

int loadFromFile(Employee * employee, FILE * fp)
{
  if (feof(fp)){
    return employeeNumb;
  }
  // I just c&p'd the format. Works because the format is fixed
  // Keep it simple when you can!
  fscanf(fp, "Name: %s\n", employee->name);
  fscanf(fp, "\tHours Worked: %f\n", &employee->hoursWorked);
  fscanf(fp, "\tWeekly Wage: $%f\n", &employee->weeklyPay);
  fscanf(fp, "\tTaxes Paid: $%f\n", &employee->taxesPaid);
  employeeNumb++;
  return employeeNumb;
}

int main()
{
  char fileName[128];
  FILE *fp;
  // pointer to the pointers to the (10) Employee structs
  Employee **employeeInfo;
  int i;

  printf("Please enter the name of the text file you'd like to read from: ");
  scanf(" %s", fileName);
  fp = (fopen(fileName, "r"));
  if (fp == NULL) {
    fprintf(stderr, "Unable to open %s", fileName);
    exit(EXIT_FAILURE);
  }
  // we need enough memory to safe ten structs
  // at first allocate memory for 10 pointers (to the structs)
  employeeInfo = malloc(10 * sizeof(Employee*));
  for (i = 0; i < 10; i++) {
    // for each pointer allocate memory for one struct
    employeeInfo[i] = malloc(sizeof(Employee));
  }
  for (i = 0; i < 10; i++) {
    // loadFromFile() takes one struct
    loadFromFile(employeeInfo[i], fp);
  }

  // clean up
  fclose(fp);
  // saveToFile() takes all structs
  saveToFile(employeeInfo, employeeNumb);
  // free memory of the individual structs
  for (i = 0; i < 10; i++) {
    free(employeeInfo[i]);
  }
  // free the memory holding the 10 pointers
  free(employeeInfo);
  // say Bye!
  exit(EXIT_SUCCESS);
}

不完美,但你应该有一些东西可以建立。

【讨论】:

  • 哇,非常感谢!对不起,我再清楚不过了;我对编程很陌生。对于为什么要使用指向结构数组的指针,我有点困惑。不过谢谢!对我肯定有很大的帮助!
  • 你想要指针,你对-&gt; 的使用表明了这一点。我只是稍微清理了一下,并在整个过程中使用了指针。唯一的缺点是你必须自己处理内存。如果您需要更多内存和/或不知道提前多少,这也是您的做法。栈内存贵,你别浪费,堆内存便宜又灵活。
  • " " 中的 scanf(" %s", newFile); 没什么用处。 "%s" 本身会消耗并丢弃前导空间。没有宽度限制scanf(" %s", newFile);gets(newFile); 一样安全。推荐使用fgets() 并去掉其潜在的尾随'\n'
  • @chux yepp,你是对的,当然,这只是懒惰的 c&p。我不想重写整个事情。我有一个很好的理由输入“// ALL CHECKS OMMITTED!”在我的示例代码中;-) 我还认为将整个*scanf() 系列纳入标准是一个坏主意。在几乎所有情况下,手写解析器都更简单、更轻、更安全、更灵活且不易出错。我们真的需要 *printf() 组的反函数吗?
  • 为了便于理解和可读性:1) 通过空行分隔代码块(for、if、else、while、do...while、switch、case、default)。
猜你喜欢
  • 2012-10-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-17
相关资源
最近更新 更多