How to get sizeof of array in following case: - c

I have written a code in C as below,
#define SOB1 10
#define SOB2 20
char Buffer_1[SOB1];
char Buffer_2[SOB2];
char * CommandArray[2] = {Buffer_1,Buffer_2};
How do I get size of Buffer_1 and Buffer_2 indirectly through CommandArray?
More precisely I should know value of SOB1 or SOB2 based on the index of char * CommandArray[2]

Without storing the information yourself, you can't.

You can't do a sizeof in this case, since the array metadata has been lost when you started accessing it via pointer. You would need to use sizeof(Buffer_1) or sizeof(Buffer_2).
Another option (if you don't have access to Buffer_1 and Buffer_2) would be to store a second size variable that is equal to the #define for each Buffer, and use that. Since the array doesn't contain a string, you also can't check for \0 or similar, so you need to be very careful for buffer overruns when using them (another reason to store a size variable).

You can just assign it to the pointer. You need to allocate memory using calloc or malloc.

Related

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

When should we use a char pointer ( char *) over a char array (char [] )? [duplicate]

This question already has answers here:
Difference between using character pointers and character arrays
(9 answers)
Closed 2 years ago.
Is there any situations where one type is preferred over the other?
The only thing I can think of is...
a pointer uses 4 bytes, and a char array's size depends on the length of the string, so if you have a really big string,it's beneficial to use a char pointer instead in order save memory example: if your passing strings around through arguments.
but in terms of string manipulation, which is preferred?
example:
char *hello_pointer = malloc(sizeof(char) * 20);
char hello_array[20];
strcat(hello_pointer, "hello pointer");
strcat(hello_array, "hello array");
is there a preference for one over the other in this case?
Difference is that with malloc() or new you will get memory allocated on the heap and this is slower and will not get destroyed with the end of the scope.
char hello_array[20] will be allocated on the stack and will be removed with the stack frame.
Also, with malloc(sizeof(char) * 20) you don't just allocate one pointer but memory block to handle 20 chars. Size will be the same.
This isn't about "saving memory", this is about dynamic allocation versus a fixed-length buffer.
In your example you're assuming that your data will be no more than 19 characters. This could be a huge mistake. The difference between char* x and char x[20] is not really relevant until you want to use that data outside the scope it was declared in.
A char* x allocated using malloc will persist outside the function's scope. A char[20] will not, you need to copy it before it gets recycled.
So in comparison, a buffer like char x[20]:
effectively zero cost to create
must be conservatively sized to avoid consuming too much stack space
will need to be NUL terminated when declared, like char x[20] = { 0 }
cannot be used once they fall out of function scope
Whereas char* x:
has a small initialization cost
must be released with free when no longer used or program will leak memory
can be used outside of function scope
must be initialized before use, may contain junk data
You're 100% responsible for:
properly initializing your character buffers
ensuring that the buffers are the correct size for the data you intend to store in them
informing any functions manipulating this buffer what the buffer's size is, or in some cases, what the remaining size is
NUL terminating any buffers you manipulate where you may overwrite the terminator
releasing any memory allocated dynamically
Typically you'll see fixed-length buffers used for things like reading in and parsing a file where you do so carefully and with awareness of your buffer's size limits. Reading functions that take a length argument are the ones you want to use even though there are some like gets() which are commonly shown. Those can and will create huge buffer-overflow bugs.
In C++ it's easy to avoid this mess and just use std::string which deals with all of this for you automatically.

malloc(sizeof(s)) allocates less memory than expected?

hey i am having problems using the sizeof operator in malloc. For example see the foll. code-
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char * copy(char *s)
{
char *t=malloc(sizeof(s));
char *ptr=s;
int i=0;
do
{
t[i++]=*ptr++;
}
while(*ptr!='\0');
return t;
}
int main()
{
char *s="hello adsjahsjkdhjkashdkjaskdasldjlasjdlajsdlkjaslkdjalsjdlasjdljasdljasdkljklsdjlasdsadasdasd";
char *b=copy(s);
printf("%s\n",b);
free(b);
return 0;
}
on ideone, it gives the error:-
* glibc detected ./prog: free(): invalid next size (fast): 0x09bcf008 **
But when i replace malloc(sizeof(s)) with malloc(strlen(s)+1) , the program works perfectly. So whats the problem?
NOTE:this is just a small prog i created to demonstrate the problem i was having in another code.
The operator sizeof doesn't do what you want on pointers. It yields the size of the pointer on your machine (which will be something like 4 or 8).
You can think of it this way: the array decays to a pointer when passed to a function and the information regarding its size is "lost".
Also note your loop doesn't fill in the 0 terminator.
You should use strlen instead of sizeof in the copy function:
char * copy(char *s)
{
char *t=malloc(strlen(s) + 1);
char *ptr=s;
int i=0;
do
{
t[i++]=*ptr++;
}
while(*ptr!='\0');
return t;
}
The problem is that sizeof does not return the value you need, that function will return the size of the char *s (probably 4 or 8 -> bytes used to storage that pointer). Check the documentation links to understand more clearly.
One more thing, if you are doing that in order to practice your C skills is OK but if you are not, you will probable just want to use the strcpy function.
Hope it helps.
sizeof(s) returns the size of char *s which is 4 (on 32 bit) or 8 (on 64 bit) systems.
arrays and strings with size information gets degenerated to pointers losing its size attributes when it is passed as a parameter to a function
So when you are calculating the size of the parameter s it either returns 32/64 based on your bitness.
instead of sizeof, you should actually do strlen and add one to it to accommodate the null character.
instead of
char *t=malloc(sizeof(s));
try
char *t=malloc(strlen(s)+1);
Please note:
There are other design issues with your code
When passing a pointer argument which is not supposed to change, you should declare it const.
Generally returning an address of a locally generated heap storage is not a good practice and is the major cause of memory leak, if cal-lee ever forgets to free the storage. Instead pass it as a non-const parameter to the function.
sizeof returns the size of the pointer (usually 4 or 8 bytes), not the size of the pointed-to object. (There is no way to get at the latter information. sizeof is effectively a compile-time constant, by the way.)
s is a pointer to char, so malloc(sizeof(s)) allocates space for one pointer to char -- typically 2-8 bytes, most often 4 bytes. As it stands, it'll always allocate this fixed amount of space, regardless of the length of string you passed in. In your test, you're passing a much longer string than that, so you overflow the buffer you allocated.
You're already given the correct answer: under the circumstances, strlen is the right function to find the size.
malloc is declared in , so we #include that header in any program that calls malloc. A ``byte'' in C is, by definition, an amount of storage suitable for storing one character, so the above invocation of malloc gives us exactly as many chars as we ask for. We could illustrate the resulting pointer like this:

Length of size_t not correct?

theMessageMaxLength keeps giving me a value of 4 even if the length is larger than 4. Why is this happening and how do I fix it? It is of type size_t and I don't have it declared anywhere, rather it is just a value being passed in as such:
place_value(int task, struct PDB *llist, char *theMessage, size_t theMessageMaxLength)
The above method is being called as follows:
place_value(task, llist, theMessage, sizeof(theMessage));
I'm assuming this is where the length gets set to 4, however, shouldn't it be set to something larger if my message is larger? How would I increase the size so it's not just 4...?
and then used like this within the function it is being passed into:
strncpy(llist->data1, theMessage, theMessageMaxLength);
llist->data1[theMessageMaxLength] = '\0';
It looks like you're confusing sizeof() with strlen().
sizeof(theMessage) will only give you the size of a char* which is a pointer - (4 bytes in your case). If you want the length of the string, you'll need to use strlen(theMessage) instead.
place_value(task, llist, theMessage, strlen(theMessage));
sizeof(theMessage) is literally same as sizeof(char *). Perhaps you were confused with the situation below:
char theMessage[1024];
/* ... some code here ...*/
printf("sizeof(theMessage): %zd\n", sizeof(theMessage));
If you allocate memory for theMessage, then you should provide its size.
EDIT: As a side node, you may be interested in strndup which allocates memory automatically and appends a NULL character at the end to the destination string. But of course, you'll have to be careful and don't forget to free it.
You are measuring the size of a pointer, which is 4 (on 32-bit platform).

C: using sprintf and strncpy inserting data into an array of pointers

I have a structure that has an array of pointers. I would like to insert into the array digits in string format, i.e. "1", "2", etc..
However, is there any difference in using either sprintf or strncpy?
Any big mistakes with my code? I know I have to call free, I will do that in another part of my code.
Many thanks for any advice!
struct port_t
{
char *collect_digits[100];
}ports[20];
/** store all the string digits in the array for the port number specified */
static void g_store_digit(char *digit, unsigned int port)
{
static int marker = 0;
/* allocate memory */
ports[port].collect_digits[marker] = (char*) malloc(sizeof(digit)); /* sizeof includes 0 terminator */
// sprintf(ports[port].collect_digits[marker++], "%s", digit);
strncpy(ports[port].collect_digits[marker++], digit, sizeof(ports[port].collect_digits[marker]));
}
Yes, your code has a few issues.
In C, don't cast the return value of malloc(). It's not needed, and can hide errors.
You're allocating space based on the size of a pointer, not the size of what you want to store.
The same for the copying.
It is unclear what the static marker does, and if the logic around it really is correct. Is port the slot that is going to be changed, or is it controlled by a static variable?
Do you want to store only single digits per slot in the array, or multiple-digit numbers?
Here's how that function could look, given the declaration:
/* Initialize the given port position to hold the given number, as a decimal string. */
static void g_store_digit(struct port_t *ports, unsigned int port, unsigned int number)
{
char tmp[32];
snprintf(tmp, sizeof tmp, "%u", number);
ports[port].collect_digits = strdup(tmp);
}
strncpy(ports[port].collect_digits[marker++], digit, sizeof(ports[port].collect_digits[marker]));
This is incorrect.
You have allocated onto collect_digits a certain amount of memory.
You copy char *digits into that memory.
The length you should copy is strlen(digits). What you're actually copying is sizeof(ports[port].collect_digits[marker]), which will give you the length of a single char *.
You cannot use sizeof() to find the length of allocated memory. Furthermore, unless you know a priori that digits is the same length as the memory you've allocated, even if sizeof() did tell you the length of allocated memory, you would be copying the wrong number of bytes (too many; you only need to copy the length of digits).
Also, even if the two lengths are always the same, obtaining the length is this way is not expressive; it misleads the reader.
Note also that strncpy() will pad with trailing NULLs if the specified copy length is greater than the length of the source string. As such, if digits is the length of the memory allocated, you will have a non-terminated string.
The sprintf() line is functionally correct, but for what you're doing, strcpy() (as opposed to strncpy()) is, from what I can see and know of the code, the correct choice.
I have to say, I don't know what you're trying to do, but the code feels very awkward.
The first thing: why have an array of pointers? Do you expect multiple strings for a port object? You probably only need a plain array or a pointer (since you are malloc-ing later on).
struct port_t
{
char *collect_digits;
}ports[20];
You need to pass the address of the string, otherwise, the malloc acts on a local copy and you never get back what you paid for.
static void g_store_digit(char **digit, unsigned int port);
Finally, the sizeof applies in a pointer context and doesn't give you the correct size.
Instead of using malloc() and strncpy(), just use strdup() - it allocates the buffer bin enough to hold the content and copies the content to the new string, all in one shot.
So you don't need g_store_digit() at all - just use strdup(), and maintain marker on the caller's level.
Another problem with the original code: The statement
strncpy(ports[port].collect_digits[marker++], digit, sizeof(ports[port].collect_digits[marker]));
references marker and marker++ in the same expression. The order of evaluation for the ++ is undefined in this case -- the second reference to marker may be evaluated either before or after the increment is performed.

Resources