【问题标题】:Load and print file using Struct - with Programing C使用 Struct 加载和打印文件 - 使用编程 C
【发布时间】:2013-02-27 19:36:00
【问题描述】:

我正在努力学习使用结构。将文件加载并读入 struct c,打印文件!

我正在尝试逐行阅读!并打印每行的姓名和姓氏!

.....

int memmove(struct students*s, char line){

int count;  /* The current number of entries in the array */
int remove; /* The entry to remove (index into array, so zero based) */

/* Move the still valid entries one step "down" in the array */

printf("tabort?: ");
        scanf("%s", &line);
    memmove(s + remove, s + (remove + 1),
   sizeof(struct students) * (count - remove - 1));

count--;  /* Now contains one less entry */

}

【问题讨论】:

  • 首先,不要在头文件中定义变量。要继续,请不要在不必要时使用全局变量。最后,关闭load 中的文件,但访问print 中的文件指针。
  • 我关闭了文件,因为什么都不会改变它,我只希望控制台屏幕中的文件是我有结构的原因!,我想将文件读入结构数组!
  • 但是如果你已经关闭了文件,那么不要继续读取它
  • 完全正确!,我关闭了文件,不想从中读取。我就是这样做的
  • 但是您使用 fscanf 调用从 print 中的文件读取。这是非法的,因为文件已被关闭。如果fp 变量是load 函数的本地变量应该是,那么你会在那里得到一个编译器错误。现在你得到一个运行时错误(即可能是崩溃)。

标签: c file load structure


【解决方案1】:

不要在print 中执行fscanf(您应该只打印,而不是从文件中读取任何内容)在加载时执行scanf-family 调用。这是一个几乎完整的示例,说明我将如何做到这一点:

#include <stdio.h>
#include <ctype.h>

#define MAX_NAME_LENGTH  100
#define MAX_STRUCTS      100

struct analg
{
    char f_name[MAX_NAME_LENGTH];
    char l_name[MAX_NAME_LENGTH];
};

/* Load from the named file, into the `analg` array provided, but no more than `max` entries */
/* Returns the number of entries loaded */
int load(char *filename, struct analg *h, int max)
{
    int count = 0;  /* The number of entries we have loaded */

    FILE *fp = fopen(filename, "r");

    char line[MAX_NAME_LENGTH * 2];  /* *2 for first and last name */

    if (fp == NULL)
        return;  /* File could not be opened */

    /* Read all lines, but only as long as we have available entries in the array */
    while (count < max && fgets(line, sizeof(line), fp) != NULL)
    {
        /* Extract the first and last names from the newly read line */
        sscanf(line, "%s %s", h[count].f_name, h[count].l_name);
        count++;  /* Increase counter so we have the current size */
    }

    /* All done loading */
    fclose(fp);

    return count;  /* Return the number of entries we loaded */
}

/* Print from the structure array, there are `count` entries in the array */
void print(struct analg *h, int count)
{
    for (int i = 0; i < count; i++)
    {
        /* Print the number and the names */
        /* +1 to the index, because it starts from zero and we want to print it nicely to the user and start from 1 */
        printf("Number %2d: %s %s\n", i + 1, h[i].f_name, h[i].l_name);
    }
}

int main(void)
{
    struct analg h[MAX_STRUCTS];

    int choice;
    int count = 0;  /* Initialize to zero, in case user chooses `print` first */

    do
    {
        printf("choose L or P: ");

        /* Read input from user, as a character, while skipping leading and trailing whitespace */
        scanf(" %c ", &choice);

        switch (tolower(choice))
        {
        case 'l':
            count = load("text.txt", h, MAX_STRUCTS);
            if (count == 0)
                printf("No structures loaded\n");
            break;

        case 'p':
            print(h, count);
            break;

        case 'q':
            /* Do nothing, just catch it for error reporting (below) will work */
            break;

        default:
            printf("\nPlease only use 'p' or 'l', or 'q' for quit\n");
            break;
        }
    } while (tolower(choice) != 'q');

    return 0;
}

OP 还想知道如何在读取条目后删除它。首先要记住的是,这些行是从文件中加载的顺序,所以要在数组中找到特定的行,只需取文件中的行号,然后减去一个(作为数组索引从零开始)。

对于实际的移除,有几个解决方案:

  1. 在结构中保留一个布尔标志,以判断它是否有效。删除条目时,只需将标志设置为“false”,打印或保存或其他处理时忽略所有标志为“false”的条目。

  2. 将要删除的条目上方的条目下移一级。这将覆盖您要删除的条目,因此它不再存在。它比第一个解决方案工作更多,但不会在数组中留下未使用的条目。

    使用memmove

    int count;  /* The current number of entries in the array */
    int remove; /* The entry to remove (index into array, so zero based) */
    
    /* Move the still valid entries one step "down" in the array */
    memmove(h + remove, h + (remove + 1),
           sizeof(struct analg) * (count - remove - 1));
    
    count--;  /* Now contains one less entry */
    

    如果您想知道h + remove 表达式,它被称为指针算法,并使用表达式h[remove]*(h + remove) 相同的事实,这意味着@987654330 @ 与 &amp;h[remove] 相同。

  3. 不要使用数组,而是使用链表,在该链表的末尾追加新行。这是最有效的解决方案,您也无法轻松删除特定行。然而,这种方法可以很容易地删除(和添加)列表中任何位置的节点。

如果您想要结构中的其他字段,例如年龄,则只需添加该字段。您当然需要修改文本文件的解析,但如果新字段放在文本文件的行尾,那么只需在sscanf 调用中添加另一种格式。当查找一个特定字段设置为特定值的条目时,只需遍历数组(或列表)并将该字段与所需值进行比较。

【讨论】:

  • 感谢您的帮助,我认为这是正确的代码,但是您知道吗,我可以例如做一个可以删除第 2 行的功能,例如:选择要删除的行号:2。行是已删除!
  • jag såg att du var från Malmö så tänkte skriva på svenska så kan förklara bättre :) jag tänkte om att kunna ta bort en rad genom att jag väljer rad nummer och tänkte ha om jag vill until ex deras ålder med hur can jag skriva en array eller variabel som kollar upp åldern?
  • @perjohn Jag har uppdaterat (på engelska, så att andra kan förstå. :)) mitt svar.
  • 感谢您的回答,我正在尝试为该程序制作switchcases,我的意思是喜欢我自己的程序,但尝试使用您的程序,所以我不明白,是吗?知道如何例如写 p 来打印它或 L 来加载它吗?
  • Det är ett stort problem som jag håller på att lösa:/ men går ej !!
【解决方案2】:

对您的程序进行了一些更改以使其正常运行

#include<stdio.h>

struct analg {
char f_name[100];
char l_name[100];
};
struct analg h;
FILE *fp;




void load() 
{
fp = fopen("text.txt", "r");

  if(fp == NULL)
  {
   printf("fail");
   return; 
  }

fgets(h.f_name, 100, fp); 
fgets(h.l_name, 100, fp); 


printf("file loaded!\n");
fclose(fp);
return;
}


void print()
{
    fscanf(fp,"%s %s\n",h.f_name,h.l_name);
    printf ("%s\n",h.f_name);
    printf ("%s\n",h.l_name);
return;
}


int main ()
{
char choice;
do{ 
printf("choose L or P: ");
scanf("%c", &choice);
switch(choice)
 {
  case 'l': 
    load();
    printf("\n[l]oad - [p]rint\n");
    break;
  case 'p': 
    print();
    printf("\n[l]oad - [p]rint\n");
    break;    

  default:        
    break;
 }
 }  
 while(choice!='q');

 return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-25
    • 1970-01-01
    • 1970-01-01
    • 2022-11-08
    相关资源
    最近更新 更多