C指针和动态alloc

时间:2017-10-21 08:18:17

标签: c pointers malloc

我现在只用了2个星期学习C语言,而且我遇到动态配置和指针的问题,我对下面的代码感到有点困惑。

我试着理解读取功能是如何工作的,但*m让我困惑。我无法找到使用*m参数的方法,也就是

if((*h = (struct inhabitant *)malloc(sizeof(struct inhabitant) * (*m))) == NULL)

我被吹走了。

以下是代码:

#include <stdlib.h>
#include "inhabitants.h"
#include "sort.h"

void read(FILE *s, struct inhabitant **h, int *m) {
  int i, ntok;
  struct inhabitant *tmph;

  ntok = fscanf(s, "%d", m);
  if(ntok != 1 || *m < 0) {
    fprintf(stderr, "Unable to read file.\n");
    exit(-1);
  }

  if((*h = (struct inhabitant *)malloc(sizeof(struct inhabitant) * (*m))) == NULL) {
    fprintf(stderr, "Unable to allocate space for inhabitants.\n");
    exit(-1);
  }

  tmph = *h;
  for(i = 0; i < (*m); ++i) {
    ntok = fscanf(s, "%d %s %s %d", &(tmph[i].distance), (char *)&(tmph[i].prenom), (char *)&(tmph[i].nom), (int *)&(tmph[i].zip));
    if(ntok != 4) {
      fprintf(stderr, "File wrongly formatted.\n");
      exit(-1);
    }
  }

}

int compare_inhabitants_by_distance(struct inhabitant *a, struct inhabitant *b) {
    if (a->distance > b->distance)
        return 1;
    else
        return 0;
  //à compléter
}

int compare_inhabitants_by_zipcode(struct inhabitant *a, struct inhabitant *b) {
  if (a->enum zipcode > b->enum zipcode)
        return 1;
    else
        return 0;
  //à compléter
}

void show(int n, struct inhabitant *a) {
  int i;
  for(i = 0; i < n; ++i) {
    printf("%d, %s, %s, %d\n", a[i].distance, a[i].prenom, a[i].nom, a[i].zip);
  }
}

void printout(FILE *s, int n, struct inhabitant *a) {
  int i;
  for(i = 0; i < n; ++i) {
    fprintf(s, "%d %s %s %d\n", a[i].distance, a[i].prenom, a[i].nom, a[i].zip);
  }
}

#define PERSONS_TO_SAVE_FILE_IN "evacuation_plan0.txt"
#define PERSONS_TO_SAVE_FILE_OUT "better_evacuation_plan0.txt"

int main(int argc, char **argv) {
  FILE *s;
  int n;
  /*For testing purpose :
  struct inhabitant inhabs[] = {
                                { 100, "Jean", "France", GUADELOUPE },
                                { 10, "Ameni", "Braminia", STBARTH },
                                { 12, "Mathieu", "Krister", GUADELOUPE },
                                { 23, "Hilaire  ", "Blanchi", STMARTIN }
                              };
  n = sizeof(inhabs) / sizeof(*inhabs);*/

  struct inhabitant *inhabs0;


  if((s = fopen(PERSONS_TO_SAVE_FILE_IN, "r")) == NULL) {
    fprintf(stderr, "Unable to open file.");
    exit(-1);
  }

  read(s, inhabs, )

  /*
  A compléter :
  - Lecture du fichier.
  - Tris.
  */

  if((s = fopen(PERSONS_TO_SAVE_FILE_OUT, "w+")) == NULL) {
    fprintf(stderr, "Unable to open file.");
    exit(-1);
  }
  printout(s, n, inhabs0);
  fclose(s);

  free(inhabs0);

  return EXIT_SUCCESS;
}

感谢阅读。希望你能找到解决方案。

2 个答案:

答案 0 :(得分:3)

在C中,assignment有些expression,表达式是statement的简单(非常常见)类型。

所以而不是

int a = 2+3;
if (a>4) { 

你可以编码

int a;
if ((a=2+3) > 4) {

具有相同的semantics

所以你的if statement类似于:

*h = (struct inhabitant *)malloc(sizeof(struct inhabitant) * (*m));
if (*h == NULL) 

(使用原始代码中的复杂if或将其拆分为两个语句,这是一个可读性和品味的问题;但是,请注意sequence points

顺便说一下,原始代码中的后续内容是味道不佳(使用exit(3)时-1也是味道差)。您最好使用perror(3)strerror(3)errno(3)来解释malloc失败的原因。所以我建议那么

  { // when *h is NULL because malloc failed
     fprintf(stderr, 
             "Unable to allocate space for %d inhabitants: %s\n", 
             *m, strerror(errno));
     exit(EXIT_FAILURE);
  }

并且在您的特定情况下(分配数组)我建议使用calloc(3)(以获得一些零初始化内存区域)而不是malloc

顺便说一句,我建议您更改read功能的名称。它可能与POSIX read混淆。

不要忘记编译所有警告和调试信息,所以gcc -Wall -Wextra -gGCC(阅读Invoking GCC)。改进您的代码以获得警告。在使用之前,请阅读每个功能的documentation。学习use the debugger gdb。努力避免undefined behavior,并且非常scared

还详细了解C dynamic memory allocationpointer aliasingvirtual address spacememory leaksgarbage collectionreference counting。除gdb调试器外,valgrind有时也很有用。还要研究现有 free software的源代码(例如在github上),你会学到很多东西。

答案 1 :(得分:2)

除了指出的其他错误外,您的fscanf变量也是错误的。您无需传递 prenumnom地址,因为它们已经是指针,例如

    for (i = 0; i < *m; ++i) {
        /* casts should not be necessary, prenom & nom already pointers */
        ntok = fscanf (s, "%d %s %s %d", &tmph[i].distance, (tmph[i].prenom),
                        (tmph[i].nom), &(tmph[i].zip));

此外,分配本身有点笨拙。使用变量名称而不是sizeof的类型,并且无需转换malloc的返回值,例如

    /* allocate/validate space for 'm' inhabitants */
    if ((*h = malloc (sizeof **h * *m)) == NULL) {
        fprintf (stderr, "Unable to allocate space for inhabitants.\n");
        exit (-1);
    }

请参阅:Do I cast the result of malloc?

未经测试,但完全放弃,您的阅读功能可以更新为类似于:

void read (FILE *s, struct inhabitant **h, int *m)
{
    int i, ntok;
    struct inhabitant *tmph;

    ntok = fscanf (s, "%d", m);
    if (ntok != 1 || *m < 0) {
        fprintf (stderr, "Unable to read file.\n");
        exit (-1);
    }

    /* allocate/validate space for 'm' inhabitants */
    if ((*h = malloc (sizeof **h * *m)) == NULL) {
        fprintf (stderr, "Unable to allocate space for inhabitants.\n");
        exit (-1);
    }

    tmph = *h;
    for (i = 0; i < *m; ++i) {
        /* casts should not be necessary, prenom & nom already pointers */
        ntok = fscanf (s, "%d %s %s %d", &tmph[i].distance, (tmph[i].prenom),
                        (tmph[i].nom), &(tmph[i].zip));
        if (ntok != 4) {
            fprintf (stderr, "File wrongly formatted.\n");
            exit (-1);
        }
    }
}

尝试一下,如果您有任何其他问题,请告诉我。

注意:您在main()中也有明显错字,read(s, inhabs, )似乎是read (s, &inhabs0);如果您给read一个有意义的回报类似于int,然后您可以返回01来表示成功/失败,而不会自动从函数中退出程序。