Why does realloc not update the size of my array? - c

I am trying to read in user input then parse it to tokens using strtok().
Here is my code:
int main(){
char argv[200];
char** tokenList = NULL;
printf("shell>>");
scanf("%[^\n]%*c", argv);
int len = 0;
char* line = strtok(argv, " ");
while (line != NULL) {
printf("%s\n", line);
printf("%lu\n", sizeof(tokenList) + (sizeof(char*) * (len+1)));
tokenList = realloc(tokenList, sizeof(tokenList) + (sizeof(char*) * (len+1)));
printf("%lu\n", sizeof(tokenList));
char* p = malloc(sizeof(char) * (sizeof(line) + 1));
p=line;
tokenList[len] = p;
len++;
line = strtok(NULL, " ");
}
The three print statements are for my debugging purposes and I cannot figure out what is going on. When I run the shell and enter "a b c" my output is the following:
a
16
8
b
24
8
c
32
8
Why is the size of my array tokenList not getting updated by the realloc call?

You are using sizeof operator on a pointer. This yields the size in bytes of the pointer, not of the length of data pointed to. It's easy to imagine why, since tokenList is just a variable that stores an address, you obtain the size of the variable, not of what the variable points to.
In C, arrays allocated on heap doesn't know their size, the developer must take care of knowing it and storing/updating it when necessary somewhere.
The only case in which you are allowed to use directly sizeof is when an array is declared with static or local storage (and not on heap). In this circumstance sizeof return the total length in bytes of the array, so that you can do sizeof(array) / sizeof(array[0]) to obtain the element count.

Related

sizeof Calloc producing wrong output [duplicate]

Can someone explain to me why my call to malloc with a string size of 6 returns a sizeof of 4 bytes? In fact, any integer argument I give malloc I get a sizeof of 4. Next, I am trying to copy two strings. Why is my ouput of the copied string (NULL)?
Following is my code:
int main()
{
char * str = "string";
char * copy = malloc(sizeof(str) + 1);
printf("bytes allocated for copy: %d\n", sizeof(copy));
while(*str != '\0'){
*copy = *str;
str++;
copy++;
}
copy = '\0';
printf("%s\n", copy);
}
sizeof(str) returns the size of a pointer of type char*. What you should do is to malloc the size of the string it self:
char * copy = malloc(strlen(str) + 1);
Also, these lines:
while(*str != '\0'){
*copy = *str;
str++;
copy++;
}
copy = '\0';
Can be rewritten easily in C like this:
while(*copy++ = *str++);
First you should understand that sizeof(xxx) where xxx is any left value expression (a variable) is always equivalent to do sizeof(type of xxx). Hence what is really doing your sizeof(str) is returning the size of a char *, that is the size of any other pointer. On a 32 bits architecture you'll get 4, on a 64 bits architecture it'll be 8, etc.
So, as others also explained you have to know the length of the string you want to allocate, and then add 1 to store the terminal \0, C implicitly use to put at the end of strings.
But to do what you want (copy a string and allocate necessary space) it will be more simple and more efficient to use strdup, that does exactly that : a malloc and a strcopy.
You should also not forget to free space you allocated yourself (using malloc, calloc, strdup or any other allocation function). In C it won't go away when allocated variable go out of scope. It will stay used until the end of the program. That's what you call a memory leak.
#include <string.h> /* for strdup, strlen */
#include <stdio.h> /* for printf */
int main()
{
char * str = "string";
char * copy = strdup(str);
printf("bytes at least allocated for copy: %d\n", strlen(copy)+1);
printf("%s\n", copy);
free(copy);
}
One last point : I changed message to bytes at least allocated because you don't really know the size allocated when calling malloc. It quite often allocates a slighly more space that what you asked for. One reason is that in many memory managers free blocks are linked together using some hidden data structure and any allocated block should be able to contain at least such structure, another is that allocated blocks are always aligned in such a way to be compatible with any type alignment.
Hope it will help you to understand C a little better.
You're getting the size of the str pointer (4 bytes), not what it's pointing to?
sizeof(str) returns the space necessary to store the pointer to the string, not the string itself. You can see the size of the string with strlen(str) for example.
Then you affect your copy pointer to an integer which has the value 0 (the character '\0'). It is the same as copy = NULL, which is what the printf() function shows you.
sizeof() returns the size of the actual type of the variable. So, when you define your type as char *, it returns the size of a pointer.
But if you made your variable an array, sizeof would return the size of the array itself, which would do what you want to do:
char *ptr = "moo to you";
char arr[] = "moo to you";
assert(sizeof(ptr) == 4); // assuming 32 bit
assert(sizeof(arr) == 11); // sizeof array includes terminating NUL
assert(strlen(arr) == 10); // strlen does not include terminating NUL
To tackle your second questions, by executing the statement copy++ you have changed the value of copy (that is, the address in memory that holds a char array) so that by the time you print it out, it is pointing at the end of the array rather than the beginning (the value returned by malloc()). You will need an extra variable to update the string and be able to access the beginning of the string:
Edit to repair malloc/sizeof issue - thanks CL.
char * str = "string";
/* char * copy = malloc(sizeof(str) + 1); Oops */
char * copy = malloc(strlen(str) + 1);
char * original_copy = copy;
printf("bytes allocated for copy: %d\n", sizeof(copy));
while(*str != '\0'){
*copy = *str;
str++;
copy++;
}
copy = '\0';
printf("%s\n", original_copy);
sizeof() returns you the size of the pointer and not the amount of allocated bytes. You don't need to count the allocated bytes, just check if the returned pointer is not NULL.
The line copy = '\0'; resets the pointer and makes it NULL.
You can use:
size_t malloc_usable_size (void *ptr);
instead of : sizeof
But it returns the real size of the allocated memory block! Not the size you passed to malloc!

Copy a string to a malloc'd array of strings

I thought I understood the answer to this question but I don't. I understand the first result but I still don't know how to do the copy correctly. I tried the following code:
// TstStrArr.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <string.h>
#include <malloc.h>
int main()
{
char ** StrPtrArr;
char InpBuf0[] = "TstFld0";
char InpBuf1[] = "TstFld1";
StrPtrArr = (char **)malloc(2 * sizeof(char *));
StrPtrArr[0] = (char *)malloc(10 + 1);
printf("inpbuf=%s sizeof=%2d ", InpBuf0, sizeof(StrPtrArr[0]));
strncpy_s(StrPtrArr[0], sizeof(StrPtrArr[0]), InpBuf0, _TRUNCATE);
printf("strptrarr=%s\n", StrPtrArr[0]);
StrPtrArr[1] = (char *)malloc(10 + 1);
printf("inpbuf=%s sizeof=%2d ", InpBuf1, sizeof(*StrPtrArr[1]));
strncpy_s(*StrPtrArr[1], sizeof(*StrPtrArr[1]), InpBuf1, _TRUNCATE); // error here
printf("*strptrarr=%s\n", StrPtrArr[1]);
free(StrPtrArr[0]);
free(StrPtrArr[1]);
free(StrPtrArr);
return 0;
}
The result I got was:
inpbuf=TstFld0 sizeof= 4 strptrarr=Tst
inpbuf=TstFld1 sizeof= 1
and the following error:
Exception thrown: write access violation.
destination_it was 0xFFFFFFCD.
The result I thought I'd get was either of the following:
inpbuf=TstFld1 sizeof=11 *strptrarr=TstFld1
inpbuf=TstFld1 sizeof= 1 *strptrarr=T
I understand the first copy copied the input buffer to the 4 byte pointer which was incorrect. I thought the second copy would copy the input buffer to the value of the dereferenced pointer of a size of 11 but it didn't. I'm guessing the copy was to the first character of the string in the array. I don't understand memory enough to know the significance of the address 0xFFFFFFCD but I guess it's in read-only memory thus causing the error.
What is the correct way to do the copy?
(I don't think it matters, but I'm using VS 2015 Community Edition Update 3.)
Why
strncpy_s(*StrPtrArr[1], sizeof(*StrPtrArr[1]), InpBuf1, _TRUNCATE);
?
*StrPtrArr[1] should be StrPtrArr[1] because StrPtrArr is of type char** and you need char* here.
and sizeof(*StrPtrArr[1]) - is quite strange....
actually sizeof(StrPtrArr[1]) also cannot provide correct value.
You should remember size of allocated memory and then use it like:
size_t arrSize = 10 + 1;
StrPtrArr[1] = (char *)malloc(arrSize);
. . .
strncpy_s(StrPtrArr[1], arrSize, InpBuf1, _TRUNCATE);
The problem is that you are using sizeof when deciding how many characters to copy. However, you allocated a fixed number of characters which is not known to sizeof operator: sizeof StrPtrArr[0] is equal to the size of char pointer on your system (four bytes, judging from the output), not 10 + 1. Hence, you need to specify that same number again in the call to secure string copy.
It isn't as complicated as people seem to think.
char* array = calloc( n, sizeof(array[0]) ); // allocate array of pointers
// assign a dynamically allocated pointer:
size_t size = strlen(str) + 1;
array[i] = malloc(size);
memcpy(array[i], str, size);
I intentionally used calloc during allocation, since that sets all pointers to NULL. This gives the advantage that you can harmlessly call free() on the pointer, even before it is assigned to point at a string.
This in turn means that you can easily (re)assign a new string to an index at any time, in the following way:
void str_assign (char** dst, const char* src)
{
size_t size = strlen(src) + 1;
free(*dst);
*dst = malloc(size);
if(*dst != NULL)
{
memcpy(*dst, src, size);
}
}
...
str_assign(&array[i], "something");

Can't determine why sizeof shows different value

I am making a program that concatenates two strings given by user. Everything is fine, but I don't know why the program shows that the sizeof of the final result is 8-bit long. Doesn't matter how long the strings are, it always shows 8. I guess, that it is the size of char, but I would like to know why it acts this way. This is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* concatenate(char *fir, char *sec)
{
int firLen = strlen(fir);
int secLen = strlen(sec);
int len = firLen + secLen + 1;
int i = 0,c=0;
int *wsk = &i;
char *result = (char *)malloc(len*sizeof(char));
while (fir[i]!='\0')
{
result[i]=fir[i];
(*wsk)++;
}
while (sec[c]!='\0')
{
result[i]=sec[c];
(*wsk)++;
c++;
}
result[len-1] = '\0';
return result;
}
int main(int argc, char **argv)
{
char *first, *second, *output;
int size1, size2;
printf("How long will your first string be: ");
scanf("%d", &size1);
first = (char *) malloc ((1+size1)*sizeof(char));
if (!first)
{
puts("\nError. Can't allocate memory!");
abort();
}
printf("How long will your second string be: ");
scanf("%d", &size2);
second = (char *) malloc ((size2+1)*sizeof(char));
if (!second)
{
puts("\nError. Can't allocate memory!");
abort();
}
printf("\nPlease, type in the first string: ");
scanf("%s",first);
printf("\nPlease, type in the second string: ");
scanf("%s",second);
output = (char *)malloc((size1+size2+1)*sizeof(char));
output = concatenate(first, second);
printf("\nConcatenation of the strings: %s", output);
printf("\n%d", sizeof(output));
free(first);
free(second);
free(output);
getchar();
return 0;
}
Don't use sizeof to determine string length, use the strlen function, as you're doing in other parts of your program.
printf("\nConcatenation of the strings: %s", output);
printf("\n%d", strlen(output));
Use sizeof to determine the size of data types, like char, a struct, an array, etc.
You've mentioned that you want to use sizeof to check if everything is fine with memory allocation, but you can't use sizeof this way on a buffer of memory allocated with malloc: you can only rely on the return value of malloc - which you aren't checking - to know if your allocation was successful.
You can use sizeof to determine the size of an array:
char myStr[13];
printf("%d\n", sizeof(myStr));
But this only works for arrays, and not buffers allocated using malloc.
Also this line creates a memory leak because you overwrite the pointer in the next line:
output = (char *)malloc((size1+size2+1)*sizeof(char));
sizeof gives the size in bytes, where a byte is the size of a char.
printf("\n%d", sizeof(output));
output is a char*, so on your system char*s are 8 bytes large. You must use strlen to obtain the length of a 0-terminated string.
printf("\n%d", sizeof(output)); prints a size of pointer to char. You platform appears to have pointers that are 8 bytes in size.
First:
second = (char *) malloc ((size2+1)*sizeof(char));
Don't typecast the result of malloc().
Second:
sizeof(char) is going to be 1, a char is 1 byte and sizeof() returns the number of bytes required to hold that data type. So you don't need the *sizeof(char), you need that for larger types like int.
Finally:
printf("\nConcatenation of the strings: %s", output); printf("\n%d", sizeof(output));
output is a char * so this is going to give you the sizeof(char *) on your system.
You said in a previous comment:
I know the differences between strlen and sizeof, but using sizeof(output) I wanted to check if everything is fine with memory allocation
Sounds like what you wanted was to verify that you allocated the correct amount of memory for the two concatenated strings. sizeof() won't give you that information. It's in the low level details at this point, you need to do something OS dependent to try and find that information. (ex. in the linux kernel if you kmalloc() memory you can use ksize() to find out exactly how many bytes you got)

Dynamic char array, size is fixed?

I am trying to create a char array dynamically. However, do not matter which number I put as the desired value of the size array it just keep using 4 has the size. If I place 3,2 or even 8, 10 it does not change...
Part where I initialize it...
char *x;
x = (char *)calloc(10, sizeof(char));
if(x == NULL )
{
return;
}
cout <<"Size_Vector = "<<sizeof(x)<<endl; //Keep making the size of the array 4..no matter what
sizeof(x) returns the size of the pointer not the allocated memory or the size of array.
It always returns 4 size of an pointer on your envrionment is 4and it will be the same for all.
You will have to keep track of how much memory you allocated yourself & also ensure that you do not write beyond the bounds of that allocated memory.
x is a pointer of type char *. sizeof(x) returns the size of the pointer instead of the array size.
Generally, there is no way to know the array size from a pointer type even if it's pointing to an array, because of array decaying.
char *x = malloc(sizeof(char)*10);
// This will give you 4
printf ("%d\n", sizeof(x));
But you can get the size of an array type.
char x[10];
// This will give you 10
printf ("%d\n", sizeof(x));
This is a short piece of code i wrote for you in case you really want to find the size of the memory piece you reserved by calling calloc though its obvious that when you say 10 spaces of 1 byte each then you are going to get 10 bytes like the case here which says you want 10 * sizeof(char) :
#include<stdio.h>
#include<stdlib.h>
main(){
char *ptr = NULL;
int i = 0;
int size = 0;
int n = 0;
printf("Enter the size of the dynamic array in bytes : ");
scanf("%d",&n);
ptr = (char*) calloc (n,sizeof(char));
for(i=0;i<n;i++){
size = size + sizeof(ptr[i]);
}
printf("Size is %d\n",size);
}
The malloc call returns a void pointer and when you say sizeof(pointer) you ask for the size of the pointer and not the chunk of memory that you just declared.So it gives you 4/8/... bytes depending on the m/c you are using.
Try this out :
char *cptr;
int *iptr;
printf("size of integer pointer is : %d\n",sizeof(iptr));
printf("size of character pointer is : %d\n",sizeof(cptr));
Note : malloc points to the address of the first element of the chunk of memory(ie 10 * 1 = 10 bytes) that you have dynamically obtained by calling it.

Solve a segmentation fault in a pointer to a pointer to a string

I'm having a segmentation fault when I want to save a string in a dynamic array.
I have a program that does this:
User insert char "s"
The program enters a loop and save strings in an array (name: cod).
When user inserts char "t", it stops
After that I save that array in the first position of a new dynamic array (name: vec).
Then if user insert char "s" again
The program enters a loop and save strings in an array.
When user inserts char "t", it stops
After that I save that array in the second position of a new dynamic array.
and so one.
This is my code:
int main(){
char Cod[30][11];
char tmp[11];
char ***vec;
int i = 0;
strcpy (tmp, "p");
vec = (char *** ) malloc (sizeof ( char *) );
vec[0] = (char ** ) malloc (sizeof ( char *) * 30);
do {
scanf("%s", tmp);
while( (strcmp (tmp, "p")) != 0){
strcpy ( Cod[i] , tmp );
scanf("%s", tmp);
i++;
}
vec = (char ***) realloc (vec, sizeof ( char *) * (i + 1));
vec[i + 1] = (char ** ) realloc (vec[i + 1], sizeof ( char *) * (30));
vec[i-1] = (char **) Cod;
scanf("%s", tmp);
}
while((strcmp (tmp, "s")) == 0);
printf("%s", vec[0][0]);
return 0;
}
This is the part of the code that work's:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char Cod[30][11];
char tmp[11];
int i = 0;
strcpy (tmp, "p");
do {
scanf("%s", tmp);
while( (strcmp (tmp, "p")) != 0){
strcpy ( Cod[i] , tmp );
scanf("%s", tmp);
i++;
}
scanf("%s", tmp);
}
while((strcmp (tmp, "s")) == 0);
printf("%s", Cod[0]);
return 0;
}
I started to fix this code but soon realized there is so much wrong in it, I don't know where to start. So instead, this turned out to be a code review answer instead, I apologize up front if it is detailed and picky.
There's a rule of thumb in C saying that if you need more than two levels of pointer indirection, your code is obfuscated and should be rewritten (reference MISRA-C:2004 17.5).
It doesn't make sense whatsoever to use dynamic memory allocation in this case, because you already know at program start-up that no string will be larger than 11 characters and there will not be more than 30 strings. If this condition is not true, you need to write a safer input method, preferably with fgets() which is safe against buffer overflows. Make sure that the input doesn't go out of bounds of array "Cod". You can allocate 30*11=330 bytes statically without a guilty conscience. And it will make the code faster.
It doesn't make sense to have 3 levels of indirection for an array of strings. You aren't even using the dynamic memory to hold a copy of strings, you just allocate pointers. This doesn't make any sense at all. If you need a pointer lookup table pointing at Cod then allocate it statically, it will only require sizeof(char*)*30 bytes.
As already mentioned, you can only use realloc on a pointer that has previously been malloc/calloc:ed.
As already mentioned, never typecast the result of malloc/realloc in C. This is C++ practice. In C, it destroys type safety and hides type compatibility bugs. There are countless, detailed discussions about this here on SO if you want to know the details.
What if you don't find "p" in the user string? The program will go havoc.
Don't name variables that affect fundamental program functionality to abstract things like tmp, vec etc. tmp could be renamed to input_buf or something, etc.
Avoid magic numbers in code, use const or #define for array length constants.
You can initialize strings in C, there is no need for strcpy to do so. char input_buf[INP_BUF_N] = "p";
To search for a char in a string, use strchr().
You shouldn't need to have the user inputting the same thing twice with scanf() in the outer do-while loop, likely a typo bug.
You can not do wild typecast between a static array of arrays to a pointer-to-pointer. This depends on the structure of whatever the pointer-to-pointer points at. Because a typical dumb-school-book dynamic 2D-array (malloc(Xsizeof(char)... malloc(Y*sizeof(char)) will not allocate memory adjacently. Plenty of discussions about this here on SO.
(you can allocate dynamic 2D arrays in adjacent memory with the use of array pointers or with "mangling", but those are rather advanced topics)
free() the dynamic memory once you are done using it.
As you hopefully can tell, the wise choice here is to rewrite this code from scratch.
Since it is a homework I tried to rewrite your code in something that should work...
char Cod[30][11];
char tmp[11];
char ***vec;
int i = 0;
strcpy (tmp, "p");
vec = (char***)malloc(sizeof(char *));
vec[0] = (char**)malloc(sizeof(Cod));
do {
scanf("%s", tmp);
int j = 0;
while(strcmp(tmp, "p")) {
strcpy(Cod[j], tmp);
scanf("%s", tmp);
j++;
}
vec = (char ***)realloc(vec, sizeof(char *) * (i+1));
vec[i] = (char **)malloc(sizeof(Cod));
memcpy(vec[i], Cod, sizeof(Cod));//you need to copy results since next time the Cod will be rewritten
scanf("%s", tmp);
i++;
} while((strcmp(tmp, "s")) == 0);
for three stars
char ***vec;
you need 3 mallocs (the casts are, at best, redundant in C and may hide an error)
vec = malloc(sizeof *vec);
vec[0] = malloc(sizeof *vec[0]);
vec[0][0] = malloc(30 * sizeof *vec[0][0]); /* sizeof (char) is 1 by definition */
In this 2 lines:
vec = (char ***) realloc (vec, sizeof ( char *) * (i + 1));
vec[i + 1] = (char ** ) realloc (vec[i + 1], sizeof ( char *) * (30));
If i = 1, then you reserve to "vec" i+1=2 pointers. In the second line you then call the 3rd one (vec[i+1] = vec[2] is 3rd element in table of size 2).

Resources