List to list assignment becomes garbage - c

I'm having some trouble with the following:
void BuildList(cs460hwp hw)
{
FILE* fp;
fp = fopen("HW2input.dat", "r");
if(fp == NULL)
{
printf("Couldn't open the file.");
return;
}
int numStudents;
int i;
bool success;
char* dueDate = malloc(9*sizeof(char));
char* course = malloc(7*sizeof(char));
char* wsuid = malloc(9*sizeof(char));
char* subDate = malloc(9*sizeof(char));
double points1 = 0;
double points2 = 0;
cs460hwp stuInsert = NULL;
fscanf(fp, "%d", &numStudents);
fscanf(fp, "%s", dueDate);
for(i = 0; i < numStudents; i++)
{
stuInsert = malloc(sizeof(cs460hwp));
fscanf(fp, "%s %s %s %lf", course, wsuid, subDate, &points1);
strcpy(stuInsert->course, course);
strcpy(stuInsert->wsuid, wsuid);
strcpy(stuInsert->subdate, subDate);
stuInsert->points1 = points1;
stuInsert->points2 = CalculatePoints(dueDate, subDate, points1);
stuInsert->nextPtr = NULL;
if(hw == NULL)
{
hw = stuInsert;
}
else
{
stuInsert->nextPtr = hw;
hw = stuInsert;
}
}
free(course);
free(wsuid);
free(subDate);
free(dueDate);
PrintGrades(hw);
fclose(fp);
}
struct hwpoints
{
char course[7];
char wsuid[9];
char subdate[9];
double points1;
double points2;
struct hwpoints *nextPtr;
};
typedef struct hwpoints *cs460hwp;
My goal here is to insert every entry to the top of the list. However, whenever I try to assign anything to nextPtr (such as in the else clause), it gets filled with garbage values. They're mostly truncated versions of old data, which leads me to believe they're being taken from the heap. I've been reading (a lot), but I'm having trouble finding advice on this particular problem.
nextPtr always becomes junk, and nextPtr->nextPtr causes a segfault. For every iteration of the loop. hw remains fine, but its pointer value never gets updated properly.
Even when I've attempted to move the memory allocation for the struct into a function, I've had the same (or similar) issues.
Can anyone point me in the right direction?

Two problems.
1) As pb2q mentioned, you are passing a pointer to a struct and trying to assign what the arg points to. That's allowed by the compiler, but it doesn't do anything for you outside the function. It might be OK in your case if:
void main()
{
cs460hwp hw = NULL;
BuildList(hw);
return;
}
Is the whole of your function. I don't know the assignment so you need to figure out if that's acceptable to you or not.
2) The much bigger problem:
stuInsert = malloc(sizeof(cs460hwp));
Did you check what sizeof(cs460hwp) comes out to be? it's 4. You're allocating enough memory for the size of a pointer, not the size of your structure. I'm pretty sure this is not what you want to do and this is what is killing you. Just for kicks, replace it with malloc(100) and see if your problem goes away. If so you just need to figure out what size you really want. ;)

A problem with your BuildList function is that you're passing a pointer to a struct hwpoints, and you're trying to re-assign what the argument points to. Since function arguments in C are pass-by-value you're only changing the copy of the pointer that your function receives, and those changes won't be reflected in the caller.
You can use this pointer to modify the contents of the list: you can change e.g. hw->course or hw->nextPtr, you can move elements around in your list. But you can't change what the head, hw points to, so you can't insert elements at the beginning of the list.
If you want to change your head pointer, as in these statements:
hw = stuInsert;
// ...
hw = stuInsert;
Then you'll need to pass a pointer to the pointer:
void BuildList(cs460hwp *hw)
And de-reference it as necessary in the body of the function.
I can't be sure that this is the cause of the output that you're observing, which may be due to other problems. But if, after some number of calls to BuildList, beginning with a head pointer equal to NULL, you're trying to print your list assuming that it has valid nodes, you could see garbage data.
Thanks to #Mike's answer, we see also that you're not allocating enough space for your list nodes:
stuInsert = malloc(sizeof(cs460hwp));
Will only allocate enough space for a pointer, since cs460hwp is typedef'd to be a pointer to struct hwpoints. You need to allocate enough space for the structure, not a pointer to it:
stuInsert = malloc(sizeof(struct hwpoints));

Related

My program crashes when I set a pointer to a NULL

this is driving me nuts, I've done my homework but for some reason here
for (int i = 0; i < room->num_of_challenges; i++) { // need a check
if (strcmp(room_to_enter, room->challenges[i].challenge->name) == 0) {
room->challenges[i].start_time = start_time;
room->challenges[i].visitor = malloc(sizeof(room->challenges[i].visitor));
room->challenges[i].visitor->current_challenge = malloc(sizeof(room->challenges[i].visitor->current_challenge));
*room->challenges[i].visitor->current_challenge = room->challenges[i];
*room->challenges[i].visitor->room_name = NULL;
*room->challenges[i].visitor->room_name = malloc(strlen(room_to_enter)+1);
strcpy(*room->challenges[i].visitor->room_name, room_to_enter);
inc_num_visits(room->challenges[i].challenge);
}
}
the program just crashes for some reason, at this point:
*room->challenges[i].visitor->room_name = malloc(strlen(room_to_enter)+1);
it's a 3 pages code with headers for each, and each page is about 300 line, so I can't post them all, also here are the structs:
struct SChallengeActivity;
typedef struct SVisitor
{
char *visitor_name;
int visitor_id;
char **room_name;
struct SChallengeActivity *current_challenge;
} Visitor;
typedef struct SChallengeActivity
{
Challenge *challenge;
Visitor *visitor;
int start_time;
} ChallengeActivity;
typedef struct SChallengeRoom
{
char *name;
int num_of_challenges;
ChallengeActivity *challenges;
} ChallengeRoom;
We can't edit the struct because it's given by the homework like that, the thing is I tried to set this line to NULL, like so:
*room->challenges[i].visitor->room_name = NULL;
and it still crashes at that line too, for some reason it can't reach that field in the struct.
Note: ignore the coding, I know I should check the malloc after each line, but for now I want it to work, I've been up all night to get it to work, and I couldn't, any help please ?
Thank you
When allocating memory for the visitor, you are only allocating the aize of a pointer. The visitor field inside your challenge is only a pointer to a Visitor. Thus you are not allocating enough memory. You should use:
malloc(sizeof(Visitor))
To get the real size of the Visitor structure and allocate ample space.
Also, setting pointers to null before allocating is useless. The call to malloc() will overwrite them.
Also,
*room->challenges[i].visitor->room_name = NULL;
room_name is a char** (pointer-to-pointer), which means it's still a pointer, and you dereference it before it's set.
Not sure why it needs to be a pointer-to-pointer, but if it needs to be, then you first have to allocate memory for one or more pointers (eg array):
room->challenges[i].visitor->room_name = malloc(sizeof(char*)*1);
*room->challenges[i].visitor->room_name = malloc(strlen(room_to_enter)+1);
...

filling dynamically allocated struct inside function

I'm trying to make a function that accepts a pre-allocated memory pointer as input and fills an array of structs at that location with data. In this example, I expected the output to be:
W 100
L 200
However, the first line is correct, but the second line prints no character and a zero. What am I doing wrong?
typedef struct{
char word;
long number;
}record;
void makerec(record** data){
data[0]->word='W';
data[0]->number=100;
data[1]->word='L';
data[1]->number=200;
}
int main(){
record* data=(record*)malloc(sizeof(record)*1000);
makerec(&data);
printf("%c %ld\n",data[0].word,data[0].number);
printf("%c %ld\n",data[1].word,data[1].number);
free(data);
return 0;
}
You're not dealing with the right types. Simply change:
void makerec(record** data) {
to:
void makerec(record * data) {
and:
makerec(&data);
to:
makerec(data);
as well as changing data[0]->word='W'; and friends to data[0].word = 'W';
data is already a pointer, and you want to change the thing to which it points, so you can just pass it directly to makerec. You'd pass a pointer to data if you wanted makerec() to make it point to something different, but that's not what you're doing here, so just passing data itself is correct.
Incidental to your main issue, but:
record* data=(record*)malloc(sizeof(record)*1000);
should be:
record* data = malloc(1000 * sizeof *data);
if ( !data ) {
perror("memory allocation failed");
exit(EXIT_FAILURE);
}
Notes:
You don't need to (and, to my mind, shouldn't) cast the return value of malloc() and friends
sizeof *data is better than sizeof(record), since it continues to work if the type of data changes, and more importantly, it removes the possibility of you applying the sizeof operator to an incorrect type, which is a common mistake.
Reversing the positions of 1000 and sizeof *data is merely cosmetic, to make the multiple '*'s easier to comprehend.
You should always check the return value of malloc() in case the allocation failed, and take appropriate action (such as exiting your program) if it did.

Weird segfault occurence

typedef struct
{
char path[MAX_FILENAME*MAX_FOLDERS];
char filename[MAX_FILENAME];
time_t date;
off_t size;
} FILES;
This code works
FILES *fls = (FILES*)malloc(sizeof(FILES));
strcpy(fls[0].filename, "asd");
printf("%s\n", fls[0].filename);
fls = (FILES*)realloc(fls, 2);
strcpy(fls[1].filename, "asdfgh");
printf("%s\n", fls[0].filename);
printf("%s\n", fls[1].filename);
But here:
void allocateFileTree(FILES *tree,int i)
{
if(i==0)
tree = (FILES*)malloc(sizeof(FILES));
else
tree = (FILES*)realloc(tree, sizeof(FILES)*i);
}
in a loop
allocateFileTree(tree, i);
struct stat buff;
stat(entry -> d_name, &buff);
strcpy(tree[i].path, "whatever");//it gives segfault
i++;//this is never executed so realloc isn't the problem (yet)
Why and how can I solve this? What is so different that it crashes?
The code you say works really doesn't. One major problem is this line here
fls = (FILES*)realloc(fls, 2);
This reallocate the pointer to be two bytes. There's also a problem with this if the realloc call fails, as then you overwrite the only pointer you have with NULL, and therefore loose the original pointer and have a memory leak (besides the obvious problem of dereferencing a NULL pointer).
Your exact cause of the crash is because you don't allocate memory for the path member, so you're using an uninitialized pointer.
Both of the above leads to undefined behavior, which is a common cause of crashes.
And finally, in C you should not cast the return of malloc (and family).
While you allocate space for an array of FILES, you do not allocate storage for path in the code shown.
In the code
strcpy(tree[i].path, "whatever")
The value of tree[i].path is undefined. It might happen to point to space you can write to, or not.
This statement:
(FILES*)realloc(tree, sizeof(tree)*i);
allocates enough space for i pointers since tree is a FILES*. I think you want:
(FILES*)realloc(tree, sizeof(*tree)*i);
Your other problem is that you never actually update your tree pointer. The allocateFileTree() function only every updates it's local copy of the pointer to the new allocation.
You may want to try something like
FILES* allocateFileTree(FILES *tree,int i)
{
if(i==0)
tree = (FILES*)malloc(sizeof(FILES));
else
tree = (FILES*)realloc(tree, sizeof(FILES)*i);
return tree;
}
and call it like so:
tree = allocateFileTree(tree, i);

How do you pass a struct Pointer in C?

I am a little confused by how pointers are passed in functions by reference?
For instance, here's some code that I have written
(I didn't copy the entire function, just the part of it that is relevant)
metadata * removeBlock(metadata *first)
{
metadata *temp = first;
if(first == NULL || first -> prev == NULL)
{
first -> in_use = 1;
first = NULL;
return temp;
}
}
What I want is that when the function returns, the original value passed in should be set to NULL.
Here is how I call the function, (this line of code will pull a metadata structure from a region in heap, it works correctly, I have debugged and made sure that after this, struct really points to a valid metadata struct)
metadata *strct = ((metadata *)ptr - sizeof(metadata));
removeBlock(strct);
However, after this method returns, strct is still the same value it was before I had passed it in the function. I tried passing in &strct, but that just threw an invalid cast exception. What is the best way to pass in the struct as an argument?
Thankyou.
I don't think what you want is a good design - if the user of your function wants the pointer set to null (why?) it would make sense to reset the value using the return value from your function.
Anyway, you'll want a pointer-to-a-pointer, like so:
metadata* removeBlock(metadata** first) {
metadata* temp = *first;
if( temp == NULL ) return temp;
if( temp->prev == NULL ) {
temp->in_use = true;
*first = NULL;
}
return temp;
}
metadata* strct = ((metadata*)ptr - sizeof(metadata));
removeBlock(&strct);
As #SheerFish said, all we have in C is pass-by-value. However, one can simulate pass-by-reference with a pointer.
void func(struct foo **fooptr) { *fooptr = 0; }
int main(int argc, char **argv) { struct foo *fooptr; func(&fooptr); }
This is passing a pointer ptr to the variable's value (never mind if that value was a pointer), allowing the function to play with the original value with *ptr. This technique is sometimes called pass-by-address, and is the closest C has to pass-by-reference.
If you pass by 'reference in C', you're going to need to keep in mind referencing and de referencing via ->/** and *. This bit of code I wrote may help you a bit
int delete_node(struct node** head, int target)
{
if(*head == NULL)
return 0;
if((*head)->data == target)
{
temp = *head;
*head = (*head)->next;
free(temp);
return 1;
}
}
Function call:
delete_node(&head, data)
You're working with direct memory pointer manipulation. You're tossing the location of the struct in memory, de referencing it, then changing the value at that memory location.
I didn't read all of the details, but this part jumped out as incorrect:
(metadata *)ptr - sizeof(metadata)
Pointer arithmetic is done in the units of the type, whereas sizeof gives you measurements in bytes.
So I suspect what you're trying to say is:
(metadata *)(((char*)ptr) - sizeof(metadata))
This is also making some assumptions about the machine you're running on, i.e. metadata may need to be padded to ensure that the fields are properly aligned for this use. If sizeof(metadata) is not a multiple of the word size, this will fail on a lot of architectures. (But x86 will let it slide, albeit with performance costs and some implications like atomic ops not working on the fields.)
pointers are passed by value. anything in c is passed by value. so in order to change the pointer passed to the function, it should receive metadata **first.
besides, you should use
metadata *strct = ((metadata *)ptr - 1);
as pointer arithmetic is done with multiples of sizeof(*p). so this is equivalent to
metadata *strct = ((metadata *)((char*)ptr - sizeof(metadata)));

Seg Fault when copying a pointer

How come the following code result in seg fault? Basically after I copy the head pointer to temp, the head pointer gone.
typedef struct address * paddress; // defines struct pointer
void addAddressToList(paddress head, int addr[])
{
if (head == NULL) {
//head->addrArray = addr; // if list is initially empty
} else {
paddress temp;
temp = head;
while (temp->right != NULL) {
temp = temp->right; // go to end of the list
}
paddress newAddress = (paddress)malloc(sizeof(paddress*));
newAddress->intAddr = addr;
newAddress->right = NULL;
newAddress->left = temp; // connect the new address
temp->right = newAddress;
}
}
main() {
paddress addressListHead;
addressListHead = (paddress)malloc(sizeof(paddress*));
int intAddr1[] = {1,2,3,4,5,6,7};
char hexAddr1[] = "123456";
int intAddr2[] = {16,14,13,12,11};
char hexAddr2[] = "fedcb";
addressListHead->intAddr = intAddr1;
addressListHead->hexAddr = hexAddr1;
addAddressToList(addressListHead, intAddr2);
}
paddress addressListHead;
addressListHead = (paddress)malloc(sizeof(paddress*));
It seems to get rid of the compilation error, you have type casted what malloc is returning to paddress. addressListHead is a pointer, which means it can hold the address of an object but not the address of a pointer. The malloc here statement doesn't create an object. You need to change this -
addressListHead = (paddress)malloc(sizeof(paddress*));
to
addressListHead = (paddress)malloc(sizeof(struct address));
in main and addAddressToList functions.
Segmentation fault :
else {
paddress temp;
temp = head;
while (temp->right != NULL) {
temp = temp->right; // go to end of the list
}
I understand paddress::right is a pointer with the fact you are comparing it to NULL. But what is temp::right is initialized to. It is pointing to some garbage address and so you cannot ask for it to compare with NULL. Make it point to a valid memory location.
There is more than one problem in your code.
Firstly, the usual advice: stop using sizeof with type names (as much as possible). Use sizeof with expressions, not types. Type names belong in declarations and nowhere else.
Your problem with memory allocation could have been prevented if you used this malloc idiom
T *p = malloc(n * sizeof *p);
i.e. sizeof should be applied to *p, where p is the pointer to the array you are allocating and n is the total number of elements in that array. That way you never have to guess what type name you should specify under sizeof (an that way your code becomes type-independent).
In your case you are allocating just one object, so the code should look as
paddress newAddress = malloc(sizeof *newAddress);
(And don't cast the result of malloc - there's absolutely no point in doing that).
Secondly, when you the head element of the list, you need to initialize all the fields. Yet you never initialize right (or left) in the head element. Hence the crash even when the correct amount of memory is allocated.
In main(), you want
addressListHead = (paddress)malloc(sizeof(address));
That makes sure you get enough bytes to hold an address.
First error:
addressListHead = (paddress)malloc(sizeof(paddress*));
paddress* means a pointer to paddress which itself is a pointer to struct address. Hence paddress* is a pointer to a pointer to struct address. You would want to do:
addressListHead = (paddress)malloc(sizeof(struct address));
Also, I see that you made a similar mistake yesterday. Why do I get a seg fault? I want to put a char array pointer inside a struct
It's important to understand the concept of pointers properly. I would definitely recommend you to go through some tutorials on pointers. If you need help with that, let me know.

Resources