I have the following structs in my on-going struggle to eventually create some kind of shell (based eventually around execvp().
struct commands {
char cmdname[30]; // The name of the command
enum ActionType action; /* char action[30]; what action to take */
};
struct userinput {
struct commands theaction; //The chosen action
char cmdentered[100]; // The cmd entered
char **anyargs; //The tokenised command
int argcount; //Argument count
};
And I initialise anyargs using malloc and create an array of strings with one string per argument to be passed on to the execvp.
I then get user input, convert the input into tokens stored in anyargs and examine the strings to find out what sort of action needs to be taken and store that in an enum.
All these methods are done by passing the pointer to the struct userinput as method parameters - which works fine. HOWEVER when I pass the pointer to the struct to a nested function, the char** anyargs becomes empty.
I hope the code I've added provides a solution to the answer! On another observation - when passed to a function inside a function, the actual value of the pointer doesn't change - only the dereferenced contents of the pointer.
Any help would be most gratefully received! I've tried to strip the code down to the areas I think are causing the issue!
Thank you!
int main() {
struct commands cmdlist[4]; //Array of structures with all commands in them
memset(cmdlist, 0, sizeof(cmdlist));
struct userinput userentry = { { { 0 } } }; //Structure containing input
userentry.theaction = cmdlist[0]; //Initialize empty command
userentry.anyargs = calloc(100, sizeof(char));
runEntry(&userentry, cmdlist); //Pass struct to function
free(userentry.anyargs);
return 0;
}
int runEntry(struct userinput *userentry, struct commands thecmds[]) {
int retval = 0;
int childpid = 0;
int processStatus;
printf("\n ... running cmd: \n\n");
printUserEntry(userentry); //in printUserEntry,
//userentry->anyargs[0] = NULL - why?
}
You've allocated 100 bytes worth of char * elements in anyargs. You haven't initialized those pointers, though. The fact that anyargs[0] happens to contain NULL is nice, but not guaranteed. malloc() doesn't initialize the allocated space.
In other words, when you say:
userentry.anyargs = malloc(100);
you've created:
userentry.anyargs = {
???, // uninitialized char *
???, // and another
???, // and another
...
??? // (100 / sizeof(char *)) entries later
};
You can explicitly initialize those to NULL in a loop:
for ( i = 0; i < (100 / sizeof(char *)); ++i )
userentry.anyargs[i] = NULL;
(or use calloc() instead of malloc() to ensure everything is zeroed out).
or you can allocate some space to them:
for ( i = 0; i < (100 / sizeof(char *)); ++i )
userentry.anyargs[i] = malloc(50); // or some other length
or just set them directly in runEntry():
userentry.anyargs[0] = "foo";
userentry.anyargs[1] = strdup(something);
Related
so my first question would be. Does fgets overwrite other char* values?
Otherwise, I'm not really sure how I have messed up my mallocs. Below is the code where the value is changing. First line is where the variable is being created.
data[dataIndex++] = createVariable(varName, 1, value, -1, line, NULL);
The code where the variable is being created
Variable *createVariable(char *name, int type, int val, int len, int line, char *string)
{
Variable *var = malloc(sizeof(Variable));
var->name = name;
var->setting = type;
var->num = val;
var->length = len;
var->line = line;
var->string = string;
return var;
}
What data looks like and how it was created.
Variable **data;
data = malloc(4 * sizeof(Variable *));
Forgot to add this, but below is my fgets code
if (fgets(line, MAX_LINE_LENGTH, in) == NULL)
{
break;
}
The problem is this line in your createVariable function:
var->name = name;
What this does is copy the pointer given as the first argument to the name field in the var structure; it doesn't make a (separate) copy of the data that is pointed to! So, assuming you call createVariable many times with the same variable as the first argument, then every object created will have the same address in its name field, and any modifications you make to any of them (via fgets) will change all of them.
To get round this, you need to allocate new memory for the name field, each time you call the createVariable function, then copy the string data to it. The simplest way to do this is using the strdup function:
Variable *createVariable(char *name, int type, int val, int len, int line, char *string)
{
Variable *var = malloc(sizeof(Variable));
var->name = strdup(name);
//...
var->string = strdup(string);
//...
But note, you will now need to be sure to free that memory from each object when you (eventually) delete it. Something like this:
void deleteVariable(Variable** var)
{
free((*var)->name); // free the name memory
free((*var)->string); // free the string memory
free(*var); // free the actual structure
*var = NULL; // set the pointer to NULL - to prevent multiple frees
}
EDIT: Just re-read your question, and noticed that you are making the same mistake with the string field! The same fix needs to be applied to that!
I have a struct that contains a value of type char*[]. It's defined like so:
struct background_element
{
pid_t pid;
int number;
char *full_command[MAX_ARGS];
};
I also have a global char*[] variable, args.
char *args[MAX_ARGS];
I try to create a new variable of type struct background_element and assign the full_command value like so:
struct background_element bg_elem = { .pid = child, .number = num_background, .full_command = args};
However, the assignment of args to .full_command seems to throw this warning: "Warning: initialization from incompatible pointer type."
I've tried to use strcpy, but since they're not char[] but char*[], it doesn't seem to work. I'm a bit at a loss of how to assign this. Any help would be appreciated.
As #user3386109 said, it's because char *full[MAX_ARGS] cannot be assigned to. There's two paths from here depending on your scenario. If args isn't going to be modified, either by other code or by freeing its string elements, then we can just point the elements of full_command to them like so:
struct background_element bg_elem = {.pid = child, .number = num_background};
for (unsigned int i = 0; i < MAX_ARGS; i++) {
bg_elem.full_command[i] = args[i];
}
If however you need to copy the strings, then you'll have to use malloc to create space for the strings, and then strcpy to copy the data over:
for (unsigned int i = 0; i < MAX_ARGS; i++) {
int str_len = strlen(args[i]);
bg_elem.full_command[i] = malloc((str_len + 1) * sizeof(char));
strcpy(bg_elem.full_command[i], args[i]);
}
The above for loop first:
Get the length of the ith arg
Allocate enough memory to the ith pointer of bg_elem.full_command
We need str_len + 1 because we need space for the null character
Copy the string from args to bg_elem.full_command
Finally, if you're needing to copy the strings from args don't forget to iterate through and free that memory at the end when you're done.
for (unsigned int i = 0; i < MAX_ARGS; i++) {
free(bg_elem.full_command[i]);
}
Note: If you need the memory that you are copying to be zeroed, calloc would be better. However since we're using strcpy, malloc works just fine.
Array objects in C are limited to only two kinds of initializers:
{}-enclosed initializers, i.e a pair of {} with individual initializers for array elements inside
String literals for char [] arrays.
Your initializer does not fall into any of these categories. It is invalid. You cannot initialize one array by another array (aside from case 2 above).
Formally, you can spell it out explicitly
struct background_element bg_elem =
{
.pid = child,
.number = num_background,
.full_command = { args[0], args[1], /* ... and so on */ }
};
but this is not really a viable approach. A much better idea would be
struct background_element bg_elem =
{
.pid = child,
.number = num_background
};
static_assert(sizeof bg_elem.full_command == sizeof args, "");
memcpy(bg_elem.full_command, args, sizeof args);
although it might suffer a bit from "double initialization" issue.
P.S. What you are trying to do is called initialization, not assignment. Assignment is a very different thing in C.
char *args[MAX_ARGS];
args is an array of MAX_ARGS pointers. args itself points to the memory of the first pointer. args hold the memory address in which the first pointer is. args[0] is the value of the first pointer. args[0][0] means, that we go to the memory of the first pointer, then go to the memory address pointed to by that pointer, and then get the value of the first byte in that memory address.
char *full_command[MAX_ARGS];
Now, this is also an array of MAX_ARGS pointers. full_command points to memory region that is MAX_ARGS * sizeof(char*) bytes length. full_command[0] is the value of the first pointer inside that memory region.
Now lets try assignment:
full_command = args;
Now we get the value of the memory address of the first pointer in args and assign that value into full_command variable. The memory of full_command is lost, it's no longer accessible by any other handle. Now args[0] = smth only and only if full_command[0] = smth. full_command points to the memory region that args points to.
To copy array VALUES you need to copy each VALUE of the array:
for (size_t i = 0; i < MAX_ARGS; ++i) {
full_command[i] = args[i];
}
or using memcpy:
memcpy(full_command, args, sizeof(full_command));
After such operation full_command points to a different region that args, both are sizeof(char*) * MAX_ARGS bytes long. And they both hold the same values.
You need to assign each array value:
struct background_element bg_elem = {
.pid = child,
.number = num_background,
.full_command = { args[0], args[1], args[2], ....<up until MAX_ARGS> },
};
That's not very usuable, it needs to be modified each time MAX_ARGS changes. So use memcpy or a loop:
struct background_element bg_elem = {
.pid = child,
.number = num_background,
};
memcpy(bg_elem.full_command, args, sizeof(bg_elem.full_command));
You have a lot of correct answers above. Simply put: arrays are weird in C. You can initialize them, but not assign them. You can't individually initialize them in a struct initializer, but you can assign them as part of a struct assignment.
#include <string.h>
int main(int argc, char *argv[])
{
char *test1 [3] = {"a", "b", "c"}; //initialization, not assignment; allowed
char *test2 [3];
//test2 = test1; //assignment of arrays; not allowed
memcpy(test2, test1, sizeof(test1)); //the right way to do a shallow array copy
}
But also, confusingly:
#include <string.h>
struct _array_holder
{
char *array[3];
};
int main(int argc, char *argv[])
{
struct _array_holder test1 = {{"a", "b", "c"}}; //_struct_ initialization; allowed
struct _array_holder test2;
test2 = test1; //assignment of _structs_; allowed!
memcpy(&test2, &test1, sizeof(test1)); //also a fine way to copy a struct
}
So, unfortunately, there is no pretty way (i.e., elegant syntax) to do what you want. Here's at least a reasonably self-contained way to use the fact that array assignments within structs work, to keep you from having to write several lines of initialization each time you want to populate a new struct:
#include <string.h>
#include <unistd.h>
#define MAX_ARGS 5
struct background_element
{
pid_t pid;
int number;
char *full_command[MAX_ARGS];
};
//something akin to a constructor for the struct
struct background_element init_background_element(pid_t pid, int number, char *full_command[])
{
struct background_element ret = {.pid = pid, .number=number};
memcpy(ret.full_command, full_command, sizeof(ret.full_command));
return ret;
}
int main(int argc, char *argv[])
{
pid_t child = 1;
int num_background = 5;
char *args[MAX_ARGS] = {"a", "b"};
//use of the constructor-like thing
struct background_element bg_elem = init_background_element(child, num_background, args);
return bg_elem.pid;
}
I want to filter an strings array passed in, something like this:
char **
filter_vids(char **vids, size_t n) {
int i;
int count = 0;
char ** filted = malloc(n * sizeof(char *));
for(i = 0; i < n; i++){
filted[i] = (char*)malloc(50 * sizeof(char));
}
for(i = 0; i < n; i++) {
if(some_filter(vids[i])) {
strcpy(filted[count++], vids[i]);
printf("in filter:%s\n", vids[i]);
}
}
return filted;
}
But the caller may not known the length of return array, it's extractly the counter variable, so what's the best practice of returning an array while telling him the right length of array?
such as
char **
filter_vids(char **vids, size_t n, int *output_length)
It's the best practice of using output_length?
I edit this function to this, as your suggestions:
char **
filter_vids(char **vids, size_t n) {
int i;
int count = 0;
char ** filted = malloc((n + 1) * sizeof(char *));
for(i = 0; i < n; i++) {
if(vids[i][0] <= 'f') {
filted[count++] = strdup(vids[i]);
}
}
filted[count] = NULL;
return filted;
}
To pass a pointer to an integer length variable whose value is then set in the function is certainly a good way. As Malcolm said, it is also general and can be used for sets of values which do not have an "invalid" member.
In the case of pointers with their invalid null pointer value one can mark the end of valid entries with a null pointer. For example, the array of string pointers which the C run time uses to pass command line arguments to main is thus terminated.
Which method to choose depends a little on how the caller wants to use the resulting array. If it is processed sequentially, a (while *p){ ..; ++p; } feels idiomatic. If, on the other hand, you need random access and must perform the equivalent of a strlen before you can do anything with the array, then it is probably better to return the length via a pointed-to length variable right away.
Two remarks:
First, note the difference between
a valid pointer to an empty string (if somebody called, let's say, myProg par1 "" par2, argv[2] could be a valid pointer to a zero byte);
and a null pointer which is pointing nowhere; in the example, argv[4] would be the null pointer, indicating the end of the argument list.
Second, You malloc more memory than you need which is wasteful in the case of longer strings and/or strict filters. You could instead allocate the string on demand inside the if clause.
These are common options:
Receive the allowed size as parameter by pointer, overwrite it with the actual size, return the array as return value.
Receive the output array as parameter by pointer, update as required, return the actual size as return value.
Append a sentinel value to the output array (here a null pointer), as suggested in the other answer.
Use a more sophisticated data structure as a return value. You could use a struct, which stores the size alongside the array or a linked list.
Example (untested):
typedef char* mystring;
typedef mystring* mystringarray;
typedef struct { mystringarray *arr; size_t size } mysizedstringarray;
/* returns filtered array, size will be updated to reflect the valid size */
mystringarray* myfun1(mystringarray in, size_t* size);
/* out will be allocated and populated, actual size is returned */
size_t myfun2(mystringarray in, size_t size, mystringarray* out);
/* output array contains valid items until sentinel value (NULL) is reached */
mystringarray* myfun3(mystringarray in, size_t size);
/* returns filtered array with actual size */
mysizedstringarray myfun4(mystringarray in, size_t size);
I needed a character array containing a dynamic number of character arrays based on the number of files in a specific folder. I was able to accomplish this by initializing char (*FullPathNames)[MAX_FILENAME_AND_PATHNAME_LENGTH] and then using FullPathNames = malloc( sizeof(*FullPathNames) * NumOfFiles * MAX_FILENAME_AND_PATHNAME_LENGTH ) ) after I know how many files another function discovered( which I have not provided). This process works flawlessly.
I can only use ANSI C; I am specifically using LabWindows CVI 8.1, to compile my code. I cannot use any other compiler. The below code is doing what I want. I can fill this array easily enough with the following code:
Strcpy(FullPathNames[0],”Test Word”);
char (*FullPathNames)[MAX_FILENAME_AND_PATHNAME_LENGTH];
size_t Size;
NumOfFiles = NumberOfUserFiles(“*.txt”, “C:\\ProgramData” );
FullPathNames = malloc( sizeof(*FullPathNames) * NumOfFiles * MAX_FILENAME_AND_PATHNAME_LENGTH ) );
Size = sizeof(*FullPathNames) * NumOfFiles;
Memset(FullPathNames,0,Size);
However, I would like to be able to pass FullPathNames which is an array of pointers to a variable amount of character arrays into a method. I want this method to be able to remove a single character array at a given index.
I am calling the method with the following code.
Remove_Element(FullPathNames,1, NumOfFiles);
The code for Remove_Element:
void Remove_Element( char (*Array)[MAX_FILENAME_AND_PATHNAME_LEN], int Index, int Array_Length )
{
int i;
char String[MAX_FILENAME_AND_PATHNAME_LEN];
char (*NewArray)[MAX_FILENAME_AND_PATHNAME_LEN];
int NewLength = Array_Length - 1;
size_t Size;
NewArray = malloc( sizeof( *NewArray) * NewLength * ( MAX_FILENAME_AND_PATHNAME_LEN ) );
Size = sizeof( *NewArray ) * NewLength;
memset(NewArray, 0, Size);
for ( i = Index; i < Array_Length - 1; i++ )
{
memcpy(String,Array[i+1],MAX_FILENAME_AND_PATHNAME_LEN); // Remove last index to avoid duplication
strcpy( Array[Index], String );
}
Array = NewArray;
}
My expectation of what I have currently is that the original data of FullPathNames remains except for the index that I removed, by copying data from index + 1, and the original pointers contained within FullPathNames is of course updated. Since I also wanted to shrink the array I attempted to set the array equal to the new array. The following information explains my attempts at debugging this behavior.
The watch variables present the following information as I enter the method.
FullPathNames = XXXXXX
NewArray = Unallocated
Array = XXXXXX
After I fill the new temporary Array the following happens:
FullPathNames = XXXXXX
NewArray = YYYYY
Array = XXXXXX
As I exit the method the following happens:
FullPathNames = XXXXXX
NewArray = YYYYY
Array = YYYYY
I was attempting to modify FullPathNames by passing it in as a pointer. I originally tried this task by using realloc but that just resulted in a free pointer exception.
Notes:
MAX_FILENAME_AND_PATHNAME_LENGTH = 516;
If I understand correctly, what you want to do is to modify the FullPathNames Pointer in the code part where you initialize your original array.
With your declartion of FullPatchNames
char (*FullPathNames)[MAX_FILENAME_AND_PATHNAME_LENGTH]
you basically declare a pointer to an array of MAX_FILENAME_AND_PATHNAME_LENGTH char elements. With your call to void Remove_Element(...) you just give a copy of this pointer to the local variable Array valid inside your function. Because of this Array = NewArray;, only changes the local copy of your pointer inside the function, not FullPathNames.
If you want to change the value of FullPathNames you must give a pointer to this pointer to your function. The Prototype of Remove_Element must look like this:
void Remove_Element( char (**Array)[MAX_FILENAME_AND_PATHNAME_LEN],
int Index, int Array_Length )
Now Array is a Pointer to an Pointer to an (one dimansional) array of char. By dereferencing this Pointer, you can change your original Pointer FullPathNames to point to your new object you created inside your function. You must modify the call to this function to Remove_Element(&FullPathNames,1, NumOfFiles);. To read from Array, you must dereference it using the * operator:
memcpy(String,*Array[i+1],MAX_FILENAME_AND_PATHNAME_LEN);
...
Array = NewArray;
Warning: This code will now produce a memory leak, since you are loosing your reference to your orignal object. You should remove this using the free() function somewhere in your code!
There seems to exist a certain lack of knowledge about the syntax in C language first and foremost.
char (*FullPathNames)[MAX_FILENAME_AND_PATHNAME_LENGTH]
This is one example. The syntax shown here would be read by a c- programmer as:
Semicolon is missing - maybe #define voodoo somewhere!
char (*FullPathNames)... - a function pointer! oh wait why square brackets next?!
Maybe he wanted to say char *FullPathNames; or he wanted char FullPathNames[MAX_FILENAME_AND_PATH_NAME_LENGTH]; Hm...
So here the first 101:
char foo[50]; // A fixed size array with capacity 50 (49 chars + '\0' max).
char *foo = NULL; // a uninitialized pointer to some char.
char (*foo)(); // a pointer to a function of signature: char(void).
char *foobar[50]; // This is an array of 50 pointers to char.
Depending on where your char foo[50]; is located (in the code file, in a function, in a structure definition), the storage used for it varies.
char foo1[50]; // zerovars section.
char foo2[50] = { 0 }; // initvars section
char foo3[50] = "Hello World!"; // also initvars section
void FooTheFoo( const char *foo )
{
if(NULL != foo )
{
printf("foo = %s\n", foo);
}
}
int main(int argc, const char *argv[])
{
char bar[50] = "Message from the past."; // bar is located on the stack (automatic variable).
FooTheFoo(bar); // fixed size array or dynamic array - passed as a (const pointer) in C.
return 0;
}
Now we got the basics down, lets look at 2-dimensional dynamic array.
char **matrix = NULL;
A pointer to a pointer of char. Or a pointer to an array of pointers to chars or an array of pointers to pointers to arrays of chars.
As lined out, there is no "meta" information regarding to what a char* or a char ** point to beyond that finally the dereferenced item will be of type char. And that it is a pointer to a pointer.
If you want to make a 2-dimensional array out of it, you have to initialize accordingly:
const size_t ROW_COUNT = 5;
const size_T COL_COUNT = 10;
char **myMatrix = malloc(sizeof(char *) * ROW_COUNT);
// check if malloc returned NULL of course!
if( NULL != myMatrix )
{
for(size_t row = 0; row < ROW_COUNT; row++ )
{
myMatrix[row] = malloc(sizeof(char) * COL_COUNT);
if( NULL == myMatrix[row] ) PanicAndCryOutLoudInDespair();
for(size_t col = 0; col < COL_COUNT; col++ )
{
myMatrix[row][col] = 0;
}
// of course you could also write instead of inner for - loop:
// memset(myMatrix[row], 0, sizeof(char) * COL_COUNT);
}
}
Last not least, how to pass such a 2-dimensional array to a function? As the char** construct does not contain the meta information regarding sizes, in the general (inner not a 0 terminated string) case, you would do it like that:
void FooIt( const char **matrix, size_t rowCount, size_t colCount )
{ // Note: standard checks omitted! (NULL != matrix, ...)
putchar(matrix[0][0]);
}
Last, if you want to get rid of your 2D dynamic array again, you need to properly free it.
void Cleanup2DArray( char **matrix, size_t rowCount )
{
for(size_t row = 0; row < rowCount; row++ )
{
free(matrix[row];
}
free(matrix);
}
The only thing more to say about it I leave to other gentle contributors. One thing coming to mind is how to express const-ness correctly for those multi-dimensional things.
const char **
const char const * const *
etc.
With this, you should be able to spot the places where you went wrong in your code and fix it.
The pointer you're passing is just a value. That it holds an address means you can dereference it to modify what it points to, but it doesn't mean changing its value directly (your assignment statement) will affect the caller-parameter. Like everything else in C, if you want to modify something by-address, then an address is exactly what you need to do it. If the thing you're modifying is a pointer, then the address of the pointer (through a pointer-to-pointer parameter) is the generally prescribed solution.
However, I can tell you the syntax and housekeeping to do that is... uninviting in your case. A simple pointer is easy enough, but a pointer-to-array-of-N isn't so simply. Were I you his would simply use the return result of the function itself, which is otherwise currently being unused and void. Declare your function like this:
char (*Remove_Element( char (*Array)[MAX_FILENAME_AND_PATHNAME_LEN],
int Index, int Array_Length ))[MAX_FILENAME_AND_PATHNAME_LEN]
{
....
return Array; // or whatever else you want to return so
// long as the type is correct.
}
and simply have the caller do this:
Array = RemoveElement(Array, Index, Array_Length);
A working variation of my solution appears below. The reason I had to do it this way is because while I was able to dereference (**Array)[MAX_FILENAME_AND_PATHNAME_LEN] I was only able to modify the first string array in the array.
The string array was initialized and filled several strings. While I could reference a string contained within *Array[0] but was unable to reference any of the other strings. The resulting array will replace the original array. This method will only work in the initial code block where the array to be replaced is initialized.
#define MAX_FILENAME_AND_PATHNAME_LEN MAX_FILENAME_LEN + MAX_PATHNAME_LEN
/*
This method was designed to free the memory allocated to an array.
*/
void FreeFileAndPathArrays( char (*Array)[MAX_FILENAME_AND_PATHNAME_LEN] )
{
free( Array );
}
/*
This method was designed to remove an index from an array. The result of this method will shrink the array by one.
*/
void Remove_Element( char (**ArrayPointer)[MAX_FILENAME_AND_PATHNAME_LEN],int Index, int *Array_Length, char (*Array)[MAX_FILENAME_AND_PATHNAME_LEN] )
{
int i = 0;
int j = 0;
char String[MAX_FILENAME_AND_PATHNAME_LEN];
char (*NewArray)[MAX_FILENAME_AND_PATHNAME_LEN];
char (*GC)[MAX_FILENAME_AND_PATHNAME_LEN];
int Length = *Array_Length;
int NewLength = Length - 1;
size_t Size;
NewArray = malloc( sizeof( *NewArray) * NewLength * ( MAX_FILENAME_AND_PATHNAME_LEN ) );
Size = sizeof( *NewArray ) * NewLength;
memset(NewArray, 0, Size);
UI_Display("Test Block:");
for ( j = 0; j < NewLength; j++ )
{
if ( j != Index )
{
memcpy(String,Array[j],MAX_FILENAME_AND_PATHNAME_LEN);
strcpy( Array[Index], String );
Fill(NewArray,String,j);
UI_Display(String);
}
}
GC = Array;
*ArrayPointer = NewArray;
free(GC);
*Array_Length = *Array_Length - 1;
}
/*
This method was designed to place a string into an index.
*/
void Fill( char (*Array)[MAX_FILENAME_AND_PATHNAME_LEN], const char * String, int Index)
{
strcpy( Array[Index], String );
}
/*
This method was designed to place fill each string array contained within the array of string arrays with 0's.
*/
void PrepareFileAndPathArrays( char (*FullPathNames)[MAX_FILENAME_AND_PATHNAME_LEN], int ROWS )
{
size_t Size;
Size = sizeof( *FullPathNames ) * ROWS;
memset(FullPathNames, 0, Size);
}
In a part of the program I'm working on I assign a name differently in different circumstances, but I want to keep the name either way, obviously. So I did something like so:
char *name;
if(*condition one*){
char namebuilder[30] = "";
//fill char array here
name = namebuilder;
} else {
name = info->name; //a char* from a struct
}
char otherstring[30] = "______________________________"
So basically the problem I'm having is that when the function takes the else route name sticks around and works just fine. But when it makes namebuilder and constructs the name, for some reason otherstring is ending up in the same address as name, and the name is getting overwritten with "__________________________". I don't understand why this is happening or how I can prevent it.
P.S: I've tested it by printing the addresses of name and otherstring, and they have the same address stored in them, but only if namebuilder was used.
Extra Background: this is a little program I'm making to mess around with pthreads, so it could possibly have to do with threading I guess, but none of the variables I mentioned are global.
EDIT: Here's the actual code for those of you asking.
struct thread_data
{
char *name;
int max;
};
void* race(void* params)
{
struct thread_data* info;
info = (struct thread_data*)params;
int len = strlen(info->name);
char* name;
if(info->max > len){
int i;
char newname[30] = "";
for(i = 0; i < info->max-1; i++){
if(i < len){
newname[i] = info->name[i];
} else {
char nextchar = randChar();
newname[i] = nextchar;
}
}
newname[info->max] = '\0';
name = newname;
} else {
name = info->name;
}
pthread_mutex_lock(&locker);
printf(name); //This correctly prints the name either way.
printf(" takes off!\n");
pthread_mutex_unlock(&locker);
//begin trying to spell here.
int spelt = 0;
char spelling[30] = "______________________________";
// All code after this sees name as "______________________________" only if it came
// from the if statement and not the else.
namebuilder was stored in the stack because it's local inside the if statement, after exiting the condition, it was marked as free, so when declaring otherstring, which have the exact same type and memory use as namebuilder, it took its place in the stack.
Here's how you can fix it:
char *name;
char namebuilder[30] = "";
if(*condition one*){
//fill char array here
name = namebuilder;
} else {
name = info->name; //a char* from a struct
}
char otherstring[30] = "______________________________";
Namebuilder is local to the if block. You need to lift it one scope up, or allocate it in dynamic memory with malloc() (don't forget to free() it when you're done !)
Your namebuilder is local to the if block. Which means that once you leave that and try to use your name, accessing the memory name points at now is UB. You'll either have to dynamically allocate the memory for namebuilder - which means you'd have to remember to clean it up later on - or you'd have to lift the declaration of namebuilder to the scope where it's being used.