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.
Related
Although it seems a very basic and repeated question, but I did not find a similar question.
So, I want to create a structure contains holds some pointers.
In initialization, I allocate memory to all of them, but I do not assign new values to them.
here is my structure
typedef struct my_special_struct{
struct my_special_struct *ptr1;
struct my_special_struct *ptr2;
int val;
}my_special_struct;
and here is the initialization function
my_special_struct *create_struct(int value,struct my_special_struct pointer1){
my_special_struct *ptr;
ptr = (my_special_struct *)malloc(sizeof(my_special_struct));
ptr->val = value;
ptr->ptr1 = (my_special_struct *)malloc(sizeof(my_special_struct));
ptr->ptr1 = pointer1;
ptr->ptr2 = (my_special_struct *)malloc(sizeof(my_special_struct));
ptr->ptr2 = NULL;
return ptr;
}
During the program running, some of these pointers should got some values assigned dynamically.
Some times ptr2 got assigned with my_special_struct, and some times it remains empty.
my_special_struct *add_ptr2(struct my_special_struct ptr,struct my_special_struct pointer2){
ptr->ptr2 = pointer2;
return ptr;
}
At the end of the code, I want to free all the pointers that got assigned, here is the function
void delete_struct(struct my_special_struct ptr){
if (ptr->ptr1 != NULL){
delete_struct(ptr->ptr1);
}
else{
free(ptr->ptr1);
}
if (ptr->ptr2 != NULL){
delete_struct(ptr->ptr2);
}
else{
free(ptr->ptr2);
}
free(ptr);
}
So, my questions:
1- should I assign NULL to ptr2 in the create_struct function, or
just memory allocation is enough?
2- do I make a safe freeing the memory in the delete_struct
function?
3- if I called delete_struct(ptr->ptr2); function, and tried to
delete only ptr2, what will be the value of ptr->ptr2 ? and what
will happens exactly when I call delete_struct(ptr); ?
On surface, thisis a question on a binary tree.
For ptr2, as noted by commented, it's enough to assign NULL pointer. Allocating memory will just result in lost ("leaked") memory.
Sample code using recursive version of delete_struct. So that function should either delete the children, or delete the current element (but not both). Also good practice is to NULL delete pointers to avoid accidental resuse
Calling 'free' does not change the value of the pointer, it marked the memory area that available for re-use.
alternative delete + pointer cleanup.
void delete_struct(struct my_special_struct ptr){
if ( ptr != NULL ) {
delete_struct(ptr->ptr1);
ptr->ptr1 = NULL ;
delete_struct(ptr->ptr2);
ptr->ptr2 = NULL ;
free(ptr);
}
}
I have an array of pointers to structs.
struct key {
int *data;
};
struct key *entry = NULL;
entry = malloc(sizeof(entry));
Reallocated a bit of times:
node = realloc(node, (length+1)*sizeof(node[0]));
node[length].data = some_int;
In another part of my program, I want to iterate through it. I don't know how much elements it is containing at the moment.
for (i=0; &(node[i]) != NULL; i++)
length = i;
But I have infinity loop. Because:
(gdb) p node[i]
$1 = {data = 0x0}
It seems to like an uninitialized value, but it is not NULL pointer.
How to determine the end of an array?
Why it is not NULL pointer?
&(node[i]) takes the address of node[i].
So
&(node[i]) != NULL
will always be true, as the address of node[i] will always be different from NULL.
&(node[i]) is same as node + i and as long as node is not null and i is not zero, this will be non-null.
If you want to mark end of array, I would suggest always (re)allocate one extra element and initialize pointer member of termination with NULL.
struct key *temp = realloc(node, (length+2)*sizeof(node[0]));
if(NULL == temp) { /* Updated as per suggestion from #alk */
/* Handle error and return */
}
node = temp;
node[length].data = address_of(some_int);
node[length+1].data = NULL;
And later while looping
for (i=0; node[i].data != NULL; i++)
length = i;
But an even better solution would be to keep length you last used to realloc bundled with node. This way you won't need to calculate it using a loop.
I had a job interview and I was asked the following question:
The free() function is too "expensive." We want to implement a function
named myFree() with the prototype void myFree( void* p ).
myFree needs to save the pointer p in some way, instead of what
the free() function would do.
At the moment, when the programmer decides to free the pointers which he saved by the myFree function, he use the function myFinalFree().
I have only one global pointer that I can use when implementing myFree, therefore I can't allocate any extra memory.
Any ideas for myFree?
You can manage the pointers in a linked-list:
Initialize a global head=0
Inside function myFree(p):
Set the value at the address pointed by p to the value of head
Set the value of head to the value of p
Inside function myFinalFree():
Start from head and free all pointers until reaching 0
Set the value of head back to 0
Here is a coding example:
typedef int t_ptr;
static t_ptr head = 0;
void myFree(void* p)
{
if (p)
{
*(t_ptr*)p = head;
head = (t_ptr)p;
}
}
void myFinalFree()
{
t_ptr* p = (t_ptr*)head;
while (p)
{
head = *p;
free(p);
p = (t_ptr*)head;
}
}
Notes:
You have to make sure that sizeof(t_ptr) == sizeof(void*)
The above code works under the assumption that malloc always allocates at least sizeof(void*) bytes, aligned to an address which is a multiple of sizeof(void*)
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)));
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));