I am writing a program that has a bigger struct and a smaller struct, the smaller one holding names of friends of the person in index 0 of a 2D array in Friends. I wrote the whole thing from scratch a few times and it keeps giving me either seg fault or Thread 1: EXC_BAD_ACCESS (code=1, address=0x0).
Here are my structs:
expandBig() and expandFriends() do not assign values to the new data.
Looks like at least a problem is name assignment.
friends->name[friends->size] is not assigned a value after expandFriends(friends), so strcpy() fails.
void addFriend(Friends * friends, char * val) {
if(friends->size == friends->cap)
expandFriends(friends);
strcpy(friends->name[friends->size], val);
....
Consider using strdup()
// strcpy(friends->name[friends->size], val);
friends->name[friends->size] = strdup(val);
... and in InitializeFriends()
friend->name[i] = NULL;
Code such as below is tedious to review.
Was the size right? IDK, now have to trudge up to friend, find its type. OK that is Friends. Now look for Friends definition and see member char ** name. OK, now with char ** de-referenced we get char *. That matches codes sizeof(char*), so sizeof(char*) OK.
friend->name = realloc(friend->name, sizeof(char*) * friend->cap);
Save time. Code to the size of the de-referenced pointer, not the type. This is easier to code right, review and maintain.
Was the size right?
Yep, by construction, sizeof *(friend->name) is the right size.
// friend->name = realloc(friend->name, sizeof(char*) * friend->cap);
friend->name = realloc(friend->name, sizeof *(friend->name) * friend->cap);
// People * ret = (People*)calloc(DEFAULT_CAP, sizeof(People));
People * ret = calloc(DEFAULT_CAP, sizeof *ret);
Unclear why code sometimes casts the return from a *alloc() call and sometimes did not. The cast is not needed.
I am currently attempting to insert a string argument into a 2D array inside of a struct. The problem I am having is that I am not sure how to use realloc to dynamically increase the size of this 2D array inside the struct. Currently it is set up to use Malloc so I can test it for a single argument, which still is giving me a segmentation fault.
Here is the struct I am working with:
typedef struct SimpleCommand {
// Available space for arguments currently preallocated
int _numberOfAvailableArguments;
// Number of arguments
int _numberOfArguments;
// Array of arguments
char **_arguments;
}SimpleCommand;
//The struct is declared in Main as follows:
struct SimpleCommand _currentSimpleCommand = {._numberOfAvailableArguments = 0, ._numberOfArguments = 0, ._arguments = NULL};
The struct is then passed into a function thats job is to strcpy an argument into the 2D array inside the simple command struct.
//insert argument into simple command
void insertArgument(struct SimpleCommand command, char * argument ){
//malloc some space for the argument
command._arguments = malloc(strlen((argument)));
//copy argument into array
strcpy(command._arguments[command._numberOfArguments], argument);
command._numberOfArguments++; //added an argument
}
Any help is much appreciated!
I'm not sure I understand your problem, but here goes my deduction:
malloc allocates memory.
realoc realocates memory preserving, when possible, the data previously stored.
pseudo (not compiled)
int count = 10;
Thing * things = malloc(count * sizeof(Thing));
things[0] = athing;
// things[0] ... [9] is ok
// need more memory
count += 10;
Thing * things = realloc(things, count * sizeof(Thing));
// things[0] ... [19] is ok
// things[0] still hold athing
As you pointed out, you are using a 2D array. The line below looks suspicious:
command._arguments = malloc(strlen((argument)));
You are allocating size for a char* and storing it in a char**!!
In your problem you need to allocate space for your array of arguments and space to copy your arguments (if I understand what you are trying to do). One will need malloc as its size does not change. The other will need realloc as more arguments are added.
I hope this helps you complete your homework without giving you the full solution.
This question already has answers here:
Using Double Pointers after memory allocated within function
(3 answers)
Closed 7 years ago.
I'm new to c programming and wanted to write a helper function for myself that should do the following
Receiving a char** as first input parameter
Receiving const char* as second input parameter (path to file)
Reading in the file and populating char** with the read in lines
Returning the number of lines read in so that the calling function "knows" the size of the passed in array
The idea is to have a helper function that will do the job of reading in a file without needing to rewrite the logic all the time again.
I continuously received segmentation faults and therefore reduced this for debugging to the following test case (still not working):
Test function:
int test_read_in_file() {
char **arrayLinesOfFile;
int numberOfRowsReadIn = read_in_file("test_file.txt",
arrayLinesOfFile);
printf("%s\n", arrayLinesOfFile[0]); // gives segmentation fault
}
The function (reduced to a simple test for now):
int read_in_file(const char* pathToFile, char** linesOfFile) {
int numberOfRows = 5;
linesOfFile = (char**) malloc(numberOfRows * sizeof(char*));
linesOfFile[0] = malloc(10 * sizeof(char)); // just for testing
strcpy(linesOfFile[0], "Andreas"); // just for testing
printf("%s\n",linesOfFile[0]); // this works fine, output "Andreas"
return numberOfRows;
}
When running this test case, the printf statement in the function works fine, the printf in the test runner gives a segmentation fault.
I don't understand why this is happening. In my understanding linesOfFile would be passed by references, then I allocate memory for the first element and then sufficient elements to hold "Andreas" in the first element.
Any help would be highly appreciated.
Thanks
Andreas
C uses pass-by-value. You need to pass the address of arrayLinesOfFile so that allocated memory is reflected in the calling function.
In other words, when you pass arrayLinesOfFile to read_in_file, a local pointer to a pointer to a char is made named linesOfFile in read_in_file and it points to the location where arrayLinesOfFile points to. When you use
linesOfFile = (char**) malloc(numberOfRows * sizeof(char*));
linesOfFile is made to point to the start of the allocated memory segment. This doesn't have any effect on arrayLinesOfFile in the other function. So, arrayLinesOfFile remains uninitialized. This explains the seg-faults.
So change
int numberOfRowsReadIn = read_in_file("test_file.txt",
arrayLinesOfFile);
to
int numberOfRowsReadIn = read_in_file("test_file.txt",
&arrayLinesOfFile);
and the read_in_file function to:
int read_in_file(const char* pathToFile, char*** linesOfFile) {
int numberOfRows = 5;
*linesOfFile = malloc(numberOfRows * sizeof(char*));
(*linesOfFile)[0] = malloc(10 * sizeof(char)); // just for testing
strcpy((*linesOfFile)[0], "Andreas"); // just for testing
printf("%s\n",(*linesOfFile)[0]); // this works fine, output "Andreas"
return numberOfRows;
}
Other changes I made in the code are
Removing the cast from malloc
Add parenthesis here (*linesOfFile)[0] because of operator precedence.
I have the following structs as example:
#define MAX_PEOPLE 16
typedef struct {
int age;
}Person;
typedef struct {
Person *people;
int numPeople;
}Team;
I'm trying to allocate an array of persons in a function, passed by parameters. My Team is supposed to store an array of 16 pointers of Person. I can't figure out what I'm doing wrong.
void initiateTeam(Team * team){
team->numPeople = MAX_PEOPLE;
Person *p[MAX_PEOPLE];
for(int i=0; i<MAX_PEOPLE;i++){
p[i] = malloc(sizeof(Person);
}
team->people = &p[0];
}
I printed out the addresses of my team->people[i] and I'm getting random junk. Why is the assingment team->people = &p[0] wrong? Shouldn't it get the first address of my array then perform pointer arithmetic?
You are pointing team->people to a statically defined array of person pointers. Once the function ends, the stack pointer moves back to where main left off, erasing all previously local memory in the addPeople function. You need to malloc p, and return it from the function
Since in the comments you stated that you're trying to allocate an array of Person objects and not pointers, you should rather do:
void addPeople(Team * team){
team->numPeople = MAX_PEOPLE;
team->people = malloc(sizeof(Person) * MAX_PEOPLE);
}
mind that there's no * in sizeof since you don't want an array of pointers but of objects. You will later be able to access the single elements (i.e. each Person object) with
team->people[2].age = 25; // The third person in the array
Finally, remember to free your memory.
your variable p is allocated in the stack of the addPeople() function. The assignment team->people = &p[0] (which is equivalent to team->people = p) is valid but dangerous because that address will be invalid as soon as the function is finished.
Better create p with malloc(sizeof (Person *) * MAX_PEOPLE) instead of using the stack.
The problem is here:
Person *p[MAX_PEOPLE];
This allocates a local variable in the function to hold the array of people pointers.
You get the address of this local variable and send it back. As soon as you are not in the function the local data is freed. It was just allocated locally. It is no longer valid. I might work for a while or it might not depending on the the program does next.
You want this:
Person **p = (Person **)malloc(sizeof (Person *) * MAX_PEOPLE);
I think you are getting the thing with pointer and memory management in C a little bit wrong. Consider reading a little bit more about it, before you continue coding your application.
Beside, I think you do not need an array of pointers to persons, but an array of persons.
Your struct is correct, but I would implement your function like that:
void addPeople(Team * team){
team->numPeople = MAX_PEOPLE;
team->people = malloc(sizeof(Person) * MAX_PEOPLE);
}
And do not forget to free() your team->people.
But if MAX_PEOPLE is an pre processor define, then it is totally unnecessary to use memory from the heap. If you are not storing too many people in your struct, the stack can easily fulfill your requirements.
I apologize if this is a waste of time and/or not what should be on this site, but I'm kind of out of ideas... I'm still a novice at programming, can't get a hold of my teacher for guidance, so... TO THE INTERNET!
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void months( FILE* monthfp, char** monthGroup );
int main (void){
FILE *monthfp; /*to be used for reading in months from months.txt*/
char** monthGroup;
int i;
if (( monthfp = fopen ( "months.txt", "r" )) == NULL ){
printf( "unable to open months.txt. \n" );
exit ( 1 );
}
months( monthfp, monthGroup );
/*test so far*/
for ( i = 0; i < 12; i++ ){
printf( "%s", monthGroup[i] );
}
fclose( monthfp );
}
void months ( FILE* monthfp, char** monthGroup ){
/*****************************************
name: months
input: input file, data array
returns: No return. Modifies array.
*/
char buffer[50];
int count = 0;
while ( fgets( buffer, sizeof(buffer), monthfp ) != NULL ){
count++;
monthGroup = malloc( count * sizeof ( char* ));
monthGroup[count] = malloc( sizeof( buffer ) * sizeof( char ));
strcpy(monthGroup[ count - 1 ], buffer );
}
}
I'm compiling in C89, everything seems to work, except for a segmentation fault. Any guidance would be very much appreciated.
edit
Thanks to everyone who took the time to provide a little bit of insight into something I've been having trouble wrapping my head around. I feel like a little kid in a village of elders in a foreign land. Much appreciation for the courtesy and guidance.
I'm afraid you don't realize how far you are from getting it right. Sit tight, this is going to be long. Welcome to C.
char** monthGroup
All this really means is "a pointer-to-pointer-to-char". However, C has many reasons why you would want to point to something. In your case, the "inner" pointing is so that you can actually point at a sequence of chars in memory (which you colloquially treat as a "string", which C properly does not have), and the "outer" pointing is so that you can point at a sequence of those char*s, and treat that sequence as an "array" (even though it isn't; you're going to dynamically allocate it).
Here's the problem: When you pass in this char** that came from main, it doesn't actually point at anything. "That's fine", you say; "the function is going to make it point at some memory that I'll allocate with malloc()".
Nope.
C passes everything by value. The char** that months receives is a copy of the char** in main's chunk of local variables. You overwrite the pointer (with the result of the malloc call), write some pointers into that pointed-at memory (more malloc results), copy some data into those chunks of pointed-at memory... and then, at the end of the function, the parameter monthGroup (which is a local variable in months) no longer exists, and you've lost all that data, and the variable monthGroup in main is still unchanged at pointing at nothing. When you try to use it as if it points at something, boom you're dead.
So how do we get around this? With another level of pointing, of course, C properly does not have "pass by reference", so we must fake it. We accept a char***, and pass it &monthGroup. This is still a copied value, but it points directly into the local variable storage for that invocation of main (on the stack). That lets us write a value that will be visible in main. We assign the first malloc result to *monthGroup, and write pointers into that storage (*monthGroup[count]), etc.
Except we don't really want to do that, because it's incredibly ugly and confusing and hard to get right. Let's instead do what should be an incredibly obvious thing that you're meant to do and that basic instruction doesn't emphasize nearly enough: use the return value of the function to return the result of the calculation - that's why it's called the return value.
That is, we set up a char** in months (not accepting any kind of parameter for it), return it, and use it to initialize the value in main.
Are we done? No.
You still have some logical errors:
You re-allocate the "outer" layer within your while-loop. That's clearly not what you want; you're allocating several "strings", but only one "array", so that allocation goes outside the loop. Otherwise, you throw away (without properly deallocating them!) the old arrays each time.
Actually, you do want to do something like this, but only because you don't know in advance how many elements you need. The problem is that the new allocation is just that - a new allocation - not containing the previously-set-up pointers.
Fortunately, C has a solution for this: realloc. This will allocate the new memory, copy the old contents across (the pointers to your allocated "strings"), and deallocate the old chunk. Hooray! Better yet, realloc will behave like malloc if we give it a NULL pointer for the "old memory". That lets us avoid special-casing our loop.
You're using the value count incorrectly. The first time through the loop, you'll increment count to 1, allocate some space for monthGroup[1] to point at, and then attempt to write into the space pointed at by monthGroup[0], which was never set up. You want to write into the same space for a "string" that you just allocated. (BTW, sizeof(char) is useless: it is always 1. Even if your system uses more than 8 bits to represent a char! The char is the fundamental unit of storage on your system.)
Except not, because there's a simpler way: use strdup to get a pointer to an allocated copy of your buffer.
char** months(FILE* monthfp) {
char buffer[50];
int count = 0;
char** monthGroup = NULL;
while (fgets(buffer, sizeof(buffer), monthfp) != NULL) {
// (re-)allocate the storage:
monthGroup = realloc(monthGroup, count * sizeof(char*));
// ask for a duplicate of the buffer contents, and put a pointer to the
// duplicate sequence into the last element of the storage:
monthGroup[count - 1] = strdup(buffer);
}
return monthGroup;
}
Adjusting main to match is left as a (hopefully trivial) exercise. Please also read the documentation for realloc and strdup.
Are we done? No.
You should still be checking for NULL returns from realloc and strdup (since they both attempt to allocate memory, and thus may fail in that way in C), and you still need code to free the allocated memory.
And, as others pointed out, you shouldn't be assuming there will be 12 months. If you could assume that, you wouldn't be dynamically allocating monthGroup in the first place; you'd just use an array. So you need to communicate the size of the result "array" somehow (adding an explicit NULL pointer to the end is one way; another is to do the horribly ugly thing, pass in a char***, and use the return value to count the size).
C has pass-by-value semantics for function calls. This is a fancy way of saying that
int main() {
int a = 5;
addOneTo(a);
printf("%d\n", a);
return 0;
}
will print 5 no matter what addOneTo() does to its parameter.
In your code, your months() function sets its local variable monthGroup to the value returned by the first malloc(), then throws away that value when it returns.
You have a few choices here on how to fix this problem. You could malloc into monthGroup outside the months() function then pass it in. You could return the monthGroup value. Or you could pass a pointer to monthGroup for pass-by-reference semantics (char***).
In any case, I would encourage you to learn how to use a debugger (e.g. gdb) so you can see why it segfaults next time!
Your problem lies in the months function, specifically your understanding of how memory works.
Looking at your code:
monthGroup = malloc( count * sizeof ( char* ));
This line allocates a chunk of memory which is equivalent to an array of char * of size count.
monthGroup[count] = malloc( sizeof( buffer ) * sizeof( char ));
Here, a buffer is allocated of size sizeof (buffer) (the sizeof (char) is unneccesary). This is one problem here: you are assigning it to monthGroup[count]. Arrays in C are zero-base, which means that the array:
int array [3];
has elements:
array [0], array [1] and array [2]
array [3] is outside the memory of the array. So monthGroup[count] is also outside the memory of the array. You want monthGroup[count-1] instead. This will write to the last element in the array.
The second problem is that every time you do the first allocation, you lose the previously allocated data (this is know as a memory leak) and the data it contained.
To fix this, there are two approaches.
When allocating the array, copy the contents of the old array to the new array:
oldarray = monthGroup;
monthGroup = malloc (count * sizeof (char *))
memcpy (monthGroup, oldarray, count-1 * sizeof (char *));
free (oldarray);
monthGroup [count-1] = ....
or use realloc.
Use a linked list. A lot more complex this one but has the advantage of not requiring the arrays to be copied every time a new item is read.
Also, the monthGroup parameter doesn't get passed back to the caller. Either change the function to:
char **months (FILE *fp)
or:
void months (FILE *fp, char ***ugly_pointer)
Finally, the caller currently assumes that there are 12 entries and attempts to print each one out. What happens if there are fewer than 12, or more than 12? One way to cope is to use a special pointer to terminate the monthsGroup array, a NULL would do nicely. Just allocate one extra element to the array and set the last one to NULL.
To me the most obvious of your problems is that you pass char** monthGroup as a parameter by value, then malloc it inside the function months, and afterwards try to use it in the caller function. However, since you passed it by value, you only stored the malloced address in a local copy of monthGroup, which does not change the value of the original variable in main.
As a quick fix, you need to pass a pointer to monthGroup, rather than (a copy of) its current value:
int main (void){
...
char** monthGroup;
...
months( monthfp, &monthGroup );
...
}
void months ( FILE* monthfp, char*** monthGroup ){
...
*monthGroup = malloc( count * sizeof ( char* ));
...
}
This is ugly (IMHO there should be no real reason to use char*** in real code) but at least a step in the right direction.
Then, as others rightly mentioned, you should also rethink your approach of reallocating monthGroup in a loop and forgetting about the previous allocations, leaving memory leaks and dangling pointers behind. What happens in the loop in your current code is
// read the first bunch of text from the file
count++;
// count is now 1
monthGroup = malloc( count * sizeof ( char* ));
// you allocated an array of size 1
monthGroup[count] = malloc( sizeof( buffer ) * sizeof( char ));
// you try to write to the element at index 1 - another segfault!
// should be monthGroup[count - 1] as below
strcpy(monthGroup[ count - 1 ], buffer );
Even with the fix suggested above, after 10 iterations, you are bound to have an array of 10 elements, the first 9 of which are dangling pointers and only the 10th pointing to a valid address.
The completed code would be this:
int main (void)
{
FILE *monthfp; /*to be used for reading in months from months.txt*/
char **monthGroup = NULL;
char **iter;
if ((monthfp = fopen("c:\\months.txt", "r")) == NULL){
printf("unable to open months.txt. \n");
exit(1);
}
months(monthfp, &monthGroup);
iter = monthGroup;
/* We know that the last element is NULL, and that element will stop the while */
while (*iter) {
printf("%s", *iter);
free(*iter);
iter++;
}
/* Remember that you were modifying iter, so you have to discard it */
free(monthGroup);
fclose(monthfp);
}
void months(FILE *monthfp, char ***monthGroup)
{
/*****************************************
name: months
input: input file, data array
returns: No return. Modifies array.
*/
char buffer[50];
int count = 0;
while (fgets(buffer, sizeof(buffer), monthfp) != NULL){
count++;
/* We realloc the buffer */
*monthGroup = (char**)realloc(*monthGroup, count * sizeof(char**));
/* Here I'm allocating an exact buffer by counting the length of the line using strlen */
(*monthGroup)[count - 1] = (char*)malloc((strlen(buffer) + 1) * sizeof( char ));
strcpy((*monthGroup)[count - 1], buffer);
}
/* We add a terminating NULL element here. Other possibility would be returning count. */
count++;
*monthGroup = (char**)realloc(*monthGroup, count * sizeof(char**));
(*monthGroup)[count - 1] = NULL;
}
As said by others a char*** is ugly.
The principal error that I see immediately, is that your allocation for monthGroup will never make it back into your main.