【问题标题】:What is this bug about? Structs, Pointers, Dynamic Memory Allocation , C这个错误是关于什么的?结构,指针,动态内存分配,C
【发布时间】:2017-05-08 21:43:06
【问题描述】:

我正在用 c 编写一个简单的银行应用程序 它将信息保存在文件中。 我想在应用程序每次运行时加载文件,并将文件中的信息添加到结构中,为此,我编写了两个函数,分别称为“loadfile”和“allocate”

在函数“loadfile”中,如果我取消注释注释行,操作系统会在我脸上抛出“停止工作”:|

你能帮我吗? 当我在“加载文件”中使用 (acc+i) 时,会出现错误。 有语法问题吗? :o 谢谢

typedef struct {
    char name[20];
    int id;
    int balance;
    char branch[10];
} account;

account *acc;

int allocate ( account *acc )  {
    int num = 0 ;
    char tempname[20],tempbranch[10];
    int tempid = -1 ,tempbalance;
    FILE *file;
    file = fopen("D://bank.txt","r");
    while ( !feof(file) ) {
        fscanf(file,"%s %d %d %s ",tempname, &tempid, &tempbalance, tempbranch);
        if (tempid != -1)
            num++;
    }
    acc = ( account *) realloc ( acc, num * sizeof(account) );
    fclose(file);
    printf(" num in allocate function : %d",num);
    return num;
}

int loadfile (account *acc) {
    int num = allocate(acc);
    char tempname[20],tempbranch[10];
    int tempid ,tempbalance;
    if ( num != 0 ) {
        int i = 0 ;
        FILE *file;
        file = fopen("D:\\bank.txt","r+");
        for ( i = 0 ; !feof(file) && i < num ; i++ ) {
            fscanf(file,"%s ",tempname );
            fscanf(file,"%d ",&tempid );
            fscanf(file,"%d ",&tempbalance );
            fscanf(file,"%s ",tempbranch );
            printf("\n i is %d \n",i);
            /* strcpy( ((acc+i)->name) , tempname);
            (acc+i)->id = tempid;
            (acc+i)->balance = tempbalance;
            strcpy( ((acc+i)->branch) , tempbranch); */
        }
        fclose(file);
    }
    return num;
}

【问题讨论】:

  • 使用全局 account *acc; I.E int allocate ( account *acc ) { --> int allocate (void) {
  • 不要投void *函数的返回值!
  • 这段代码有太多错误。它不验证返回值,也不能正确使用feof()。另外,您不知道 C 中的作用域是什么,并且您的格式样式不好。
  • @SOFUser 有两种方法可以使用 realloc: 使用它来更改先前分配的段的大小。然后,您必须将指针传递给先前分配的内存。或者你像 malloc 一样使用它来分配新内存。然后,您必须传递一个 NULL 指针。您执行后者似乎只是运气不好,因为您使用的是具有静态存储持续时间的 icky 全局变量,因为它恰好初始化为 NULL。如果您将该变量移动到应该在的本地范围内,那么除非您将指针显式初始化为 NULL,否则 realloc 将不起作用。

标签: c file struct allocation scanf


【解决方案1】:

我无法解释你所有的问题。我需要几个小时。我希望这段代码是自描述的。如果您需要帮助,请在评论中问我。

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

typedef struct {
  char name[20];
  int id;
  int balance;
  char branch[10];
} account_t;

static account_t *parse_account_file(FILE *file, size_t *size) {
  if (file == NULL || size == NULL) {
    return NULL;
  }

  size_t i = 0;
  account_t *account = malloc(sizeof *account);
  if (account == NULL) {
    return NULL;
  }

  int ret;
  while (
      (ret = fscanf(file, "%19s %d %d %9s\n", account[i].name, &account[i].id,
                    &account[i].balance, account[i].branch)) == 4) {
    account_t *old = account;
    account = realloc(account, sizeof *account * (++i + 1));
    if (account == NULL) {
      free(old);
      return NULL;
    }
  }

  if (ret == EOF) {
    if (ferror(file)) {
      perror("parse_account_file()");
    } else {
      *size = i;
      account_t *old = account;
      account = realloc(account, sizeof *account * i);
      if (account == NULL) {
        return old;
      }
      return account;
    }
  } else {
    fprintf(stderr, "error parsing\n");
  }

  free(account);

  return NULL;
}

int main(void) {
  char const *name = "D:\\bank.txt";
  FILE *file = stdin;

  size_t size;
  account_t *account = parse_account_file(file, &size);
  fclose(file);
  if (account == NULL) {
    return 1;
  }

  for (size_t i = 0; i < size; i++) {
    printf("%s %d %d %s\n", account[i].name, account[i].id, account[i].balance,
           account[i].branch);
  }

  free(account);
}

【讨论】:

  • 不是downvoter,而是return realloc(account, sizeof *account * i);的范围是什么???
  • 旁注:如果realloc 失败,使用realloc 将其返回值反映到原始指针可能会泄漏先前分配的内存。
  • @LPs 我虽然 realloc 如果无法找到内存,我会解决这个问题。我从不在我的程序中使用realloc。我返回realloc(这个不会失败,不是吗?),告诉我没有使用我分配的超出内存stackoverflow.com/questions/7078019/…
【解决方案2】:

发布的代码存在很多问题。尚不清楚单独的分配函数有何帮助,不建议使用文件范围变量acc。我认为在这里使用realloc() 没有意义,因为分配只进行一次。如果您确实使用了realloc(),则应该将结果存储在一个临时指针中,因为如果出现分配错误,该函数可以返回一个NULL 指针。如果直接分配给要重新分配的指针,这会导致内存泄漏。我重写了代码以说明一些修复,试图保持原始代码的一般结构。

您应该检查您调用的函数的返回值。 realloc()malloc() 返回一个指向已分配内存的指针,或者在发生分配错误时返回一个 NULL 指针。您应该检查此值并处理结果。 scanf() 函数返回成功分配的数量。您应该检查此值以验证输入是否符合预期。使用feof() 控制循环是almost always a bad idea,因为该函数依赖于设置的文件结束指示器,并且该指示器仅在 I/O 操作失败时设置。

在下面的程序中,fgets() 用于从文件中读取一行输入到缓冲区中,sscanf() 用于从缓冲区中提取输入数据。在分配阶段,EOF 或空行表示数据结束。这里不做解析,只计算行数。对于每一行,为account 分配空间。请注意,代码会检查打开和关闭文件时的错误以及分配错误。

loadfile() 函数再次使用fgets() 将一行输入读入buffer,然后使用sscanf() 扫描缓冲区。请注意字符串的宽度说明符的使用。这些比它们读入的数组的大小小一,以便为sscanf() 放置在字符串末尾的'\0' 留出空间。另请注意,如果进行的分配少于 4 个,则程序 exits 会显示错误消息。如果对临时变量的赋值成功,account 会更新数据。

有很多方法可以改进这段代码(最明显的是去掉全局变量acc),但这应该为您提供一个很好的起点。

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

typedef struct {
    char name[20];
    int id;
    int balance;
    char branch[10];
} account;

account *acc = NULL;

int allocate(void)
{
    int num = 0 ;
    char buffer[1000];
    FILE *file;

    file = fopen("D://bank.txt","r");
    if (file == NULL) {
        fprintf(stderr, "Unable to open file in allocate()\n");
        exit(EXIT_FAILURE);
    }

    while (fgets(buffer, sizeof(buffer), file) != NULL &&
           buffer[0] != '\n') {
        num++;
    }

    acc = malloc(num * sizeof(*acc));
    if (acc == NULL) {
        fprintf(stderr, "Allocation error in allocate()\n");
        exit(EXIT_FAILURE);
    }

    if (fclose(file) != 0) {
        fprintf(stderr, "Unable to close file in allocate()\n");
        exit(EXIT_FAILURE);
    }

    printf(" num in allocate function : %d\n",num);
    return num;
}

int loadfile(void)
{
    int num = allocate();
    char buffer[1000], tempname[20],tempbranch[10];
    int tempid ,tempbalance;
    if ( num != 0 ) {
        int i = 0 ;
        FILE *file;

        file = fopen("D://bank.txt","r+");
        if (file == NULL) {
            fprintf(stderr, "Unable to open file in loadfile()\n");
            exit(EXIT_FAILURE);
        }

        while (fgets(buffer, sizeof(buffer), file) != NULL
               && buffer[0] != '\n') {
            if (sscanf(buffer, "%19s %d %d %9s",
                       tempname, &tempid, &tempbalance, tempbranch) != 4) {
                fprintf(stderr, "%d: Malformed input data\n", i);
                exit(EXIT_FAILURE);
            }

            strcpy(acc[i].name, tempname);
            acc[i].id = tempid;
            acc[i].balance = tempbalance;
            strcpy(acc[i].branch, tempbranch);
            ++i;
        }

        if (fclose(file) != 0) {
            fprintf(stderr, "Unable to open file in loadfile()\n");
            exit(EXIT_FAILURE);
        }
    }

    return num;
}

int main(void)
{
    int num = loadfile();
    for (int i = 0; i < num; i++) {
        printf("%s %d %d %s\n",
               acc[i].name, acc[i].id, acc[i].balance, acc[i].branch);
    }

    return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-01-10
    • 2021-02-14
    • 1970-01-01
    • 1970-01-01
    • 2013-04-18
    • 2015-07-04
    • 2023-04-02
    • 2017-01-03
    相关资源
    最近更新 更多