关于结构数组了解Malloc和Realloc

时间:2018-06-21 12:06:10

标签: c arrays struct malloc realloc

我一直在努力解决malloc和realloc背后的思想,这已经有一段时间了,目前我在动态创建结构数组方面存在问题。我有一个struct triangle,它本身由struct coordinates的数组组成。我希望能够有一个triangles数组,该数组必须足够大,但是每次我尝试增加数组的长度时,似乎什么都没有发生。 Realloc不会失败,malloc也不会失败。但是,新三角形未插入我的数组中。这是我的代码供参考。

#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
struct coordinate {
    int x;
    int y;
};

struct triangle {
    struct coordinate point[3];
};
  static size_t size = 0;

static void addTriangle(struct triangle **triangles, struct triangle *t) {
    struct triangle *ts = (struct triangle*) realloc(*triangles, (size+1) * sizeof(struct triangle));
    if(ts == NULL) {
        free(ts);
        exit(EXIT_FAILURE);
    }

    *triangles = ts;
    triangles[size] = t;
    size++;

}

int main() {
    struct triangle* triangles = (struct triangle *) malloc(sizeof(struct triangle));
    if(triangles == NULL) {
        free(triangles);
        exit(EXIT_FAILURE);
    }
    for(int i = 0; i < 2; i++) {
        struct coordinate *a = malloc(sizeof(struct coordinate));
        a->x = 1 * i;
        a->y = 2 * i;
        struct coordinate *b = malloc(sizeof(struct coordinate));
        b->x = 3 * i;
        b->y = 4 * i;
        struct coordinate *c = malloc(sizeof(struct coordinate));
        c->x = 5 * i;
        c->y = 6 * i;
        struct triangle *t = malloc(sizeof(struct triangle));
        t->point[0] = *a;
        t->point[1] = *b;
        t->point[2] = *c;

        addTriangle(triangles, t);
    }

}

我已经尝试了所有发现的变体,但是我宁愿不只是盲目地将&和*扔进去,直到发生某些事情为止。

3 个答案:

答案 0 :(得分:3)

照原样,您的程序在将未初始化的*triangles传递给reallochttps://taas.trust-in-soft.com/tsnippet/t/9ff94de4时会调用未定义的行为。您可能打算在&triangles中调用main时通过。{p>

main中的呼叫更改为addTriangle(&triangles, t);,下一个问题是addTrianglehttps://taas.trust-in-soft.com/tsnippet/t/658228a1内部的越界访问。同样,这可能是因为您具有错误的间接级别,并且意味着诸如(*triangles)[size]之类的东西。  而不是triangles[size]

如果将行triangles[size] = t;更改为(*triangles)[size] = *t;,则没有未定义的行为。由于已对其进行了修改,因此应检查该程序是否仍能满足您的要求:https://taas.trust-in-soft.com/tsnippet/t/8915bd2d

最终版本:

#include <string.h>
#include <stdlib.h>
struct coordinate {
    int x;
    int y;
};

struct triangle {
    struct coordinate point[3];
};
  static size_t size = 0;

static void addTriangle(struct triangle **triangles, struct triangle *t) {
    struct triangle *ts = (struct triangle*) realloc(*triangles, (size+1) * sizeof(struct triangle));
    if(ts == NULL) {
        free(ts);
        exit(EXIT_FAILURE);
    }

    *triangles = ts;
    (*triangles)[size] = *t; // a struct assignment
    size++;

}

int main() {
    struct triangle* triangles = (struct triangle *) malloc(sizeof(struct triangle));
    if(triangles == NULL) {
        free(triangles);
        exit(EXIT_FAILURE);
    }
    for(int i = 0; i < 2; i++) {
        struct coordinate *a = malloc(sizeof(struct coordinate));
        a->x = 1 * i;
        a->y = 2 * i;
        struct coordinate *b = malloc(sizeof(struct coordinate));
        b->x = 3 * i;
        b->y = 4 * i;
        struct coordinate *c = malloc(sizeof(struct coordinate));
        c->x = 5 * i;
        c->y = 6 * i;
        struct triangle *t = malloc(sizeof(struct triangle));
        t->point[0] = *a;
        t->point[1] = *b;
        t->point[2] = *c;

        addTriangle(&triangles, t); /* pass the address of triangles
           so that addTriangle can modify this variable's contents */
    }

}

与您所问问题没有直接关系的旁注

  1. 只要您使用C编程,请do not cast the result of malloc。只需编写struct triangle* triangles = malloc(...

  2. 正如@aschepler在评论中指出的那样,该程序仍会泄漏从main分配的内存块。这些可以在每次迭代结束时释放,而无需添加任何未定义的行为:https://taas.trust-in-soft.com/tsnippet/t/a0705262。这样做,您可能会意识到t->point[0] = *a;,...实际上是结构分配,并且没有必要首先分配单独的struct coordinate:您只需填写每个{{1} } struct coordinate的成员。另外,也不必在struct triangle中分配struct triangle:您可以为此使用局部变量,因为无论如何,结构的内容将由函数{{1}复制}到main的局部变量addTriangle指向的数组。

  3. 如果maintriangles中的空指针,则无需调用free(triangles)

    triangles

    允许将空指针传递到main,这可以达到您的期望(不执行任何操作),但是由于您知道struct triangle* triangles = (struct triangle *) malloc(... if(triangles == NULL) { free(triangles); exit(EXIT_FAILURE); } 在{ {1}}分支,只需调用free

  4. 处理triangles on the other hand is a subtle subject的失败。您的程序做错了,但没关系,因为它会立即调用NULL

  5. 在静态文件范围变量then中存储有关exit的局部变量realloc指向的已分配数组的信息不一致。两者是如此紧密地联系在一起,因此它们应该在同一范围内。由于您需要exit才能更改main,因此不能简单地将triangles设置为size的局部变量,而可以将局部变量{{1 addTriangle中的}}文件范围,位于size旁边。如果您毕竟希望将size设为main的局部变量,则需要将其地址传递给函数triangles,以便后者可以更新前者。

答案 1 :(得分:0)

您可以将Invalid value for field 'resource.disks[0].source': ''. Source url of disk is missing.循环的整个部分替换为

const createVM = () => {

    const Compute = require('@google-cloud/compute');
    const compute = new Compute();
    const zone = compute.zone('us-central1-f');
    let disk;
    const diskName = 'debian-http-disk';
    const vmName = 'debian-http'
    let vm;

    disk = zone.disk(diskName);

    zone
    .createVM(vmName, {
        disks: [disk], 
        http: true, 
        machineType: 'f1-micro'
    })
    .then((data) => {
        vm = data[0];
        const operation = data[1];
        return operation.promise();
    })
    .then(() => {
        console.log('vm created successfully');        
    })
    .catch((e) => {
        console.error(e);
    });    

};

请注意参数前的for,因为您想同时传递两者的地址。

我已经注意到struct triangle t = {{{i, 2*i},{3*i,4*i},{5*i,6*i}}}; addTriangle(&triangles, &t); 应该是&

triangles[size] = t;

答案 2 :(得分:0)

将函数调用更改为

addTriangle(&triangles, t);