为什么这个分配做得不好?

问题描述 投票:0回答:1

我有

point.h
polygon.h
文件及其关联的
.c
文件。在
point.h

// point.h
#ifndef POINT_H
#define POINT_H

typedef struct Point point;

point* alloc_point(void);
void* free_point(point*);
void* init_point(point*, float, float);
void* print_point(const point*);
float get_x_point(const point*);
float get_y_point(const point*);
void* set_x_point(point*, float);
void* set_y_point(point*, float);

#endif

point.c
,我有

// point.c
#include <stdlib.h>
#include <stdio.h>
#include "point.h"

#define GET_VALUE_ERROR (2L)

struct Point
{
    float x;
    float y;
};

point* alloc_point(void)
{
    point* pt = malloc(sizeof *pt);

    if(NULL == pt)
    {
        fprintf(stderr, "Could not allocate point. Aborting\n");
        return NULL;
    }
    else
    {
        return pt;
    }
}

void* free_point(point* pt)
{
    if(NULL == pt)
    {
        fprintf(stderr, "Could not free point. Aborting\n");
        return NULL;
    }
    else
    {
        free(pt);
        pt = NULL;
        return NULL;
    }
}

void* init_point(point* pt, float x, float y)
{
    if(NULL == pt)
    {
        fprintf(stderr, "Cannot initiate point.\n");
        return NULL;
    }
    else
    {
        pt -> x = x;
        pt -> y = y;
        return NULL;
    }
}

void* print_point(const point* pt)
{
    if(NULL == pt)
    {
        fprintf(stderr, "Cannot print point.\n");
        return NULL;
    }
    else
    {
        printf("Point at (%f, %f)\n", pt -> x, pt -> y);
        return NULL;
    }
}

float get_x_point(const point* pt)
{
    if(NULL == pt)
    {
        fprintf(stderr, "Cannot get point.\n");
        return GET_VALUE_ERROR;
    }
    else
    {
        return pt -> x;
    }
}

float get_y_point(const point* pt)
{
    if(NULL == pt)
    {
        fprintf(stderr, "Cannot get point.\n");
        return GET_VALUE_ERROR;
    }
    else
    {
        return pt -> y;
    }
}

void* set_x_point(point* pt, float x)
{
    if(NULL == pt)
    {
        fprintf(stderr, "Cannot get point.\n");
        return NULL;
    }
    else
    {
        pt -> x = x;
        return NULL;
    }
}

void* set_y_point(point* pt, float y)
{
    if(NULL == pt)
    {
        fprintf(stderr, "Cannot get point.\n");
        return NULL;
    }
    else
    {
        pt -> y = y;
        return NULL;
    }
}

polygon.h
时我有

// polygon.h
#ifndef POLYGON_H
#define POLYGON_H

typedef struct Polygon polygon;

polygon* alloc_polygon(unsigned);
void* free_polygon(polygon*);
void* init_polygon(polygon*, unsigned, float, point*);
void* print_polygon(const polygon*);
unsigned get_polygon_nside(const polygon*);
void* set_polygon_nside(polygon*, unsigned);
point* get_polygon_centre(const polygon*);
void* set_polygon_centre(polygon*, point*);

#endif

并且在

polygon.c
我有

// polygon.c
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include "point.h"
#include "polygon.h"

#ifndef M_PI
    #define M_PI (3.14159265358979323846264338327950288)
#endif

#define GET_NSIDE_ERROR (2U)

struct Polygon
{
    unsigned nside;
    point* centre;
    point** vertices;
};

polygon* alloc_polygon(unsigned nside)
{
    polygon* poly = malloc(sizeof(*poly));

    if(NULL == poly)
    {
        fprintf(stderr, "Cannot allocate polygon.\n");
        return NULL;
    }
    else
    {
        poly -> nside = nside;
        poly -> centre = alloc_point();
        if(NULL == poly -> centre)
        {
            fprintf(stderr, "Cannot allocate polygon centre.\n");
            free(poly);
            poly = NULL;
            return NULL;
        }
        else
        {
            poly -> vertices = malloc(nside * sizeof(point*));
            if(NULL == poly -> vertices)
            {
                fprintf(stderr, "Cannot allocate polygon vertices.\n");
                free(poly -> centre);
                poly -> centre = NULL;
                free(poly);
                poly = NULL;
                return NULL;
            }
            else
            {
                for(unsigned i = 0; i < nside; i++)
                {
                    poly -> vertices[i] = alloc_point();
                    if(NULL == poly -> vertices[i])
                    {
                        fprintf(stderr, "Cannot allocate node %u.\n", i);
                        for(unsigned j = 0; j < i; j++)
                        {
                            free(poly -> vertices[j]);
                            poly -> vertices[j] = NULL;
                        }
                        free(poly -> centre);
                        poly -> centre = NULL;
                        free(poly -> vertices);
                        poly -> vertices = NULL;
                        free(poly);
                        poly = NULL;
                    }
                }
            }
        }

        return poly;
    }
}

void* free_polygon(polygon* poly)
{
    if(NULL == poly)
    {
        fprintf(stderr, "Cannot free polygon.\n");
        return NULL;
    }
    else
    {
        if(NULL == poly -> centre)
        {
            fprintf(stderr, "Cannot free polygon centre.\n");
            return NULL;
        }
        else
        {
            free(poly -> centre);
            poly -> centre = NULL;

            if(NULL == poly -> vertices)
            {
                fprintf(stderr, "Cannot free polygon vertices.\n");
                return NULL;
            }
            else
            {
                free(poly -> vertices);
                poly -> vertices = NULL;

                for(unsigned i = 0; i < poly -> nside; i++)
                {
                    if(NULL == poly -> vertices[i])
                    {
                        fprintf(stderr, "Cannot free vertex %u.\n", i);
                        return NULL;
                    }
                    else
                    {
                        free(poly -> vertices[i]);
                        poly -> vertices = NULL;
                    }
                }
            }
        }

        free(poly);
        poly = NULL;
    }

    return NULL;
}

// Rest of implementation

显然,多边形的分配和/或释放不正确。为了看到这一点,我写了这篇

main.c
阅读

#include <stdio.h>
#include "point.h"
#include "polygon.h"

#define EXECUTION_OK (0U)

int main() {
    unsigned nside = 3;
    float radius = 1.0;

    point* centre = alloc_point();
    init_point(centre, 0.0, 0.0);

    polygon* poly = alloc_polygon(nside);
    init_polygon(poly, nside, radius, centre);

    free_polygon(poly);
    free_point(centre);
    return EXECUTION_OK;
}

使用命令

gcc -Wall -Wextra -Wpedantic -Werror -std=c99 .\point.c .\polygon.c .\main.c -o .\main.exe
编译,我的IDE中有一个“红十字”(我使用
VSCode
),如图所示(这表明出了问题),我也不知道它来自哪里,也不知道如何解决?

c malloc dynamic-memory-allocation c99 opaque-types
1个回答
0
投票

您的程序在

free_polygon()
中出现段错误,因为您在每个
vertices
元素之前释放了
verticies[i]
数组:

                free(poly -> vertices);
                poly -> vertices = NULL;

                for(unsigned i = 0; i < poly -> nside; i++)
                {
                    if(NULL == poly -> vertices[i])
                    {
                        fprintf(stderr, "Cannot free vertex %u.\n", i);
                        return NULL;
                    }
                    else
                    {
                        free(poly -> vertices[i]);
                        poly -> vertices = NULL;
                    }
                }

一般来说,您希望以与获取资源相反的顺序释放资源(因此

vertices[i]
vertices
之前):

void* free_polygon(polygon* poly) {
    if(NULL == poly) {
        fprintf(stderr, "Cannot free polygon.\n");
        return NULL;
    }
    if(NULL == poly->vertices) {
        fprintf(stderr, "Cannot free polygon vertices.\n");
        return NULL;
    }
    for(unsigned i = 0; i < poly->nside; i++) {
        if(NULL == poly->vertices[i]) {
            fprintf(stderr, "Cannot free vertex %u.\n", i);
            return NULL;
        }
        free(poly -> vertices[i]);
        poly -> vertices[i] = NULL;
    }
    if(NULL == poly->centre) {
        fprintf(stderr, "Cannot free polygon centre.\n");
        return NULL;
    }
    free(poly->centre);
    free(poly -> vertices);
    free(poly);
    return NULL;
}

由于您的函数始终返回

NULL
,请考虑将其返回类型更改为
void
。另外看看是否可以使用
free_polygon()
中的
alloc_polygon()
函数,因为它相当复杂。我通常以某种方式构造我的对象,这样我就可以在任何时候调用 free,并且在 free 期间不会将部分构造的对象视为错误。最后,(不固定)考虑使用命名空间前缀,即
polygon_alloc()
而不是
alloc_polygon()

polygon* alloc_polygon(unsigned nside) {
    polygon* poly = malloc(sizeof(*poly));
    if(!poly) {
        fprintf(stderr, "Cannot allocate polygon.\n");
        return NULL;
    }
    poly -> nside = nside;

    poly->centre = NULL;
    poly->vertices = NULL;
    poly -> centre = alloc_point();
    if(!poly->centre) {
        fprintf(stderr, "Cannot allocate polygon centre.\n");
        free_polygon(poly);
        return NULL;
    }
    poly->vertices = malloc(nside * sizeof(point*));
    if(!poly->vertices) {
        fprintf(stderr, "Cannot allocate polygon vertices.\n");
        free_polygon(poly);
        return NULL;
    }
    for(unsigned i = 0; i < nside; i++) {
        poly -> vertices[i] = alloc_point();
        if(!poly->vertices[i]) {
            fprintf(stderr, "Cannot allocate node %u.\n", i);
            free_polygon(poly);
            return NULL;
        }
    }
    return poly;
}

void free_polygon(polygon* poly) {
    if(!poly) return;
    if(!poly->vertices) return;
    for(unsigned i = 0; i < poly->nside; i++)
        free(poly -> vertices[i]);
    free(poly->centre);
    free(poly ->vertices);
    free(poly);
}
© www.soinside.com 2019 - 2024. All rights reserved.