0

I have a problem, and I cannot figure out the solution for it. I have to programm some code to a µC, but I am not familiar with it.

I have to create an analysis and show the results of it on the screen of the machine. The analysis is allready done and functional. But getting the results from the analysis to the screen is my problem.

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. The linker is made that way, that every dynamic allocation ends up on the heap. But this is done in C so I cannot use "new". But everything allocated with malloc ends up on the heap automatically and that is why I need to use malloc, but I haven't used that before, so I have real trouble with it. 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.

To make it even more complicated I have to declare the variable with "extern" in the buffer.h file and have to implement it in the buffer.c file.

So my buffer.h line looks like this:

extern char * g_results[100][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?

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);
}

And then I iterate through the g_results_buffer on the screen and display the content. The problem is: it works perfect for the FIRST result only. Everything is as I wanted it.

But all other lines are empty. I checked the results-array, and all values are stored in them, so that is not the cause for the problem. Also, the values are not overwritten, it is really the 1st value.

I cannot see what it is the problem here.

My guesses are:

a) allocation with malloc isn't done correctly. Only allocating space for the 1st element? When I remove the [0][0] I get a compiler error: "assignment to expression with array type". But I do not know what that should mean.

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

I really need your help.

How do I store the results from the results-array after the 1st element into the g_results-array?

MrByte
  • 3
  • 2
  • Please provide complete code as a [mre] as well as the exact input, expected result and actual result. Not asking for and don't want a full dump of your code. Create a small but complete example that illustrates the problem. – kaylum Jan 20 '22 at 11:25
  • 1
    `so the array should have the size of 1000 byte to hold 100 results with the length of 9 and 1 terminating /0. Right?` Wrong. The array contains 100*10 **pointers** . – wildplasser Jan 20 '22 at 11:48
  • @wildplasser OK, that is not what I want or need. How can I fix that? I need a 2D array that can store one value for all 100 positions. – MrByte Jan 20 '22 at 12:20

2 Answers2

0

This is all odd, you seem to just want:

// 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?

Yes, you are, you only assigned first element g_results[0][0] to 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?

No. To allocate something on the heap you have to call malloc.

But there is no reason to use the heap, especially that you are on a microcontroller and especially that you know how many elements you are going to allocate. Heap is for unknowns, if you know that you want exactly 100 x 10 x chars, just take them.

Overall, consider reading some C books.

I do not know what that should mean.

You cannot assign to an array as a whole. You can assign to array elements, one by one.

KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • Hi, thanks for you answer. The problem with static memory allocation is, that is done in a small internal ram, which is allready almost full. I do not have the space to store it in there. But the device has a bigger external ram and the linker uses the external ram for dynamic memory allocation. That is why I need to do it dynamically, to get it into the external ram. – MrByte Jan 21 '22 at 12:08
0

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.

A “global array“ and “the larger heap” are different things. C does not have a true global name space. It does have objects with static storage duration, for which memory is reserved for the entire execution of the program. People use the “heap” to refer to dynamically allocated memory, which is reserved from the time a program requests it (as with malloc) until the time the program releases it (as with free).

Variables declared outside of functions have file scope for their names, external or internal linkage, and static storage duration. These are different from dynamic memory. So it is not clear what memory you want: static storage duration or dynamic memory?

“Heap” is a misnomer. Properly, that word refers to a type of data structure. You can simply call it “allocated memory.” A “heap” may be used to organize pieces of memory available for allocation, but it can be used for other purposes, and the memory management routines may use other data structures.

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

The linker links object modules together. It has nothing to do with the heap.

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

When you allocate memory, it does not end up on the heap. The heap (if it is used for memory management) is where memory that has been freed is kept until it is allocated again. When you allocate memory, it is taken off of the heap.

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

This is unclear. Perhaps you mean there is some display device that you must communicate with by providing strings of characters.

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.

That would have been useful at the beginning of your post.

So my buffer.h line looks like this:

extern char * g_results[100][10];

That declares an array of 100 arrays of 10 pointers to char *. So you will have 1,000 pointers to strings (technically 1,000 pointers to the first character of strings, but we generally speak of a pointer to the first character of a string as a pointer to the string). That is not likely what you want. If you want 100 strings of up to 10 characters each (including the terminating null byte in that 10), then a pointer to an array of 100 arrays of 10 characters would suffice. That can be declared with:

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

However, when working with arrays, we generally just use a pointer to the first element of the array rather than a pointer to the whole array:

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?

That space does suffice for 100 instances of 10-byte strings. It would not have worked with your original declaration of extern char * g_results[100][10];, which would need space for 1,000 pointers.

However, having changed g_results to extern char (*g_results)[10];, we must now assign the address returned by malloc to g_results, not to g_results[0][0]. We can allocate the required space with:

g_results = malloc(100 * sizeof *g_results);

Alternately, instead of allocating memory, just use static storage:

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); }

There is no need to use buffer; you can send the snprintf results directly to the final memory.

Since g_results is an array of 100 arrays of 10 char, g_results[i] is an array of 10 char. When an array is used as an expression, it is automatically converted to a pointer to its first element, except when it is the operand of sizeof, the operand of unary &, or is a string literal used to initialize an array (in a definition). So you can use g_results[i] to get the address where string i should be written:

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

Some notes about this:

  • We see use of the array both with automatic conversion and without. The argument g_results[i] is converted to &g_results[i][0]. In sizeof g_results[i], sizeof gives the size of the array, not a pointer.
  • The buffer length passed to snprintf does not need to be reduced by 1 for allow for the terminating null character. snprintf handles that by itself. So we pass the full size, sizeof g_results[i].

But all other lines are empty.

That is because your declaration of g_results was wrong. It declared 1,000 pointers, and you stored an address only in g_results[0][0], so all the other pointers were uninitialized.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • This was very helpful and fixed my problem. Thank you very much. Just to clarify a few things: I am not a µC programmer, and I can only believe what I've been told. They told me, that the device has a small internal ram (few KB) and one external ram (several MB) and that the internal RAM was used for static memory allocation and external for dynamic and they called internal RAM "Stack" and external "Heap". I have to programm it as static as possible - so that the machine does the exakt same thing every time. And you guessed right about the display. It uses an API acepting only char arrays. – MrByte Jan 21 '22 at 11:56