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.
Related
I´m a bit confused with these 2.
I have a function called check that does the following:
bool check(const char *word)
{
char newWord[LENGTH + 1] = "";
for (int i = 0; word[i]; i++)
{
newWord[i] = tolower(word[i]);
}
}
Now for example if I use ="", the variable newWord will have all of it´s values as '\0' anytime I run the function check();
But when using char newWord[LENGTH + 1]; the variable seems to keep the old values even after my functions has returned, so when I do check() again, the char newWord already has values from the previous time I ran that function.
I know this is related to pointers and memory allocation but I just cannot seem to get how this works.
It's not a fancy answer, but compilers (and versions of compilers) have different opinions on whether to initialize memory before you use it. Unless things have changed recently, the only variables that get automatically initialized are variables with a static scope (global variables and those explicitly marked static).
For everything else, certain compilers might set everything to zeroes (or another value for debugging), but most won't add that small overhead to your program, when you're probably just going to assign a value of your own, soon enough. One of the biggest debugging effort of my career was because we changed C compilers from one that didn't pre-initialize variables (like most do) to one that did, exposing a bunch of errors my predecessors didn't catch (assigning to the wrong variable, looking for non-zero values and suddenly finding them), so it's an important feature to know about.
The key to your question, though is "seems to keep," because it's only an accident that the old string is still in the right position. If you call another function between check() calls, you'll start to see different scratch memory.
Moral of the story? Always initialize every one of your variables, unless you absolutely know that it's going to get a value before you use it.
The values that you find after running check() twice are still garbage values. When you allocate some memory using
char newWord[LENGTH + 1];
You are always getting "some" memory that the operating system handles you (in laymen-terms), having initially garbage values. It is just a coincidence that you're getting the same memory blocks that you got from the previous call to check().
However, when you do:
char newWord[LENGTH + 1] = "";
You are explicitly initializing those memory blocks to \0.
If you don't initialize a local variable, it has an indeterminate value. Which could be anything, including random "garbage" or left-overs sitting in RAM memory since previous execution. There are no guarantees of what value you will get - and that's it.
Accessing such an uninitialized variable's value might also invoke undefined behavior in some cases:
(Why) is using an uninitialized variable undefined behavior?
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.
I'm trying to make a program that basically picks a specific piece of source code and adds some other specific code into it. The program is just to big to put it all inside my question, but basically I have this "actors" struct:
typedef struct actors_s {
int num;
char *src_path;
char *project_path;
int *papify;
char *actor_path[];
} actors_s;
As you can see these are almost all pointers and the last one is an array of strings. This needs to be done this way because the number of "actor elements" depends on the input every time.
The problem:In an specific test case, I have a case with 'num' members in the actor_path array. Then I first call malloc only once this way:
*actors->actor_path = malloc(actors->num);
My logic tells me I shouldn't be using the '*' operator here but without it I get an error, this is possibly where the problem is. So, a function is called that allocates a new memory space for every new member (never going further of 'num' members):
int size = strlen(name)+strlen(actors->project_path)+strlen("/src/")+strlen(".c")+4;
actors->actor_path[i] = malloc(size);
(The malloc calls are properly tested if successful in the actual program)
This is called inside a function that is called for every "actor_path" element. In this test example I have three actors.
Mysteriously enough, on the third call of this malloc, the src_path element of the struct, which was properly allocated and set to a string once in the beginning of the program (and never touched again) is freed (I think so, at least it is changed into random numbers and symbols if I watch it in debug mode).
Anyone has any idea how and why is this possible? How do I fix this?
Thanks in advance.
EDIT:
Here are some screenshots from the debug watch window: http://imgur.com/a/aB1uv
First call to malloc: all OK.
Second call to malloc: all OK.
Third call to malloc: src_path gets erased!!
[] in latest array element is called flexible array member. It means structure have an array that starts just after structure itself, and its size is unspecified. You have to allocate memory for this manually. E.g.
actors_s *actor = malloc(sizeof(*actor) + sizeof(char*) * num);
Then just assign at most num elements into actor_path (each element is pointer to char).
about *actors->actor_path = malloc(actors->num);
actors->actor_path is an array of pointers, so *actors->actor_path is the first pointer in actors->actor_path, i.e. actors->actor_path[0].
When doing this, you actually allocate actors->num bytes memory for actors->actor_path[0].
Now, accessing actors->actor_path[0] is OK, while accessing actors->actor_path[1], actors->actor_path[2], actors->actor_path[3],... may cause problems, say, rewrite src_path...
about the solution
#keltar is right. In this way, the resource for actors->actor_path[0], actors->actor_path[1], actors->actor_path[2], ..., actors->actor_path[num - 1] is correctly allocated.
I'm trying to write a simple C program on Ubuntu using Eclipse CDT (yes, I'm more comfortable with an IDE and I'm used to Eclipse from Java development), and I'm stuck with something weird. On one part of my code, I initialize a char array in a function, and it is by default pointing to the same location with one of the inputs, which has nothing to do with that char array. Here is my code:
char* subdir(const char input[], const char dir[]){
[*] int totallen = strlen(input) + strlen(dir) + 2;
char retval[totallen];
strcpy(retval, input);
strcat(retval, dir);
...}
Ok at the part I've marked with [*], there is a checkpoint. Even at that breakpoint, when I check y locals, I see that retval is pointing to the same address with my argument input. It not even possible as input comes from another function and retval is created in this function. Is is me being unexperienced with C and missing something, or is there a bug somewhere with the C compiler?
It seems so obvious to me that they should't point to the same (and a valid, of course, they aren't NULL) location. When the code goes on, it literally messes up everything; I get random characters and shapes in console and the program crashes.
I don't think it makes sense to check the address of retval BEFORE it appears, it being a VLA and all (by definition the compiler and the debugger don't know much about it, it's generated at runtime on the stack).
Try checking its address after its point of definition.
EDIT
I just read the "I get random characters and shapes in console". It's obvious now that you are returning the VLA and expecting things to work.
A VLA is only valid inside the block where it was defined. Using it outside is undefined behavior and thus very dangerous. Even if the size were constant, it still wouldn't be valid to return it from the function. In this case you most definitely want to malloc the memory.
What cnicutar said.
I hate people who do this, so I hate me ... but ... Arrays of non-const size are a C99 extension and not supported by C++. Of course GCC has extensions to make it happen.
Under the covers you are essentially doing an _alloca, so your odds of blowing out the stack are proportional to who has access to abuse the function.
Finally, I hope it doesn't actually get returned, because that would be returning a pointer to a stack allocated array, which would be your real problem since that array is gone as of the point of return.
In C++ you would typically use a string class.
In C you would either pass a pointer and length in as parameters, or a pointer to a pointer (or return a pointer) and specify the calls should call free() on it when done. These solutions all suck because they are error prone to leaks or truncation or overflow. :/
Well, your fundamental problem is that you are returning a pointer to the stack allocated VLA. You can't do that. Pointers to local variables are only valid inside the scope of the function that declares them. Your code results in Undefined Behaviour.
At least I am assuming that somewhere in the ..... in the real code is the line return retval.
You'll need to use heap allocation, or pass a suitably sized buffer to the function.
As well as that, you only need +1 rather than +2 in the length calculation - there is only one null-terminator.
Try changing retval to a character pointer and allocating your buffer using malloc().
Pass the two string arguments as, char * or const char *
Rather than returning char *, you should just pass another parameter with a string pointer that you already malloc'd space for.
Return bool or int describing what happened in the function, and use the parameter you passed to store the result.
Lastly don't forget to free the memory since you're having to malloc space for the string on the heap...
//retstr is not a const like the other two
bool subdir(const char *input, const char *dir,char *retstr){
strcpy(retstr, input);
strcat(retstr, dir);
return 1;
}
int main()
{
char h[]="Hello ";
char w[]="World!";
char *greet=(char*)malloc(strlen(h)+strlen(w)+1); //Size of the result plus room for the terminator!
subdir(h,w,greet);
printf("%s",greet);
return 1;
}
This will print: "Hello World!" added together by your function.
Also when you're creating a string on the fly you must malloc. The compiler doesn't know how long the two other strings are going to be, thus using char greet[totallen]; shouldn't work.
I'm new to C, so feel free to correct mistakes.
I have some code that somewhat goes like this:
// some variables declared here like int array_size
char* cmd = (char*)malloc(array_size*sizeof(char));
for(;;){
// code here sets cmd to some string
free(cmd);
array_size = 10;
cmd = (char*)malloc(array_size*sizeof(char));
// print 1
printf(cmd);
printf("%d\n", strlen(cmd));
// repeat above for some time and then break
}
So I do the loop for a while and see what it prints. What I expected was every time the string would be empty and the length would be 0. However, that is not the case. Apparently sometimes malloc gets memory with junk and prints that out and that memory with junk has a length != 0. So I was thinking about solving this by setting all char in a new char string to '\0' when malloc returns; however, I'm pretty sure I just did something wrong. Why is it even after I free the string and do a whole new malloc that my string comes with junk unlike the first malloc? What am I doing wrong?
malloc just allocated the memory and nothing more. It has no promises about what is in the memory. Specifically, it does not initialize memory. If you want allocated memory to be zeroed out, you can either do it manually with memset or simply call calloc (which is essentially malloc with zeroing out of memory).
malloc does not initialise the memory. You are just lucky the first time around.
Also if it is junk and contains a % symbol you are going to have other problems.
No you did nothing wrong - malloc does not guarantee the memory will be set to 0, only that it belongs to your process.
In general setting newly allocated memory to zero in unneeded so in C it is never explicitly cleared which would take several clock cycles.
There is a rather convenient method 'memset' to set it if you need
Your code segment has, at a minimum, the following problems.
You don't ever need to multiply by sizeof(char) - it's always one.
You cast the return value of malloc. This can hide errors that would otherwise be detected, such as if you forget to include the header with the malloc prototype (so it assumes int return code).
malloc is not required to do anything with the memory it gives you, nor will it necessarily give you the same block you just freed. You can initialise it to an empty string with a simple *cmd = '\0'; after every malloc if that's what you need.
printf (cmd) is dangerous if you don't know what cmd contains. If it has a format specifier character (%), you will get into trouble. A better way is printf ("%s", cmd).