Length of size_t not correct? - c

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

Related

Strlen() of allocated pointer

I create a buffer like this but I don't give it content. Then I try to view strlen() of this block memory.
int size = 24;
char *c;
c = (char *)malloc(size);
printf("%d\n", strlen(c));
What I get is not 24 but 40. I try to view the value from c[40] to c[47] and I always get \0 but after c[47] is not null anymore.
When I set size = 18, the result isn't 40 anymore. It's 32. And values from c[32] to c[47] are all \0.
When I set size = 7, the result is 24 and values form c[24] to c[47] are all \0.
I know using strlen for an array like this is not able to give me the size I used in malloc() function.
I just wonder why this happened and when we change the value of size, how the result change? Is there anything we can deal with using this?
Edit: It seem like everyone think the result is unpredictable. It's the fact that it's always a multiple of 8 and when we increase the size, there is a limit where the result increase. We can determine exactly the value of size that make the result change and it doesn't change despite how many times we test. Does it depend on OS not just C language or compiler? Why 8 is chosen?
The memory you allocated isn't initialized. Passing it to strlen, a function that expects a NUL terminated string, has undefined behavior. So you can get whatever, you don't even have to get any result.
There is not built-in way in C to know the exact size of an allocated block of memory.
You should read the documentation, strlen() is for the length of strings. Without much detail I will tell you one thing,
There is no way to get the length of a pointer dynamically, so your only option is to store it and use it later.
A simple elegant method, is to use a struct for that, where you store the size and use it every time you need.
struct pointer_type {
void *pointer;
size_t allocated_size;
};
As for the "What i get is not 24 but 40" question,
Your pointer, is uninitialized. This causes what is known as undefined behavior because the way strlen() works is by dereferencing the pointer and counting characters until a given character occurs, something like
int strlen(const char *const str)
{
int count = 0;
while (*(str++) != '\0') ++count;
return count;
}
and since your pointer points to random garbage, this will not work right and the returned value is unpredictable.

Size needed to construct a char* out of wchar_t* in C

I'm trying to convert a wchar_t* to char* and my memory wasting solution was
char *wstrtostr(const wchar_t *text) {
size_t size = wcslen(text)*sizeof(wchar_t)+1;
char *sa = malloc(size);
wcstombs(sa,text,size);
return sa;
}
A character might be single-byte or multi-byte and wcslen will count them regardless of their equivalent size as chars.
The question is how can we determine the equivalent char size for a wchar so that we can build an alternative to wcslen for this specific problem and consequently determine the size required to build our char pointer?
To answer what you asked, you can repeatedly call wcstombs with bytes slowly increasing until you get something stored. Not sure however how efficient that is for what you seem to want to do though. Maybe you would want a different approach:
Allocate some memory. Call wcsrtombs. If src doesn't end up being NULL then you ran out of memory so realloc and call wcsrtombs again from where it left off last time.
Depending on your data you can build a heuristic for how much memory to allocate in the first place so reallocing is rare.
Update: It turns out that if you are running under Linux, and don't require portability or C99 compliance, there exists another method. If you call wcstombs with NULL as the destination then it will return the number of bytes that would have been required. You can then alloc this number of bytes and call wcstombs again. Which approach will be better will depend on your circumstances, specifically I imagine the length of the string and how good your heuristic is at guessing the correct length first go. Also, just to reiterate, if you code needs to be portable then this is a non-standard API. Thanks to melpomene for the pointer.
Second update: wcsrtombs does support, according to C99, having its dest pointer set to NULL to get the length required for the output buffer. Thanks to Story Teller for that. So you could call that once with NULL, and then a second time with an appropriately sized buffer.

How to get sizeof of array in following case:

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.

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:

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