gpt4 book ai didi

c - 使用结构获取垃圾数据以进行重新分配

转载 作者:太空宇宙 更新时间:2023-11-04 06:46:53 24 4
gpt4 key购买 nike

我试图创建一个结构的自扩展数组。我很幸运地使用了这种使用字符串数组的技术,但是使用结构不起作用。下面是代码:

//  SO1.h
//
#pragma once

typedef struct {
int tag;
int type;
}structure;

structure* addElement(structure* userArray, size_t* userArrayLength, size_t* userArrayAvailable, const int tag);

void listArray();

这是C代码:
#include "stdio.h"
#include "stdlib.h"
#include "malloc.h"
#include "SO1.h"

const int ARRAY_INITIAL_SIZE = 2;
const int ARRAY_ADDITIONAL_SIZE = ARRAY_INITIAL_SIZE / 2;
structure* userArray;
size_t userArrayLength = -1;
size_t userArrayAvailable = ARRAY_INITIAL_SIZE;

int main()
{
userArray = (structure*)malloc(userArrayAvailable * sizeof(structure));
if (userArray == NULL) {
printf("could not allocate memory\n");
exit(EXIT_FAILURE);
}

userArray = addElement(userArray, &userArrayLength, &userArrayAvailable, 13);
userArray = addElement(userArray, &userArrayLength, &userArrayAvailable, 14);
userArray = addElement(userArray, &userArrayLength, &userArrayAvailable, 15);
userArray = addElement(userArray, &userArrayLength, &userArrayAvailable, 16);
userArray = addElement(userArray, &userArrayLength, &userArrayAvailable, 17);
userArray = addElement(userArray, &userArrayLength, &userArrayAvailable, 18);
userArray = addElement(userArray, &userArrayLength, &userArrayAvailable, 19);
userArray = addElement(userArray, &userArrayLength, &userArrayAvailable, 20);
userArray = addElement(userArray, &userArrayLength, &userArrayAvailable, 21);
userArray = addElement(userArray, &userArrayLength, &userArrayAvailable, 22);
userArray = addElement(userArray, &userArrayLength, &userArrayAvailable, 23);
userArray = addElement(userArray, &userArrayLength, &userArrayAvailable, 24);
userArray = addElement(userArray, &userArrayLength, &userArrayAvailable, 25);
}

structure* addElement(structure* userArray, size_t* userArrayLength, size_t* userArrayAvailable, const int tag)
{
(*userArrayLength)++;
if (*userArrayLength > *userArrayAvailable) {
*userArrayAvailable += ARRAY_ADDITIONAL_SIZE;
userArray = (structure*)realloc(userArray, *userArrayAvailable * sizeof(structure));
}
if (userArray == NULL) {
printf("could not reallocate memory\n");
exit(EXIT_FAILURE);
}
userArray[*userArrayLength].tag = tag;
userArray[*userArrayLength].type = 1;

listArray();

return userArray;
}

void listArray()
{
for (size_t i = 0; i <= userArrayLength; i++) {
printf("%2d %d\n", userArray[i].tag,
userArray[i].type);
}
printf("\n");
}

完成 realloc之后,我就开始获取垃圾数据。前两个和最后一个条目都可以,但是中间的被“-842150451-842150451”替换。是输出:
13   1

13 1
14 1

13 1
14 1
15 1

13 1
14 1
-842150451 -842150451
16 1

13 1
14 1
-842150451 -842150451
-842150451 -842150451
17 1

13 1
14 1
-842150451 -842150451
-842150451 -842150451
-842150451 -842150451
18 1
:
:
:
13 1
14 1
-842150451 -842150451
-842150451 -842150451
-842150451 -842150451
-842150451 -842150451
-842150451 -842150451
-842150451 -842150451
-842150451 -842150451
-842150451 -842150451
-842150451 -842150451
-842150451 -842150451
25 1

我不认为Visual Studio与此有任何关系,但我升级到了vscommunityedition201916.1.4,我仍然得到了不好的数据。
我肯定这是个初犯的错误,但我看不出来。有人知道什么会导致这些数据损坏吗?
更新:我不知道具体的区别在哪里,但我做了由史蒂夫首脑会议,用户3121023和约翰博林格建议的改变。它几乎解决了这个问题。一切正常,直到我进入最后一个条目。(我还更改了代码以使用userArrayLength值更新.type字段。)输出如下:
:
:
:
13 0
14 1
15 2
16 3
17 4
18 5
19 6
20 7
21 8
22 9
23 10
24 11

13 0
14 1
15 2
16 3
17 4
18 5
19 6
20 7
21 8
22 9
23 10
24 11
-33686019 0

有人能告诉我为什么最后一个条目会这样出现吗?

最佳答案

您使用了一个糟糕的约定来管理您的userArrayLength变量。
一开始,人们经常会发现C的一个恼人之处是它使用了基于0的数组,但是C选择基于0的数组的原因是,它使一组非常简单、内部一致、避免错误的习惯用法成为可能,用于管理像您这样的动态数组。
首先要问的问题是,如果您的userArray最初是空的(当然是空的),为什么要将它的大小初始化为userArrayLength = -1?(我知道答案,但正如我将要展示的那样,重新安排程序的其他部分一点点就可以让我们消除这个黑客攻击。)
最好是初始化userArrayLength = 0,并重新排列程序,以便在任何时候,userArrayLength都包含数组中的元素数——不能多于或少于一个,或任何类似的混淆。
我建议进行以下更改:
初始化userArrayLength = 0
当您决定是否需要重新分配时,将>更改为>=,即测试是否*userArrayLength >= *userArrayAvailable
将数据存储到数组中时,在将新元素存储到数组中之后移动增量步骤(*userArrayLength)++
listArray中,通过写入userArrayLength,从0变为小于for (size_t i = 0; i < userArrayLength; i++)的1。
有了这些变化,你的程序对我有效。
这个练习的全部要点是安排userArrayLength变量的定义和使用是有意义的。如果它应该包含userArray的长度,那么让它实际包含userArray的确切长度,而不必总是记住它总是少一个,或者什么的。(技术术语是试图保持良好的loop invariant
如果您使用的是C语言中的数组——任何类型的数组,静态或动态分配——下面是一些您应该遵循的规则。(我不确定这些规则是否写在任何地方,有些人会说它们只是“习语”或“约定”,但是每一个有能力的C程序员都会同意,这是绝大多数时候你应该这样做的方式,除非你有一些很好的特殊理由这样做。换言之,它们也可能是规则。)
始终使用基于0的数组。
如果有一个变量跟踪数组当前使用的数量,并且数组最初为空,则始终将“count”变量初始化为0。
在数组中存储新元素时,总是在存储新元素后增加“count”变量。而且由于您使用的是基于0的数组,所以要用于存储的元素的右下标正好是您的“count”变量(不是或多或少的1或任何类似的混淆)。
如果正在使用动态分配的数组,并且正在测试是否需要在存储新元素之前增大数组,(a)在存储新元素之前执行此测试,以及(b)在“count”变量和跟踪当前分配大小的变量之间使用>=测试。(当然,跟踪当前分配大小的变量应该跟踪当前分配的大小,而不是多个或少个。)
在数组上迭代时,始终使用惯用的for(i = 0; i < N; i++循环。
如果看起来我对这些“规则”做了太大的改动,这里有一个真实的故事。我已经研究这个答案大约20分钟了,我仍然不知道原始程序中的实际错误是什么。我就是懒得想出来。我立刻注意到了不标准的用法,这使得程序太难让我思考。所以我很快改变了程序,使用“适当的”习惯用法,果然,问题解决了。
所以这显示了这些“规则”的好处。是的,我同意,盲目遵守规则是危险的。是的,我同意,弄清楚为什么使用非标准的原始程序会有问题,这可能是有指导意义的。但如果我没有时间这么做,只要简单地换成公认的习惯用法(我知道,从多年的经验来看,它总是有效的)就能神奇地让bug消失,我可以继续前进。
还有一点。我的“规则3”说“存储新元素后总是增加‘count’变量”

array[i++] = newelement;

这里要注意的关键是 userArrayLength的后缀形式正是您想要的,使用前缀形式 ++将是非常非常错误的。
(在您的例子中,因为您有一个结构数组,要分配多个成员,所以使用 array[++i]不是很自然,除非您只注意在最后一个分配中使用它。)
最后,研究如果C的数组是基于1的,那么规则是什么也是有指导意义的。我不会通过列出它们来延长这个太长的答案,但它们实际上并不太糟糕。(事实上,我可能在这个答案的开头夸大了一点,当时我对“C选择基于0的数组的原因”做了一个空洞的断言。)但是--叫我疯狂,或者说是一个毫无希望的C nurd--我觉得很有意思的是,如果你发现自己插入了基于1的数组,前缀自动递增形式--也就是说, ++--最终会成为正确的选择。

关于c - 使用结构获取垃圾数据以进行重新分配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56824721/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com