0

以下代码编译并执行,没有任何警告或错误。但是,当我使用夹板分析代码时,它显示 4 个警告(显示在代码下方)。

我见过的大多数示例(带有那种警告)都使用 malloc 和 free。由于此代码不使用 malloc,我们可以说忽略这些警告是安全的吗?在不删除指针的情况下编写代码的正确方法应该是什么?

#include <stdio.h>

typedef struct
{
    void (*Doit) ( void );
} func;

typedef struct
{
    func f;
    int val;
} obj;

typedef struct
{
    obj *o;
} world;

static void Read( void ) {
    printf( "Read\n");
}

static void Init( world *w ) {
    obj pc;
    w->o = &pc;           //(1)
    w->o->val = 10;
    w->o->f.Doit = Read;
    w->o->f.Doit();
}

int main() {
    world w;
    Init( &w );     //(2)
    return 0;      //(3)
}

(1) :28:5: 仅隐式存储 w->o (type obj *) 未在分配前释放: w->o = &pc 。检测到内存泄漏。只有限定的存储在最后一次引用丢失之前不会被释放。

(1) :28:5: 直接地址 &pc 仅隐式分配给: w->o = &pc 。立即地址(& 运算符的结果)传输不一致。

(2) :33:11: 定义前使用的变量 w 使用的右值可能未初始化为某个执行路径上的值。

(3) :34:14: 只有从这个范围内声明的变量派生的存储 wo(类型 obj *)不会被释放(内存泄漏)。怀疑由于结构或深度指针的不完全释放导致的存储泄漏。可从正在解除分配的引用访问的非共享存储尚未被解除分配。Splint 假设当一个对象作为仅输出的 void 指针传递时,外部对象将被释放,但内部对象不会。

这段代码只是对我想要实现的其他东西的测试,但由于我不精通 C,我想了解使用上述方法的内存泄漏风险。

提前致谢。

4

2 回答 2

2

我发现splint输出非常难以理解。根据您的平台,您可能还想尝试valgrind.

不管怎样,您的代码的主要问题是它pc是一个局部变量。它在 结束时变得无效Init(),因为它(可能与每个编译器一起)位于堆栈上。

你可能想要做

w->o = (obj *) malloc(sizeof(obj));

反而。

另一种方法是将 w 中的 o 的类型更改为obj而不是obj *

关于内存管理的注意事项C(强烈推荐进一步阅读):

函数参数和局部变量通常位于所谓的stack. 一旦函数返回,它们就会失效。编译器总是需要知道堆栈对象的大小。

通过分配的对象malloc()位于堆上。malloc()可用于未知大小的对象。分配的对象malloc()保持有效,直到它们的指针传递给realloc()or free()。如果您忘记将malloc'd 指针传递给free,则会发生内存泄漏。如果您在对象变得无效后访问它,您将获得未定义的行为(堆中的那个位置现在可能被其他东西重用,但也许数据仍然存在,谁知道?)。在最坏的情况下,您可能会遇到分段错误或堆损坏。如果您将无效的对象指针传递给free()or realloc(),您可能会遇到堆损坏。

全局变量和静态函数成员位于其他地方(tm),并且在程序的整个执行过程中有效(至少从进入 main 直到从它返回,就像 main 的局部变量一样)。

malloc()是一个复杂的函数,它在称为堆的复杂数据结构中内部管理可用的内存块。堆损坏意味着您损坏了该数据结构本身。分段错误意味着您在有效内存块之外的某处写入/读取。

请注意,该C标准不保证任何情况。它不能保证像堆栈这样的东西甚至存在。但是,我所知道的所有编译器都是这样做的。不过,对于某些嵌入式平台,这malloc()是一个非常简单的函数,每次分配某些内容时都会增加一个指针,并且free()什么都不做。

于 2014-04-01T05:00:52.947 回答
1

在初始化()

static void Init( world *w ) {
    obj pc;
    w->o = &pc;           //(1)
    w->o->val = 10;
    w->o->f.Doit = Read;
    w->o->f.Doit();
}

对象电脑;是函数 Init() 中的自动变量。

从 Init() 返回后,它指向的内存将无效。所以在 init() w->o 之后的 main() 中将是无效的。

你有使用 malloc

w->o = (obj *) malloc(sizeof(obj)); 

您可以在 Init() 或 main() 中执行此操作。

注意:您必须使用 free() 释放它,否则会发生内存泄漏。

于 2014-04-01T05:12:01.800 回答