Arrays is initialized as:
char** aldos = NULL;
char** aldoFilenames = NULL;
Function definition is:
int readFilesFromDirectory(char*** dest, char*** nameDest)
Passed to function via:
readFilesFromDirectory(&aldos, &aldoFilenames);
After counting the files, dest and nameDest are initialized:
*dest = (char**)malloc(sizeof(char*)*count);
*nameDest = (char**)malloc(sizeof(char*)*count);
count = 0; //resetting to read in the files again
First filename for nameDest is read in like:
*nameDest[count] = (char*) malloc(sizeof(char)*strlen(findData.cFileName) + 1);
strcpy(*nameDest[count], findData.cFileName);
//can confirm in my program, the value exists properly in *nameDest[count]
count++;
Heres where the problem comes in, when I throw it in a loop, it crashes (with no real useful error codes):
while (FindNextFile(hfind, &findData) != 0)
{
*nameDest[count] = (char*) malloc(sizeof(char)*strlen(findData.cFileName) + 1); //doesnt make it past here, CRASH
sprintf(*nameDest[count],"%s\0",findData.cFileName);
count++;
}
Any insight would be appreciated, I'll be quick to add more information if requested
In *nameDest[count], the indexing operator place before the dereference operator, making the code equivalent to *(nameDest[count]), which is not what you want since nameDest points to the array. You need to do the pointer dereference before the array indexing by using parenthesis: (*nameDest)[count]
I should also note that polling the OS twice for the directory listing - once for the count and once for the actual names - is unreliable, as between the two polls, the count might have changed. Consider using realloc to resize the array as you find more entries.
Several problems in the code
1) the expression: sizeof(char) is defined as 1 and multiplying anything by 1 has no effect, especially as part of a malloc() parameter, so it just clutters the code and accomplishes nothing.
Suggest removing the sizeof(char) expressions.
2) the memory allocation family (malloc, calloc, realloc) have a returned type of void* which can be assigned to any other pointer, so the cast is unneeded, just clutters the code and is a real headache when debugging and/or maintaining the code.
Suggest remove the casting of the returned values from malloc()
3) in C, array offsets start with 0 and end with array size -1 So when an array of size count is allocated, the valid offsets are 0...count-1.
However, the posted code is accessing array[count] which is past the end of the array, this is undefined behaviour and can/will lead to a seg fault event.
Related
I have this code
int main(int argc, char *argv[])
{
int i=1;
char **m=malloc(sizeof(char *)*i);
printf("%zu\n",sizeof *m);
m[0]=malloc(strlen("hello")+1);
strcpy(m[0],"hello");
printf("%s\n", m[0]);
i=2;
m=(char **)realloc(m,sizeof (char *)*i);
m[1]=malloc(strlen("hi")+1);
strcpy(m[1],"hi");
printf("%s %s \n",m[0],m[1] );
// TODO: write proper cleanup code just for good habits.
return 0;
}
this is how I am allocating pointer char **m 8 byte single char pointer
int i=1;
char **m=malloc(sizeof(char *)*i);
and this is how I am allocating area of space whose address will be kept in m[0]
m[0]=malloc(strlen("hello")+1);
strcpy(m[0],"hello");
printf("%s\n", m[0]);
I like to know is this normally how its done. I mean allocating space for pointer and then allocating space in memory that the pointer will hold.
Does m[0]=malloc(strlen("hello")+1); is same as this *(m+0)=malloc(strlen("hello")+1); and does this m[1]=malloc(strlen("hi")+1); this *(m+1)=malloc(strlen("hi")+1);
And I am increasing pointer to pointer numbers like this in allocation m=(char **)realloc(m,sizeof (char *)*i); before m[1]=malloc(strlen("hi")+1);
is there anything wrong with above code. I seen similar code on this Dynamic memory/realloc string array
can anyone please explain with this statement char **m=malloc(sizeof(char *)*i); I am allocating 8 byte single pointer of type char but with this statement m=(char **)realloc(m,sizeof (char *)*i); why I am not getting stack smaching detected error. How exactly realloc works. can anyone give me the link of realloc function or explain a bit on this please
I like to know is this normally how its done. I mean allocating space for pointer and then allocating space in memory that the pointer will hold.
It depends on what you are trying to achieve. If you wish to allocate an unspecified amount of strings with individual lengths, then your code is pretty much the correct way to do it.
If you wish to have a fixed amount of strings with individual lengths, you could just do char* arr [n]; and then only malloc each arr[i].
Or if you wish to have a fixed amount of strings with a fixed maximum length, you could use a 2D array of characters, char arr [x][y];, and no malloc at all.
Does m[0]=malloc(strlen("hello")+1); is same as this *(m+0)=malloc(strlen("hello")+1);
Yes, m[0] is 100% equivalent to *((m)+(0)). See Do pointers support "array style indexing"?
is there anything wrong with above code
Not really, except stylistic and performance issues. It could optionally be rewritten like this:
char** m = malloc(sizeof(*m) * i); // subjective style change
m[0]=malloc(sizeof("hello")); // compile-time calculation, better performance
why I am not getting stack smaching detected error
Why would you get that? The only thing stored on the stack here is the char** itself. The rest is stored on the heap.
How exactly realloc works. can anyone give me the link of realloc function or explain a bit on this please
It works pretty much as you've used it, though pedantically you should not store the result in the same pointer as the one passed, in case realloc fails and you wish to continue using the old data. That's a very minor remark though, since in case realloc fails, it either means that you made an unrealistic request for memory, or that the RAM on your system is toast and you will unlikely be able to continue execution anyway.
The canonical documentation for realloc would be the C standard C17 7.22.3.5:
#include <stdlib.h>
void *realloc(void *ptr, size_t size);
The realloc function deallocates the old object pointed to by ptr and returns a
pointer to a new object that has the size specified by size. The contents of the new
object shall be the same as that of the old object prior to deallocation, up to the lesser of
the new and old sizes. Any bytes in the new object beyond the size of the old object have
indeterminate values.
If ptr is a null pointer, the realloc function behaves like the malloc function for the
specified size. Otherwise, if ptr does not match a pointer earlier returned by a memory
management function, or if the space has been deallocated by a call to the free or
realloc function, the behavior is undefined. If memory for the new object cannot be
allocated, the old object is not deallocated and its value is unchanged.
Returns
The realloc function returns a pointer to the new object (which may have the same value as a pointer to the old object), or a null pointer if the new object could not be allocated.
Notably there is no guarantee that the returned pointer always has the same value as the old pointer, so correct use would be:
char* tmp = realloc(arr, size);
if(tmp == NULL)
{
/* error handling */
}
arr = tmp;
(Where tmp has the same type as arr.)
Your code looks fine to me. Yes, if you are storing an array of strings, and you don't know how many strings will be in the array in advance, then it is perfectly fine to allocate space for an array of pointers with malloc. You also need to somehow get memory for the strings themselves, and it is perfectly fine for each string to be allocated with its own malloc call.
The line you wrote to use realloc is fine; it expands the memory area you've allocated for pointers so that it now has the capacity to hold 2 pointers, instead of just 1. When the realloc function does this, it might need to move the memory allocation to a different address, so that is why you have to overwrite m as you did. There is no stack smashing going on here. Also, please note that pointers are not 8 bytes on every platform; that's why it was wise of you to write sizeof(char *) instead of 8.
To find more documentation about realloc, you can look in the C++ standard, or the POSIX standard, but perhaps the most appropriate place for this question is the C standard, which documents realloc on page 314.
this is what I have so far but I can't figure out what is wrong with it
void newCopy(char *s)
{
char newString = malloc(sizeof(int * strlen(s)));
newString = s;
return &newString;
}
void newCopy(char *s)
{
char newString = malloc(sizeof(int * strlen(s)));
First and second problems are here.
First is, You're assigning the return of malloc, which is a pointer, to a variable declared as char. The variable should be declared as char*.
Second is, your input to sizeof is wrong.
int * strlen(s) is nonsense and won't compile, because you're trying to multiply a type and an integer. You meant sizeof(int) (which is an integer) * strlen(s) (also an integer) which will compile.
You should use sizeof(char) instead of sizeof(int), since it is a string.
You should add 1 to the size, since strings in C need to be null terminated by an extra \0 that strlen does not report being part of the string length.
Putting it all together, sizeof(char)*(strlen(s)+1)
newString = s;
Third problem is here. = is not a magic operator - it assigns the value in the variable s (which is a pointer) to the value in the variable newString (which after fixing the above mistake, will also be a pointer). It does nothing beside that.
What you want to do instead is use strcpy, which is a function that copies the contents of one string (by following its pointer) to the contents of another string (by following its pointer). http://www.cplusplus.com/reference/cstring/strcpy/
return &newString;
Fourth and fifth problems are here.
Fourth is, You have declared the function as void and here you are trying to return a char*.
Fifth is, you are trying to return a pointer to something that was declared on the stack (a local variable). As soon as the function returns, anything on the stack for that function is trash and cannot be referenced anymore.
However, if you correctly make newString of type char*, all you need to do is return newString; And you correctly return a pointer by value which points into the heap (thanks to the earlier malloc).
}
Finally, judging by this code, I should inform you that C is not a newbie friendly language, where you can just type things that 'look like' what you want to happen and pray it works. If you're even slightly wrong your code will crash and you will have zero idea why, because you don't know the right way to do things. Either read a really good book on C and teach yourself everything from basic to advance step by step so you know how it all works, or pick up a more user friendly language.
I should start by pointing out that in my opinion, given the number and (especially) nature of the mistakes in this code, you probably need to get a good book on C.
Your newString = s; overwrites the pointer instead of copying the string into the space you just allocated. Thus, you lose the pointer to what you just allocating (leaking the memory) without making a copy. You probably want to use strcpy instead of direct assignment.
Your computation of the size you allocate isn't what you really want either. Typically, for a string of length N, you want to allocate N+1 bytes. You're currently attempting to allocat sizeof(int * strlen(s)) bytes, which shouldn't even compile.
A corrected version should be like:
char *newCopy(char *s)
{
if (s == NULL)
return NULL;
char *newString = malloc(strlen(s) + 1);
if (newString == NULL)
return NULL;
strcpy(newString, s);
return newString;
}
I'm new to C and haven't really grasped when C decides to free an object and when it decides to keep an object.
heap_t is pointer to a struct heap.
heap_t create_heap(){
heap_t h_t = (heap_t)malloc(sizeof(heap));
h_t->it = 0;
h_t->len = 10;
h_t->arr = (token_t)calloc(10, sizeof(token));
//call below a couple of times to fill up arr
app_heap(h_t, ENUM, "enum", 1);
return h_t;
}
putting h_t through
int app_heap(heap_t h, enum symbol s, char* word, int line){
int it = h->it;
int len = h->len;
if (it + 1 < len ){
token temp;
h->arr[it] = temp;
h->arr[it].sym = s;
h->arr[it].word = word;
h->arr[it].line = line;
h->it = it + 1;
printf(h->arr[it].word);
return 1;
} else {
h->len = len*2;
h->arr = realloc(h->arr, len*2);
return app_heap(h, s, word, line);
}
}
Why does my h_t->arr fill up with junk and eventually I get a segmentation fault? How do I fix this? Any C coding tips/styles to avoid stuff like this?
First, to answer your question about the crash, I think the reason you are getting segmentation fault is that you fail to multiply len by sizeof(token) in the call to realloc. You end up writing past the end of the block that has been allocated, eventually triggering a segfault.
As far as "deciding to free an object and when [...] to keep an object" goes, C does not decide any of it for you: it simply does it when you tell it to by calling free, without asking you any further questions. This "obedience" ends up costing you sometimes, because you can accidentally free something you still need. It is a good idea to NULL out the pointer, to improve your chance of catching the issue faster (unfortunately, this is not enough to eliminate the problem altogether, because of shared pointers).
free(h->arr);
h -> arr = NULL; // Doing this is a good practice
To summarize, managing memory in C is a tedious task that requires a lot of thinking and discipline. You need to check the result of every allocation call to see if it has failed, and perform many auxiliary tasks when it does.
C does not "decide" anything, if you have allocated something yourself with an explicit call to e.g. malloc(), it will stay allocated until you free() it (or until the program terminates, typically).
I think this:
token temp;
h->arr[it] = temp;
h->arr[it].sym = s;
/* more accesses */
is very weird, the first two lines don't do anything sensible.
As pointed out by dasblinkenlight, you're failing to scale the re-allocation into bytes, which will cause dramatic shrinkage of the array when it tries to grow, and corrupt it totally.
You shouldn't cast the return values of malloc() and realloc(), in C.
Remember that realloc() might fail, in which case you will lose your pointer if you overwrite it like you do.
Lots of repetition in your code, i.e. realloc(h->arr, len*2) instead of realloc(h->arr, h->len * sizeof *h->arr) and so on.
Note how the last bullet point also fixes the realloc() scaling bug mentioned above.
You're not reallocating to the proper size, the realloc statement needs to be:
realloc(h->arr, sizeof(token) * len*2);
^^^^^^^^^^^^
(Or perhaps better realloc(h->arr, sizeof *h->arr * h->h_len);)
In C, you are responsible to free the memory you allocate. You have to free() the memory you've malloc/calloc/realloc'ed when it's suitable to do so. The C runtime never frees anything, except when the program has terminated(some more esoteric systems might not release the memory even then).
Also, try to be consistent, the general form for allocating is always T *foo = malloc(sizeof *foo), and dont duplicate stuff.
e.g.
h_t->arr = (token_t)calloc(10, sizeof(token));
^^^^^^^^ ^^ ^^^^^^^^^^^^^
Don't cast the return value of malloc in C. It's unncessesary and might hide a serious compiler warning and bug if you forget to include stdlib.h
the cast is token_t but the sizeof applies to token, why are they different, and are they the same type as *h_t->arr ?
You already have the magic 10 value, use h_t->len
If you ever change the type of h_t->arr, you have to remember to change the sizeof(..)
So make this
h_t->arr = calloc(h_t->len, sizeof *h_t->arr);
Two main problems in creating dangling pointers in C are the not assigning
NULL to a pointer after freeing its allocated memory, and shared pointers.
There is a solution to the first problem, of automatically nulling out the pointer.
void SaferFree(void *AFree[])
{
free(AFree[0]);
AFree[0] = NULL;
}
The caller, instead calling
free(p);
will call
SaferFree(&p);
In respect to the second and harder to be siolved issue:
The rule of three says:
If you need to explicitly declare either the destructor, copy constructor or copy assignment operator yourself, you probably need to explicitly declare all three of them.
Sharing a pointer in C is simply copying it (copy assignment). It means that using the rule of three (or the general rule of 0)
when programming in C obliges the programmer to supply a way to construct and especially destruct such an assignment, which is possible, but not an
easy task especially when C does not supply a descructor that is implicitly activated as in C++.
I have the following test function to copy and concatenate a variable number of string arguments, allocating automatically:
char *copycat(char *first, ...) {
va_list vl;
va_start(vl, first);
char *result = (char *) malloc(strlen(first) + 1);
char *next;
strcpy(result, first);
while (next = va_arg(vl, char *)) {
result = (char *) realloc(result, strlen(result) + strlen(next) + 1);
strcat(result, next);
}
return result;
}
Problem is, if I do this:
puts(copycat("herp", "derp", "hurr", "durr"));
it should print out a 16-byte string, "herpderphurrdurr". Instead, it prints out a 42-byte string, which is the correct 16 bytes plus 26 more bytes of junk characters.
I'm not quite sure why yet. Any ideas?
The variable-argument-list functions don't magically know how many arguments there are, so you're most likely walking the stack until you happen to hit a NULL.
You either need an argument numStrings, or supply an explicit null-terminator argument after your list of strings.
You need a sentinel marker on your list:
puts(copycat("herp", "derp", "hurr", "durr", NULL));
Otherwise, va_arg doesn't actually know when to stop. That fact that you're getting junk is pure accident since you're invoking undefined behaviour. For example, when I ran your code as-is, I got a segmentation fault.
Variable argument functions, such as printf need some sort of indication as to how many items are passed in: printf itself uses the format string up front to figure this out.
The two general methods are a count (or format string) which is useful when you can't use one of the possible values as a sentinel (a marker at the end).
If you can use a sentinel (like NULL in the case of pointers, or -1 in the case of non-negative signed integers, that's usually better so you don't have to count the elements (and possible get the element count and element list out of step).
Keep in mind that puts(copycat("herp", "derp", "hurr", "durr")); is a memory leak since you're allocating memory then losing the pointer to it. Using:
char *s = copycat("herp", "derp", "hurr", "durr");
puts(s);
free (s);
is one way to fix that, and you may want to put in error checking code in case the allocations fail.
What I understand from your code is that you assume va_next will return NULL once each argument has been "popped". That's wrong as va_next has absolutely no way to determine the number of arguments : your while loop will keep running until a NULL is randomly hit.
Solution : either provide the number of arguments, or add call your function with an additional "NULL" argument.
PS: if you are wondering why printf doesn't require such an additional argument, it's because the number of expected arguments is deduced from the format string (the number of '%flag')
As an addition to the other answers, you should cast the NULL to the expected type when using it as an argument to a variadic function: (char *)NULL. If NULL is defined as 0, then an int will be stored instead, which will accidentally work when int has the sime size as the pointer and NULL is represented by all bits 0. But none of this is guaranteed, so you may run into strange behaviour that's hard to debug when porting the code or even when only changing the compiler.
As others have mentioned, va_arg does not know when to stop. It is up to you to provide NULL (or some other marker) when you call the function. Just a few side notes:
You must call free on pointers you obtain from malloc and realloc.
There is no reason to cast the result of malloc or realloc in C.
When calling realloc, it is best to store the return value into a temporary variable. If realloc is unable to reallocate enough memory, it returns NULL but the original pointer is not freed. If you use realloc the way you do, and it is unable to reallocate the memory, then you have lost the original pointer and your subsequent call to strcat will likely fail. You could use it like this:
char *tmp = realloc(result, strlen(result) + strlen(next) + 1);
if (tmp == NULL)
{
// handle error here and free the memory
free(result);
}
else
{
// reallocation was successful, re-assign the original pointer
result = tmp;
}
Assuming I have a piece of code similar to this:
SOMESTRUCTURE *info;
info = malloc(sizeof(SOMESTRUCTURE));
while(something...)
{
info->mini[0] = malloc(sizeof(SOMESTRUCTURE *)); // It's a structure inside the same structure
while(something...)
{
info->mini[x]->name = malloc(sizeof(char *)*strlen(name));
printf("%s\n", info->mini[0]->name); // This prints out the correct value
}
}
printf("%s\n", info->mini[0]->name); // But now the value is lost and is null
How can I make the info->mini[0]->name value apply throughout the entire function?
No, that should still be available to you. The only way you could lose the value would be if x were 0 on one of the iterations of your while loop or if you execute the malloc inside the outer loop without entering the inner loop - it's hard to tell if this is possible since you don't specify what something is in both cases.
It's true that variable created within a certain scope will disappear when you exit that scope but that isn't the case here. Allocated memory will survive scope changes. A given pointer to that memory may not but your pointer in this case (info is still in scope when you exit the outer while statement).
I do see one other potential problem - your malloc(sizeof(char *) * strlen(name)) should probably be malloc(strlen(name) + 1) (since sizeof(char) is always 1). It probably works because a char * will normally be bigger than a char but it's the wrong way to do it nonetheless.
However, I cannot see anywhere in your code where you actually set info->mini[0]->name to anything so I'm at a loss as to how it can ever have a correct value, unless it's somehow picking up a value from a previous malloc (this is possible since malloc itself is not required to clear the memory it gives to you).
You should post your actual code or preferably the smallest piece of code that exhibits the problem.
make sure x is never 0
I recommend you to use glib's g_strdup function, see API - You'll find in glib many useful functions to handle strings :
So in your case to duplicate the string name you'd just do ...
info->mini[x]->name = g_strdup(name);
Edited
As commented ... you can use standard strdup to get the same functionality:
info->mini[x]->name = strdup(name);
End Edition
By doing this, info->mini[x]->name will point to a dynamic allocated memory space that will be available outside your function - unless you free it.
If you don't want to use glib then:
info->mini[x]->name = malloc(sizeof(char) * (strlen(name) + 1));
strcpy(info->mini[x]->name,name);
In this case mind that the malloc is of sizeof(char) because a string is an array of chars not of char *, as you had before. +1 is to save last char for null terminated char.
I see that you allocate info->mini[x]->name, and on the very next line, print it out.
In between, you don't seem to actually put any data into ->name, so I don't see how it can possibly print the correct value out.
Your allocation of ->name depends on the value of x at that time. But you never show us x being declared, or its value being set.
Please show us information about the declaration and assignments of x and where data is actually copied into ->name.