简体   繁体   中英

Using strcpy on a 2D char array allocated with malloc

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?

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.

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 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM