我有point.h个和polygon.h个文件,以及与它们相关的.c个文件.在point.h年内

// point.h
#ifndef POINT_H
#define POINT_H

typedef struct Point point;

point *point_alloc(void);
void *point_free(point *);
void *point_init(point *, float, float);
void *point_print(const point *);
float point_get_x(const point *);
float point_get_y(const point *);
void *point_set_x(point *, float);
void *point_set_y(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 *point_alloc(void)
{
    point *pt = malloc(sizeof *pt);

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

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

void *point_init(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 *point_print(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 point_get_x(const point *pt)
{
    if(NULL == pt)
    {
        fprintf(stderr, "Cannot get point.\n");
        return GET_VALUE_ERROR;
    }
    else
    {
        return pt -> x;
    }
}

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

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

void *point_set_y(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 *polygon_alloc(unsigned);
void *polygon_free(polygon *);
void *polygon_init(polygon *, unsigned, float, point *);
void *polygon_print(const polygon *);
unsigned polygon_get_nside(const polygon *);
void *polygon_set_nside(polygon *, unsigned);
point *polygon_get_centre(const polygon *);
void *polygon_set_centre(polygon *, point *);
point *polygon_get_vertex(const polygon *, unsigned);
void *polygon_set_vertex(polygon *, unsigned, float, float);

#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 *polygon_alloc(unsigned nside)
{
    if(nside == 0)
    {
        fprintf(stderr, "Cannot have a 0-sided polygon.\n");
        return NULL;
    }
    else
    {
        polygon *poly = malloc(sizeof(*poly));

        if(NULL == poly)
        {
            fprintf(stderr, "Cannot allocate polygon.\n");
            return NULL;
        }
        else
        {
            poly -> nside = nside;
            poly -> centre = point_alloc();
            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] = point_alloc();
                        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 *polygon_free(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
            {
                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[i] = NULL;
                    }
                }

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

        free(poly);
        poly = NULL;
    }

    return NULL;
}

void *polygon_init(polygon *poly, unsigned nside, float radius, point *centre)
{
    if(NULL == poly)
    {
        fprintf(stderr, "Polygon not existing.\n");
        return NULL;
    }
    else if(NULL == centre)
    {
        fprintf(stderr, "Polygon centre not existing.\n");
        return NULL;
    }
    else
    {
        polygon_set_nside(poly, nside);
        polygon_set_centre(poly, centre);

        for(unsigned i = 0; i < poly -> nside; i++)
        {
            float angle = (1 + 2 * i) * (M_PI / poly -> nside);
            float x = radius * cos(angle);
            float y = radius * sin(angle);
            polygon_set_vertex(poly, i, x, y);
        }

        return NULL;
    }
}

void *polygon_set_nside(polygon *poly, unsigned nside)
{
    if(NULL == poly)
    {
        fprintf(stderr, "Cannot set polygon number of sides.\n");
        return NULL;
    }
    else
    {
        poly -> nside = nside;
        return NULL;
    }
}

void *polygon_set_centre(polygon *poly, point *centre)
{
    if(NULL == poly)
    {
        fprintf(stderr, "Cannot set polygon number of sides.\n");
        return NULL;
    }
    else
    {
        poly -> centre = centre;
        return NULL;
    }
}

// Rest of implementation

显然,多边形的分配和/或释放是不正确的.为了看到这一点,我写下了这main.c个读数

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

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

    point* centre = point_alloc();
    point_init(centre, 0.0, 0.0);

    polygon* poly = polygon_alloc(nside);
    polygon_init(poly, nside, radius, centre); // this one is a problem
    polygon_print(poly);

    polygon_free(poly);
    point_free(centre);
    exit(EXIT_SUCCESS);
}

compiled using the command gcc -Wall -Wextra -Wpedantic -Werror -std=c99 .\point.c .\polygon.c .\main.c -o .\main.exe, I have a a "red cross in my IDE (I use VSCode), as illustrated here in the picture (which indicates that something is wrong) and I do not know neither from where it comes, nor how to solve it? enter image description here

100

多亏了下面的答案,我更正了分配/释放函数,并能够发现问题是由polygon_init函数引起的,但我不能准确地指出哪里出了问题?

推荐答案

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

                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).free_polygon()中的任何错误都可能导致内存泄漏.例如,如果是poly->vertices[i] == NULL,那么我们不会释放剩余的poly->verticies[i]poly->verticespoly->centrepoly.因为您的alloc_polygon()负责部分构造,所以可能没问题,但这是一个有风险的设计:

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;
    }
    free(poly->vertices);
    if(NULL == poly->centre) {
        fprintf(stderr, "Cannot free polygon centre.\n");
        return NULL;
    }
    free(poly->centre);
    free(poly);
    return NULL;
}

其他建议:

  1. 由于free_polygon()总是返回NULL,请考虑将其返回类型更改为void.
  2. 有了经验,!polyNULL == poly更容易读懂.
  3. alloc_polygon()是相当复杂的;考虑将分配和释放函数设计为匹配对,这样你就可以在一个部分构造的对象上调用free_polygon(),方法是用NULL,calloc而不是malloc()verticies初始化变量,并反向释放资源. 我通常使用goto来清理链,但是如果你有疑虑,你可以在每个错误情况下重复这两行. 编译器(至少是gcc)会在你错过goto之前的变量初始化时警告你,我觉得这很有帮助.
  4. 由于您的poly对象的生命周期在调用free_polygon()之后到期,所以我从不费心将任何变量设置为NULL.这就是说,它可能会帮助你在免费缺陷后获得使用.
  5. 考虑使用名称空间前缀,即polygon_alloc()而不是alloc_polygon().
  6. 更喜欢polygon *poly而不是polygon* poly.如果您在一行中声明了两个指针,则可以避免混淆.
polygon *polygon_alloc(unsigned nside) {
    polygon *poly = malloc(sizeof *poly);
    if(!poly) {
        fprintf(stderr, "Cannot allocate polygon.\n");
        goto err;
    }
    poly->nside = nside;
    poly->vertices = NULL;
    poly->centre = alloc_point();
    if(!poly->centre) {
        fprintf(stderr, "Cannot allocate polygon centre.\n");
        goto err;
    }
    poly->vertices = calloc(nside, sizeof *poly->vertices);
    if(!poly->vertices) {
        fprintf(stderr, "Cannot allocate polygon vertices.\n");
        goto err;
    }
    for(unsigned i = 0; i < nside; i++) {
        poly->vertices[i] = alloc_point();
        if(!poly->vertices[i]) {
            fprintf(stderr, "Cannot allocate node %u.\n", i);
            goto err;
        }
    }
    return poly;
:err
    polygon_free(poly);
    return NULL;   
}

void polygon_free(polygon *poly) {
    if(!poly) return;
    if(poly->vertices)
        for(unsigned i = 0; i < poly->nside; i++)
           free(poly->vertices[i]);
    free(poly->vertices);
    free(poly->centre);
    free(poly);
}

C++相关问答推荐

海湾合作委员会是否保证大小匹配的访问?

try 使用sigqueue函数将指向 struct 体的指针数据传递到信号处理程序,使用siginfo_t struct 体从一个进程传递到另一个进程

如何启用ss(另一个调查套接字的实用程序)来查看Linux主机上加入的多播组IP地址?

无效使用未定义类型'structsquare'?

什么C代码将确定打开的套接字正在使用的网络适配器?

在32位处理器上优化53—32位模计算>

如何判断宏参数是否为C语言中的整型文字

以前版本的tty_ldisc_ops.ioctl()是否也需要文件参数?

在编译时参数化类型定义

具有交换链获取和命令缓冲区提交的同步-危险-读后写错误

在C语言中,是否可以使枚举数向后计数?

如何识别Linux中USB集线器(根)和连接到集线器(根设备)的设备(子设备)?

对于C中给定数组中的每个查询,如何正确编码以输出给定索引范围(1到N)中所有数字的总和?

为什么指针运算会产生错误的结果?

在C++中允许使用字符作为宏参数

我不知道为什么它不能正常工作,我用了get()和fget(),结果是一样的

`%%的sscanf无法按预期工作

GnuCobol 使用 double 类型的参数调用 C 函数

为什么使用 C 引用这个 char 数组会导致 Stack smasing?

我怎样才能用c语言正常运行这两个进程?