复制结构体组件会删除相同结构体的另一个组件。

3

我目前正在学习C语言,需要编写一个“动态数组”程序。

在我们提供的头文件中,struct DynArray被声明为:

struct DynamicArray
{
    unsigned int size;
    unsigned int capacity;

    int *data;
};

我已经实现了dyn_array程序中的大部分函数,那些函数最初是空的。
我的困难在于dn_append(DynamicArray *a, int elem)函数。 我所得到的唯一描述是

// =====================================================================================
//         Name:  dn_append
//  Description:  Append an element.
//
//   Parameters:  a - the array
//                elem - the new value
//      Returns:  non-zero, if the array was successfully extended
// =====================================================================================

我们有一个Makefile来编译这个程序和几个测试用例。在其中一个测试程序中,初始化了一个新的DynArray,然后添加了几个值:
int
main ( int argc, char *argv[] )
{
    DynamicArray *a1;
    int                     i;

    a1 = dn_new ( 5 );

    dn_append ( a1,  5 );
    dn_append ( a1,  7 );
    dn_append ( a1,  8 );
    dn_append ( a1, 11 );
    dn_append ( a1, 13 );
    dn_append ( a1, 15 );

    dn_set ( a1, 2, 9 );

    for ( i = 0; i < dn_size ( a1 ); i += 1 )
    {
        printf ( "%d\n", dn_get ( a1, i ) );
    }

    dn_destory ( a1 );

    return 0;
}

程序会因为分段错误而终止。
我的(有缺陷的)实现如下所示。外部的 else-分支完全混乱了,因为调试让我抓狂。(请注意,在代码示例后面我会解释有问题的那一行。)

    int
dn_append ( DynamicArray *a, int elem )
{
    printf("\n\nAppend:\n");
    if (a->size >= a->capacity) {
        printf("Array too small");
        int *dataPtr = realloc(a->data, 2*a->capacity);

        if (dataPtr != NULL) {
            a->capacity *= 2;
            a->data = dataPtr;
            a->data[a->size] = elem;
            a->size++;
        }
        else {
                return 0;
        }
    }
    else {
        int *dataPtr;
        dataPtr = a->data;

        printf("Size: %d, Capacity: %d\n", a->size, a->capacity);
        int sizeN = a->size;
        printf("Size: %d, Capacity: %d\n", a->size, a->capacity);

        //int offset = sizeN;
        int *temp;
        temp = dataPtr;// + offset;
        //dataPtr[offset] = elem;
        //printf("Data at %d is %d, should be %d\n", offset, *(a->data), elem);

        a->size++;
    }

    return 1;
} 

问题所在的代码行位于外部else语句中间:
    printf("Size: %d, Capacity: %d\n", a->size, a->capacity);
    int sizeN = a->size;
    printf("Size: %d, Capacity: %d\n", a->size, a->capacity);

当我运行程序时,这些行会被打印出来。
Size: 0, Capacity: 5
Size: 0, Capacity: 0

我甚至没有触及结构中的 capacity 组件,但它将其设置为 0,这完全毁掉了后面的程序。
在注释掉 int sizeN = a->size; 这行之后,capacity 就像应该的那样保持不变。我需要以某种方式读取 size
那么,为什么它会更改该组件呢?
一些额外信息:
DynamicArray*
dn_new ( unsigned int capacity )
{
    if (capacity > 0) {
        int *dataPtr = malloc(capacity*sizeof(int));

        if (dataPtr != NULL) {
            struct DynamicArray array = { 0, capacity, dataPtr };
            return &array;
        }
        else {
            return NULL;
        }
    }
    else {
        return NULL;
    }
}

1
请展示您的分配器函数,并尝试在valgrind和/或调试器中运行您的代码。 - Mat
dn_new看起来是什么样子? - nneonneo
valgrind 告诉我,对于每一行我使用 printf(),都会出现 Conditional jump or move depends on uninitialised value(s)Use of uninitialised value of size 8 的错误。此外,我也不知道什么是分配器函数。 - J0hj0h
1
你的分配器函数就是 dn_new() - user12205
1
这正是我所猜测的。看一下这个问题:https://dev59.com/ZWw15IYBdhLWcg3wuuCn - Mat
显示剩余2条评论
2个回答

3
在你的dn_new()函数中,你有以下代码:
if (dataPtr != NULL) {
    struct DynamicArray array = { 0, capacity, dataPtr };
    return &array;
}

在这里,array是一个局部变量; 在返回它后,它将超出作用域。您应该为其分配堆内存:

struct DynamicArray *array = malloc(sizeof *array);
array->size = 0;
array->capacity = capacity;
array->data = dataPtr;
return array;

请记得在析构函数(dn_destroy())中使用free()释放该内存。

非常感谢!我之前尝试过,但编译器报错“标量初始化程序中存在过多的元素”,所以我尝试了一个解决方法。显然,我做了一些与此不同的事情... - J0hj0h
是的,这就是问题所在。通过返回一个局部变量,它将被未来的函数调用覆盖。 - nneonneo

2

看起来你混淆了如何解释大小和容量。你把它们当作元素数量来使用,但是你使用realloc时分配的是字节数。请将代码更改为以下内容:

int *dataPtr = realloc(a->data, 2*a->capacity*sizeof(a->data[0]));

我已经将其更改为 sizeof(int)(因为我们只允许 int 值),但上述问题仍然存在。不过,非常感谢您的提示! - J0hj0h

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接