在使用 malloc 分配的二维字符数组上使用 strcpy

Using strcpy on a 2D char array allocated with malloc

我有一个问题,我想不出解决办法。我必须编写一些代码到 µC,但我不熟悉它。

我必须创建一个分析并将其结果显示在机器的屏幕上。分析已经完成并且可以正常运行。但是把分析结果放到屏幕上是我的问题。

我必须将所有结果存储在一个全局数组中。由于堆栈在机器上真的很有限,我不得不把它带到更大的堆上。链接器就是这样制作的,每个动态分配都在堆上结束。但这是在 C 中完成的,所以我不能使用“new”。但是用 malloc 分配的所有东西都会自动在堆上结束,这就是我需要使用 malloc 的原因,但我以前没有用过,所以我真的遇到了麻烦。屏幕的问题是,它只接受字符数组。

总而言之:我必须创建一个全局二维字符数组来保存最多 100 个位置的结果,并且我必须使用 malloc 为其分配内存。

为了让它变得更加复杂,我必须在 buffer.h 文件中用“extern”声明变量,并且必须在 buffer.c 文件中实现它。

所以我的 buffer.h 行看起来像这样:

extern char * g_results[100][10];

在 buffer.c 我正在使用:

g_results[0][0] = malloc ( 100 * 10 )

每个字符为 1 个字节,因此数组的大小应为 1000 字节以容纳 100 个结果,长度为 9,1 以 /0 结尾。对吗?

现在我尝试在 strcpy 的帮助下将结果存储到这个数组中。 我在分析结束时在 for 循环中执行此操作。

for (int i = 0; i < 100, i++)
{
  // Got to convert it to text 1st, since the display does not accept anything but text.
  snprintf(buffer, 9, "%.2f", results[i]);
  strcpy(g_results[i][0], buffer);
}

然后我在屏幕上遍历 g_results_buffer 并显示内容。问题是:它仅适用于第一个结果。一切如我所愿

但是其他所有行都是空的。我检查了结果数组,所有值都存储在其中,所以这不是问题的原因。另外,值没有被覆盖,它真的是第一个值。

我看不出这是什么问题。

我的猜测是:

a) malloc 的分配没有正确完成。只为第一个元素分配 space?当我删除 [0][0] 时,出现编译器错误:“赋值给具有数组类型的表达式”。但是我不知道那是什么意思。

b) (完全)错误地使用了指针。有没有一种方法可以将该数组声明为非指针,但仍在堆上?

我真的需要你的帮助。

如何将结果数组中第一个元素之后的结果存储到 g_results-array 中?

这很奇怪,你似乎只是想要:

// array of 100 arrays of 10 chars
char g_results[100][10];

for (int i = 0; i < 100, i++) {
   // why snprintf+strcpy? Just write where you want to write.
   snprintf(g_results[i], 10, "%.2f", results[i]);
   //                                  ^^^^^^^^ has to be float or double
   //                     ^^ why 9? The buffer has 10 chars.
}

Only allocating space for the 1st element?

是的,您只是将第一个元素 g_results[0][0] 分配给 malloc ( 100 * 10 )

wrong usage of the pointers. Is there a way I can declare that array as a non-pointer, but still on the heap?

没有。要在堆上分配一些东西,你必须调用 malloc.

但是没有理由使用堆,尤其是你在微控制器上,尤其是你知道你要分配多少元素。堆是为未知数准备的,如果你知道你想要恰好 100 x 10 x 个字符,就拿走它们。

总体而言,考虑阅读 some C books

I do not know what that should mean.

不能对整个数组进行赋值。您可以一个一个地分配给数组元素。

I have to store all results in a global array. Since the stack is really limited on the machine, I have to bring it to the larger heap.

“全局数组”和“较大的堆”是不同的东西。 C 没有真正的全局名称 space。它确实有具有静态存储持续时间的对象,为此程序的整个执行保留内存。人们使用“堆”来指代动态分配的内存,从程序请求它(如malloc)到程序释放它(如free)期间一直保留。

在函数外部声明的变量的名称、外部或内部链接以及静态存储持续时间具有文件范围。这些不同于动态内存。所以不清楚你要什么内存:静态存储时长还是动态内存?

“堆”用词不当。正确地说,这个词指的是一种数据结构。您可以简单地将其称为“分配的内存”。 “堆”可用于组织可供分配的内存块,但它可用于其他目的,内存管理例程可使用其他数据结构。

The linker is made that way, that every dynamic allocation ends up on the heap.

链接器将目标模块链接在一起。跟堆没关系。

But everything allocated with malloc ends up on the heap automatically and that is why I need to use malloc,…

分配内存时,它不会在堆上结束。堆(如果它用于内存管理)是在再次分配之前保留已释放内存的地方。当您分配内存时,它会从堆中取出。

The problem with the screen is, it accepts only char arrays.

这还不清楚。也许你的意思是有一些显示设备,你必须通过提供字符串来与之通信。

In summaray: I have to create a global 2D char array holding the results of up to 100 positions and I have to allocate the memory for it using malloc.

这在您 post 的开头会很有用。

So my buffer.h line looks like this:

extern char * g_results[100][10];

这声明了一个包含 100 个数组的数组,每个数组包含 10 个指向 char * 的指针。因此,您将有 1,000 个指向字符串的指针(从技术上讲,有 1,000 个指向字符串第一个字符的指针,但我们通常将指向字符串第一个字符的指针称为指向字符串的指针)。这不太可能是你想要的。如果您想要 100 个字符串,每个字符串最多 10 个字符(包括那 10 个中的终止空字节),那么指向 100 个 10 个字符数组的数组的指针就足够了。可以声明为:

extern char (*g_results)[100][10];

但是,在处理数组时,我们通常只使用指向数组第一个元素的指针,而不是指向整个数组的指针:

extern char (*g_results)[10];

In the buffer.c I am using:

g_results[0][0] = malloc ( 100 * 10 )

Each char is 1 byte, so the array should have the size of 1000 byte to hold 100 results with the length of 9 and 1 terminating /0. Right?

space 足以满足 100 个 10 字节字符串的实例。它不适用于您最初的 extern char * g_results[100][10]; 声明,它需要 space 来获得 1,000 个指针。

但是,将 g_results 更改为 extern char (*g_results)[10]; 后,我们现在必须将 malloc 返回的地址分配给 g_results,而不是 g_results[0][0]。我们可以分配所需的 space 与:

g_results = malloc(100 * sizeof *g_results);

或者,不分配内存,只使用静态存储:

char g_results[100][10];

Now I try to store the results into this array with the help of strcpy. I am doing this in a for loop at the end of the analysis.

for (int i = 0; i < 100, i++) { // Got to convert it to text 1st, since the display does not accept anything but text. snprintf(buffer, 9, "%.2f", results[i]); strcpy(g_results[i][0], buffer); }

不需要使用buffer;您可以将 snprintf 结果直接发送到最终存储器。

由于g_results是10个char的100个数组,g_results[i]是10个char的数组。当数组用作表达式时,它会自动转换为指向其第一个元素的指针,除非它是 sizeof 的操作数、一元 & 的操作数或使用的字符串文字初始化数组(在定义中)。所以可以用g_results[i]得到字符串i应该写的地址:

snprintf(g_results[i], sizeof g_results[i], "%.2f", results[i]);

关于此的一些说明:

  • 我们看到在自动转换和不自动转换的情况下都使用了数组。参数 g_results[i] 被转换为 &g_results[i][0]。在 sizeof g_results[i] 中,sizeof 给出数组的大小,而不是指针。
  • 传递给 snprintf 的缓冲区长度不需要减 1 以允许终止空字符。 snprintf 自行处理。所以我们传递全尺寸,sizeof g_results[i].

But all other lines are empty.

那是因为你的g_results声明是错误的。它声明了 1,000 个指针,而你只在 g_results[0][0] 中存储了一个地址,因此所有其他指针都未初始化。