GIDForums  

Go Back   GIDForums > Computer Programming Forums > C Programming Language
User Name
Password
Register FAQ Members List Calendar Search Today's Posts Mark Forums Read

 
 
Thread Tools Search this Thread Rate Thread
  #1  
Old 08-Aug-2007, 11:38
aijazbaig1's Avatar
aijazbaig1 aijazbaig1 is offline
Member
 
Join Date: May 2006
Location: India
Posts: 156
aijazbaig1 has a spectacular aura aboutaijazbaig1 has a spectacular aura about
Lightbulb

need 'pointers' on deaing with segmentation faults


Hello there guys.
I have been reading various interesting posts on this forum about segmentation faults and I wish to now use the things learnt to debug my very own piece of code.

If u remember I had a post named 'Help Analyzing a Linked List' sometime back which got pretty bloated. Nevertheless I could finally implement my simple singly-Linked Linked list and the final (kind of) working code is repeated below.
CPP / C++ / C Code:
#include <stdio.h>
#include "list.h"

int main()
{
    printf("In testlist main()\n");
    List mylist;
    Listelmt *tmp_idx;

    char userinput[10];
    int ins_idx = 0,rem_idx = 0;
    int *mydata;
    int **remvd_data;
    //char user_ip;

    list_init(&mylist,deallocatelist);/*initialize the list during prog start*/
    while(1)
        {
            puts("The following functions are aval.");
            puts("please enter the number to select or q to quit followed by a return");
            printf("\t1. Insert an element in the list.\n\t2. Destroy the list.\n\t3. Remove an element.\n");
            printf("\t4. Display the list.\n");
            scanf("%s",userinput);
            //printf("you entered %c\n",userinput[0]);
            if(userinput[0] != '1' && userinput[0] != '2' && userinput[0] != '3' && userinput[0] != '4' && userinput[0] != 'q' && userinput[0] != 'Q')
                {
                    puts("invalid input");
                    return -1;
                }
            else
                {
                    switch (userinput[0])
                        {
                        case '1':
                            {                               
                                mydata = (int *)malloc(sizeof(int));
                                if (mydata == NULL)
                                    {
                                        puts("no. more space available");
                                        return -1;
                                    }
                                puts("enter the element");
                                scanf("%d",mydata);
                                if (mylist.size == 0)
                                        list_ins_nxt(&mylist,NULL,(void*)mydata);
                                else
                                    {
                                        puts("after how many elements do u want it to be inserted?");
                                        scanf("%d",&ins_idx);                                       
                                        if (ins_idx > mylist.size)
                                            {
                                                puts("you exceeded the number of elements");
                                                return -1;
                                            }
                                        //tmp_idx = (mylist.head)->next;
                                        tmp_idx = mylist.head;
                                        if (ins_idx > 0)
                                            {
                                                for(int i = 0;i < ins_idx-1;i++)
                                                    tmp_idx = tmp_idx->next;/*navigate thru to the needed element*/    
                                                list_ins_nxt(&mylist,tmp_idx,(void*)mydata);
                                            }
                                        else
                                            list_ins_nxt(&mylist,NULL,(void*)mydata);
                                    }
                                //free(tmp_idx);
                                break;
                            }
                        case '2':
                            {
                                list_destroy(&mylist);
                                //elmtcnt = 0;
                                break;
                            }
                        case '3':
                            {
                                if(mylist.size == 0)
                                    puts("nothing to remove");
                                else
                                    {
                                        puts("after how many elements do u wish to remove?");
                                        scanf("%d",&rem_idx);
                                        if (rem_idx > mylist.size)
                                            {
                                                puts("the entered number is invalid");
                                                return -1;
                                            }
                                        else
                                            {
                                                //tmp_idx = (mylist.head)->next;
                                                tmp_idx = mylist.head;
                                                for(int i = 0;i < ins_idx-1;i++)
                                                    tmp_idx = tmp_idx->next;/*navigate thru to the needed element*/
                                                list_rem_nxt(&mylist,tmp_idx,(void**)remvd_data);
                                                //elmtcnt--;
                                            }
                                    }
                                //free(tmp_idx);
                                break;
                            }
                        case '4':
                            {
                                displaylist(&mylist);
                                break;
                            }
                        case 'q':
                            return 0;
                        case 'Q':
                            return 0;
                        }
                }
        }           
}
The header file can be found from here. Just discard all the #defines in that file.

And the file list.c is here:
CPP / C++ / C Code:
#include <stdio.h>
#include <string.h>
#include "list.h"

void deallocatelist(void *ptr)/*this fn de-allocates a list pointed to by ptr*/
{
    Listelmt *temp;
    Listelmt *head = ptr;

    while (head) {
        temp = head -> next;
        free(head);
        head = temp;
    }
}

void list_init(List *list, void (*destroy)(void *data))/*initialize list depending on whats passed to data*/
{
  list -> size = 0;
  list -> destroy = destroy;
  list -> head = NULL;
  list -> tail = NULL;
}

void list_destroy(List *list)
{
    if (list -> size == 0)
        {
            puts("list empty, nothin removed"); 
            return;
        }
    //    else if (list -> destroy != NULL)
    else
        deallocatelist(list -> head);
    memset(list, 0, sizeof(list));
    return;
}

int list_ins_nxt(List *list, Listelmt *elmt, const void *data)
{
    Listelmt *new_element;
    new_element = (Listelmt *)malloc(sizeof(Listelmt));

    if (new_element == NULL)
                   return -1;
    else
        {
            new_element->data = (void*) data;
            if (list -> size == 0 && elmt == NULL) /*the list is empty*/
                {
                    /*list_init(list,NULL);*/
                list -> head = new_element;
                list -> tail = new_element;
                new_element -> next = NULL;
                (list -> size)++;
                }
            else
                {
                    if (elmt == NULL) /*insert new element at the start of the list*/
                        {
                            new_element -> next = list -> head;
                            list -> head = new_element;
                        }
                    else if (elmt -> next == NULL) /*insert new element at the end of the list*/
                        {
                            elmt -> next = new_element;
                            new_element -> next = NULL;
                            list -> tail = new_element;
                        }
                    else 
                        {
                            new_element -> next = elmt -> next;
                            elmt -> next = new_element;
                        }
                    (list -> size)++;

                }
        }
    //free(new_element); 
    return 0;
}

int list_rem_nxt(List *list, Listelmt *elmt, void **data)
{
    Listelmt *old_element;

    if (list -> size == 0) return -1;/*list is empty..nothin 2 remove*/
    else if (elmt == NULL) /*remove the head of the list*/
        {
            old_element = list -> head;
            data =  &(old_element -> data);
            list -> head = old_element -> next;
        }
    else if (elmt -> next == NULL) /*remove the tail of the list*/
        {
            old_element = list -> tail;
            data = &(old_element -> data);
            list -> tail = elmt;
        }
    else 
        {
            old_element = elmt -> next;
            data = &(old_element -> data);
            elmt -> next = old_element -> next;
        }
    //free(old_element);
    (list -> size)--;
    return 0;
}

void displaylist(List *list)
{
    Listelmt *tmp_elmt;
    int elmt_idx = 0;

    tmp_elmt = (list -> head);
    puts("");
    while (tmp_elmt -> next != NULL)
        {
            printf("\telement no. %d : %d\n ",elmt_idx,*(int*)(tmp_elmt->data));
            tmp_elmt = tmp_elmt->next;
            elmt_idx++;
        }
    if (tmp_elmt -> next == NULL)
            printf("\telement no. %d : %d\n ",elmt_idx,*(int*)(tmp_elmt->data));

    free(tmp_elmt);
    return;
}
This code is at times giving me the following error message on the console
Code:
Bus Error core dumped
A file called core gets created in the folder which contains the source file. It doesn't seem to be an ASCII file as it cannot be read by any text editor. Well I did try to track whats going on by using GDB (GNU debugger), to which i'm still pretty new as well.

To describe a typical testing sequence, I go on adding elements using the option 1 and in any order..ive tried inserting elements between two elements and ive tried adding elements to the tail and to the head and it seems to be working.

The problem seems to be that when i access the displaylist function for the second time, after inserting an element in the list, I get the bus error. Moreover, I think that the display list function is using some other variable (not the actual associated with list) to display the elements. This is because even after choosing option 2 for destroying the list, option 4 is still able to display the elements.

On using (my relatively amateurish skills with)gdb to track whats going on..i came across certain findings. when i tried adding a new element which falls somewhere between the head and the tail of the list, the variable mydata got allocated a memory location which was the present tail of the list, i.e. mydata was equal to list->tail even after the statement containing the malloc function was executed in testlist.c.

This obviously meant that we have two variables trying to access the same memory location and I suspected a segmentation fault and it very naturally gave the bus error. Well..what i do not get is why is malloc assigning such a location to mydata when it knows that list->tail already has possession over that piece of memory?

Furthermore as described earlier, when i tried to destroy the list before ever opting to print the contents, it was still able to print the contents of the list after executing the complete deallocatelist function. On using gdb again, it showed that the local head variable inside deallocatelist was being changed on every iteration of the while loop, but the head variable of the list (list->head that is) remained completely unchanged and so was the tail. Any clues??

Hope to hear from you guys,
__________________
Hope to hear from you guys!

--------------------------------------------------

Best Regards,
Aijaz Baig.
  #2  
Old 08-Aug-2007, 13:15
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 5,303
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold

Re: need 'pointers' on deaing with segmentation faults


Quote:
Originally Posted by aijazbaig1
when i tried adding a new element which falls somewhere between the head and the tail of the list, the variable mydata got allocated a memory location which was the present tail of the list, i.e. mydata was equal to list->tail even after the statement containing the malloc function was executed in testlist.c.

Once you notice things like this (courtesy of gdb or whatever), the idea is to figure out how that could happen. Look at your list_ins_next code:
CPP / C++ / C Code:
int list_ins_nxt(List * list, Listelmt * elmt, const void *data)
{
    Listelmt *new_element;
    new_element = (Listelmt *) malloc(sizeof(Listelmt));

    if (new_element == NULL)
        return -1;
    else {
        new_element->data = (void *) data;
.
.
.
Your malloc() statement allocates storage for the list element. One of the members of that struct is "data", which is a pointer. You never allocate storage for a new data value, you simply set the pointer value to whatever pointer value came in.

Consider something like the following:
CPP / C++ / C Code:
    Listelmt *new_element;
    if (new_element == NULL) {
        return -1; /* or whatever you need to do for failure */
    }
    new_element->data = malloc(sizeof(int));
    if (new_element-> == NULL) {
        return -1; /* or whatever you need to do for failure */
    }

    *(new_element->data) = *(int *)data;/* copy the data value */
.
.
.

If this is an example from an elementary book, I think that it's not very well suited for inexperienced programmers. All of the casting from void pointers to pointers to int (and vice-versa) that are there supposedly to make the algorithms generic in nature really get in the way of understanding the fundamentals of manipulating linked list structures.

Things like copying a pointer value rather than copying the data value that you get from the dereferenced pointer could happen to anyone, but to people without a lot of experience, it may be pretty hard to see, especially with the visual clutter of all of the casts that are required by these struct definitions.

And the bottom line is that it only works for ints anyhow. Any changes to make the list work for other data types will involve massive error-prone manual editing of every single one of the routines anyhow.

(But that's only an opinion, and I know that different people have different ways of teaching and different ways of learning. Things that work for some people might not be very good for others. I also know that not everyone agrees with my opinion(s), and that's OK. Really.)


Regards,

Dave
  #3  
Old 08-Aug-2007, 14:02
aijazbaig1's Avatar
aijazbaig1 aijazbaig1 is offline
Member
 
Join Date: May 2006
Location: India
Posts: 156
aijazbaig1 has a spectacular aura aboutaijazbaig1 has a spectacular aura about

Re: need 'pointers' on deaing with segmentation faults


Hi there Dave.

Quote:
Your malloc() statement allocates storage for the list element. One of the members of that struct is "data", which is a pointer. You never allocate storage for a new data value, you simply set the pointer value to whatever pointer value came in.

Hmm..so u mean I should create a new variable dynamically within the list_ins_nxt function such that it should be able to 'hold' the data value that would be inserted into the list, right?

So rather than allocating a memory location for the variable new_elmt I should allocate storage for the int. pointer that is passed in the form of the variable data.

Fine. I can see that from the modified code. However what does this statement stand for:
CPP / C++ / C Code:
if (new_element-> == NULL)

Does it mean that 'if whatever new_element points to is a NULL....' ?

And in the first if statement you directly compare the variable 'new_element' to NULL. I suppose since it is an auto variable, it will get created automatically on arrival at the function isn't it?..so we do not need to use malloc to create it.. Now that is a pretty handy tip you showed there!..

Well..I will try incorporating these changes in my program and see what ensues. By the way, do u have anything to comment on the deallocatelist function and the way I have tried to use it to destroy the list? It does not seem to do anything to the actual list variables outside the function.

And the thought of having the self-destructive destroy function a part of the list itself seems to be pretty bizarre to me. Is it normal practice amongst pros to do such a thing?

Waiting eagerly for your replies,
__________________
Hope to hear from you guys!

--------------------------------------------------

Best Regards,
Aijaz Baig.
  #4  
Old 08-Aug-2007, 15:17
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 5,303
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold

Re: need 'pointers' on deaing with segmentation faults


Quote:
Originally Posted by aijazbaig1
what does this statement stand for:
CPP / C++ / C Code:
if (new_element-> == NULL)
That was a mistake on my part, and would have given a compiler error. Since it followed
CPP / C++ / C Code:
new_element->data = malloc(sizeof(int));
It should have been
CPP / C++ / C Code:
if (new_element->data == NULL)
Quote:
Originally Posted by aijazbaig1
And in the first if statement you directly compare the variable 'new_element' to NULL.
CPP / C++ / C Code:
    Listelmt *new_element;
    new_element = (Listelmt *) malloc(sizeof(Listelmt))
    if (new_element == NULL)
The value returned by malloc is assigned to the pointer new_element. If malloc failed (the system couldn't give the program as much memory as it asked for), then malloc returns NULL (which is a pointer whose value is the equivalent to zero). Your struct has a pointer as its element. It must point to something. That what malloc does: It gives it something to point to so that data can be stored there.
Quote:
Originally Posted by aijazbaig1
...comment on the deallocatelist function ...
It looks like you have the right idea. You start at the head of the list and free each element as you go through the list. Now, with the extra malloc for the data item, you should free the memory for the data item also. I'm not sure why you say that it doesn't seem to do anything. If you have some specific question, use gdb or ask specifics here after you get everything else working.
Quote:
Originally Posted by aijazbaig1
...destroy function a part of the list
The "destroy" function is what deallocates the dynamic memory used by the list. And yes, you should always deallocate dynamic memory when you are through with the objects.

Now, you shouldn't free things until you are through with them. Here is a bug that could create some of your problems

CPP / C++ / C Code:
void displaylist(List *list)
{
    Listelmt *tmp_elmt;
    int elmt_idx = 0;
,.
.
.  Do some things with tmp_elmt
.
.
.
   free(tmp_elmt); /* <===NO! */
}
You didn't allocate any memory here with tmp_elmt. It may still be pointing to some element in your list that you don't want to annihilate. Why would you free that memory here??????


On the other hand in your "remove" function you don't free the memory allocated to the node that you are removing. That's a memory leak. It wouldn't cause this small program to crash or anything, and fixing it won't make this little program perform better, but it is a bug that should be fixed.


Note that when the program is terminated, the operating system reclaims memory and other resources that have been given to that process, but as long as a process is active, if it gets more and more resources without ever giving it back to the system, that's a problem. I think it's a good habit to getinto: deallocate dynamic memory objects when you are through with them, even though it might not be strictly necessary at the end of the program.

Regards,

Dave
  #5  
Old 15-Aug-2007, 07:58
aijazbaig1's Avatar
aijazbaig1 aijazbaig1 is offline
Member
 
Join Date: May 2006
Location: India
Posts: 156
aijazbaig1 has a spectacular aura aboutaijazbaig1 has a spectacular aura about

Re: need 'pointers' on deaing with segmentation faults


Hi.
Quote:
The value returned by malloc is assigned to the pointer new_element. If malloc failed (the system couldn't give the program as much memory as it asked for), then malloc returns NULL (which is a pointer whose value is the equivalent to zero). Your struct has a pointer as its element. It must point to something. That what malloc does: It gives it something to point to so that data can be stored there.
When I declare (and thereby define) a given variable, doesn't the compiler automatically allocate enough space for the variable from the heap of the program memory? I think the only difference in case of pointer variables is that the pointer now points to some random location in memory and dereferencing it might give bizarre results or even a seg fault as we do not have access over the piece of memory that this variable might now be pointing at. Am I right here?
Nevertheless, about the variable new_element, the program seems to be correctly displaying the elements in the list if I ignore the malloc statement and the free statement.

So as u said, new_element need not be freed as it is pointing at the variable of the type listelmt and doing so causes the bus error i'd think. Hence I have removed the free statement and also the malloc statement.

Now, moving over to the function deallocatelist, i will post the output of the gdb debugger to show how things look when i try to use the function to destroy the list. I make heavy use of the bt full and the print gdb commands which are used to show the contents of the stack alongwith all the local variables for the former and printing the value of the variable in question for the latter.

I set up a breakpoint at line 34 in list.c and when the execution reaches that place, i step thru the program and check the variables as i mentioned above.

By the way, I have renamed some variables to make it easy to understand if its a pointer or a piece of data. 'mydata' is now 'crrnt_data_ptr' and rmvd_data is now 'rmvd_data_handle'. Nevertheless, the variables inside the deallocatelist function have been left unchanged.

heres what i see as i enter deallocatelist function:
Code:
#0 deallocatelist (ptr=0x216a0) at list.c:8 temp = (Listelmt *) 0xff327684 //undefined as of yet head = (Listelmt *) 0xffbff4d8 //undefined as of yet #1 0x00010d90 in list_destroy (list=0xffbff5d0) at list.c:34 No locals. #2 0x00010ba0 in main () at testlist.c:71 mylist = {size = 3, match = 0, destroy = 0x10cc4 <deallocatelist>, head = 0x216a0, tail = 0x21670} tmp_idx = (Listelmt *) 0x21640 userinput = "2\000\000\000\000\000\000\000\000" ins_idx = 0 rem_idx = 0 crrnt_data_ptr = (int *) 0x21690 rmd_data_handle = (int **) 0x0
After the first 2 lines in the function I have:
Code:
temp = (Listelmt *) 0xff327684 //still undefined as expected..no assignment made head = (Listelmt *) 0x216a0 //now points to the head of the list.
After two lines in the 'While' loop:
Code:
temp = (Listelmt *) 0x21640 //points to head->next now head = (Listelmt *) 0x216a0 //still points to head..free didn't do anything!!
temp gets the correct value although the 'free(head)' statement seems to have done nothing here. Head is still equal to the list->head variable and hence it still is holding valid data and has not been returned to the system. Dereferencing that variable will still give me the data it holds.

hence the 'head' variable is merely toggled between the values of the listelmt address without those memory locations being actually freed from the program memory.

hence even after the whole cycle of 'seemingly' freeing the memory, on checking option 4, i am able to see all the elements of the list perfectly intact.

I guess I am missing something fundamental here. Eager to hear from you guys.
__________________
Hope to hear from you guys!

--------------------------------------------------

Best Regards,
Aijaz Baig.
  #6  
Old 15-Aug-2007, 10:22
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 5,303
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold

Re: need 'pointers' on deaing with segmentation faults


Quote:
Originally Posted by aijazbaig1
When I declare (and thereby define) a given variable, doesn't the compiler automatically allocate enough space for the variable from the heap
In fact, compilers use the stack for local (automatic) variables and they use the heap for dynamically-allocated memory (malloc(), calloc() and realloc()), but yes, they allocate memory automatically for local non-static variables. When an automatic variable goes out of scope (at the end of the block/function where they were declared), it is "deallocated" automatically. The value of an automatic variable is undefined unless there is an initializer given when the variable is declared. This is true for all automatic variables, including pointers.
Quote:
Originally Posted by aijazbaig1
The pointer now points to some random location in memory and dereferencing it might give bizarre results or even a seg fault as we do not have access over the piece of memory that this variable might now be pointing at. Am I right here?
You are absolutely correct. Dereferencing a pointer that does not point to a legally accessible memory location leads to undefined behavior. The behavior may be benign or it may do nothing at all, or it may change the value of some other program variable or it may cause a seg fault. Undefined is undefined.

Quote:
Originally Posted by aijazbaig1
Nevertheless, about the variable new_element, the program seems to be correctly displaying the elements in the list if I ignore the malloc statement and the free statement.

I don't have any idea what you are talking about. I don't see anywhere that you have used free(new_element) in the code that you have posted.

Please note: If you execute free(anypointer) it deallocates the memory that is pointed to by anypointer, and your program can not legally access that memory after that point. The variable anypointer itself is still there. You can't legally dereference it. You can't legally call free() with that variable again. It can be used again (that is: it can be assigned another value with another malloc() or whatever).

If you use free() to de-allocate some dynamic memory and the program subsequently tries to access that memory, the behavior is undefined. It may "just happen" that it seems to work for some test conditions if nothing in the system has caused that block of memory to be allocated somewhere else.

Undefined behavior means undefined. It is not guaranteed that violating some of the rules will always cause an error to manifest itself. It is still a program bug if you do it, and if getting the "right answer" makes you believe that it is not a bug, then that's too bad. Undefined means undefined.

There is absolutely nothing to be gained by trying to guess whether a given bug like this will always cause some particular behavior.
Quote:
Originally Posted by aijazbaig1


Now, moving over to the function deallocatelist, i will post the output of the gdb debugger
It is almost impossible for me to follow anyone else's steps through a debugger (even if i have the same setup and same compiler and same debugger), and I won't try. Maybe someone else will analyze your debugger output. Sorry.

For beginning programmers I suggest that they use print statements so that I can run their program on my system and display exactly what they are seeing. I have never been successful in following someone else's steps when they "tell me" what they did. Period.

Debuggers are powerful tools and even beginners can learn to use them effectively. It's just that I don't have the time or patience to try to step through things unless I am physically present and looking over their shoulder when they try to make it work.

One more time: Undefined behavior is undefined. Looking at unallocated memory with a debugger or with a print statement is absolutely unproductive. Why bother?
Quote:
Originally Posted by aijazbaig1
I guess I am missing something fundamental here.

Yes. You are wasting your time looking at memory blocks that have been deallocated (and therefore can not be legallly used by your program). SInce they can not be legally used by your program, why would you waste so much effort on trying to understand more about their contents?


Regards,

Dave
  #7  
Old 17-Aug-2007, 03:55
aijazbaig1's Avatar
aijazbaig1 aijazbaig1 is offline
Member
 
Join Date: May 2006
Location: India
Posts: 156
aijazbaig1 has a spectacular aura aboutaijazbaig1 has a spectacular aura about
Smile

Re: need 'pointers' on deaing with segmentation faults


Quote:
Please note: If you execute free(anypointer) it deallocates the memory that is pointed to by anypointer, and your program can not legally access that memory after that point. The variable anypointer itself is still there. You can't legally dereference it. You can't legally call free() with that variable again. It can be used again (that is: it can be assigned another value with another malloc() or whatever).

If you use free() to de-allocate some dynamic memory and the program subsequently tries to access that memory, the behavior is undefined. It may "just happen" that it seems to work for some test conditions if nothing in the system has caused that block of memory to be allocated somewhere else.

Undefined behavior means undefined. It is not guaranteed that violating some of the rules will always cause an error to manifest itself. It is still a program bug if you do it, and if getting the "right answer" makes you believe that it is not a bug, then that's too bad. Undefined means undefined.


In keeping with your suggestion to use printfs for you to track whats happening, I have made some small modifications to my original. However I have changed the variable names in a lot of different places and hence I show all the three source files again, (hoping it wont irritate people here ). Below that I have posted the output of the program when I use the 2nd option of destroying the list. The remove function hasn't been corrected as of yet. I'll leave it for later. By the way as you pointed above, it may so happen that I may still be able to use that memory location despite using free. Well, thats exactly whats happening. Hence I still can read the same data out of that memory location as I would before calling free with it. The only thing that I seemingly 'can' do now; is that I now have that memory location available to be written over to. Hence if I choose to insert new elements, I could do it from the start of the list and it would overwrite the contents of the previous locations.

Heres the source code:
testlist.c:
CPP / C++ / C Code:
#include <stdio.h>
#include "list.h"

int main()
{
    printf("In testlist main()\n");
    List mylist;
    Listelmt *tmp_idx;

    char userinput[10];
    int ins_idx = 0,rem_idx = 0;
    int *crrnt_data_ptr;
    int **rmd_data_handle;
    //char user_ip;

    list_init(&mylist,deallocatelist);/*initialize the list during prog start*/
    while(1)
        {
            puts("The following functions are aval.");
            puts("please enter the number to select or q to quit followed by a return");
            printf("\t1. Insert an element in the list.\n\t2. Destroy the list.\n\t3. Remove an element.\n");
            printf("\t4. Display the list.\n");
            scanf("%s",userinput);
            //printf("you entered %c\n",userinput[0]);
            if(userinput[0] != '1' && userinput[0] != '2' && userinput[0] != '3' && userinput[0] != '4' && userinput[0] != 'q' && userinput[0] != 'Q')
                {
                    puts("invalid input");
                    return -1;
                }
            else
                {
                    switch (userinput[0])
                        {
                        case '1':
                            {                               
                                crrnt_data_ptr = (int *)malloc(sizeof(int));
                                if (crrnt_data_ptr == NULL)
                                    {
                                        puts("no. more space available");
                                        return -1;
                                    }
                                puts("enter the element");
                                scanf("%d",crrnt_data_ptr);
                                if (mylist.size == 0)
                                        list_ins_nxt(&mylist,NULL,(void*)crrnt_data_ptr);
                                else
                                    {
                                        puts("after how many elements do u want it to be inserted?");
                                        scanf("%d",&ins_idx);                                       
                                        if (ins_idx > mylist.size)
                                            {
                                                puts("you exceeded the number of elements");
                                                return -1;
                                            }
                                        //tmp_idx = (mylist.head)->next;
                                        tmp_idx = mylist.head;
                                        if (ins_idx > 0)
                                            {
                                                for(int i = 0;i < ins_idx-1;i++)
                                                    tmp_idx = tmp_idx->next;/*navigate thru to the needed element*/    
                                                list_ins_nxt(&mylist,tmp_idx,(void*)crrnt_data_ptr);
                                            }
                                        else
                                            list_ins_nxt(&mylist,NULL,(void*)crrnt_data_ptr);
                                    }
                                //free(tmp_idx);
                                break;
                            }
                        case '2':
                            {
                                list_destroy(&mylist);
                                //elmtcnt = 0;
                                break;
                            }
                        case '3':
                            {
                                if(mylist.size == 0)
                                    puts("nothing to remove");
                                else
                                    {
                                        puts("after how many elements do u wish to remove?");
                                        scanf("%d",&rem_idx);
                                        if (rem_idx > mylist.size)
                                            {
                                                puts("the entered number is invalid");
                                                return -1;
                                            }
                                        else
                                            {
                                                //tmp_idx = (mylist.head)->next;
                                                tmp_idx = mylist.head;
                                                for(int i = 0;i < ins_idx-1;i++)
                                                    tmp_idx = tmp_idx->next;/*navigate thru to the needed element*/
                                                list_rem_nxt(&mylist,tmp_idx,(void**)rmd_data_handle);
                                                //elmtcnt--;
                                            }
                                    }
                                //free(tmp_idx);
                                break;
                            }
                        case '4':
                            {
                                displaylist(&mylist);
                                break;
                            }
                        case 'q':
                            return 0;
                        case 'Q':
                            return 0;
                        }
                }
        }           
}

list.h:
CPP / C++ / C Code:
#ifndef LIST_H
#define LIST_H

#include <stdlib.h>

typedef struct Listelmt_ {
  void *data_ptr;
  struct Listelmt_ *next;
}
Listelmt;

typedef struct List_ {
  int size;
  int (*match)(const void *key1, const void *key2);
  void (*destroy)(void *data);

  Listelmt *head;
  Listelmt *tail;
}
List;

void deallocatelist(void *ptr);
void list_init(List *list, void (*destroy)(void *lst_head));
void list_destroy(List *list);
void displaylist(List *list);
int list_ins_nxt(List *list, Listelmt *elmt, const void *data);
int list_rem_nxt(List *list, Listelmt *elmt, void **data);

#endif

list.c:
CPP / C++ / C Code:
#include <stdio.h>
#include <string.h>
#include "list.h"

void deallocatelist(void *ptr)/*this fn de-allocates a list pointed to by ptr*/
{
    Listelmt *temp;
    Listelmt *head = ptr;
    int iteration = 0;

    printf("\nbefore while,the var. head = 0x%p. head holds the following data = %d\n",head,*(int*)(head->data_ptr));
    while (head) {
        temp = head -> next;
        free(head);
        printf("\nIteration no. %d\n",++iteration);
        puts("I can still use that memory location after executing free");
        printf("head =0x%p,head now holds the following data = %d\n\n",head,*(int*)(head->data_ptr));/*this is what causes the elements to be printed even after*/
        head = temp;                                     /*deallocatelist has finished looping through the whole list*/ 
    }
}

void list_init(List *list, void (*destroy)(void *lst_head))/*initialize list depending on whats passed to data*/
{
  list -> size = 0;
  list -> destroy = destroy;
  list -> head = NULL;
  list -> tail = NULL;
}

void list_destroy(List *list)
{
    if (list -> size == 0)
        {
            puts("list empty, nothin removed"); 
            return;
        }
    //    else if (list -> destroy != NULL)
    else
        deallocatelist(list -> head);
    memset(list, 0, sizeof(list));
    return;
}

int list_ins_nxt(List *list, Listelmt *elmt, const void *crrnt_data_ptr)
{
    Listelmt *new_element;
    new_element = (Listelmt *)malloc(sizeof(Listelmt));

    if (new_element == NULL)
                   return -1;
    else
        {
            new_element -> data_ptr = malloc(sizeof(int));
            if (new_element -> data_ptr == NULL)
                {
                    puts("not enuf space..sorry");
                    return -1;
                }
            *(int*)(new_element->data_ptr) = *(int*) crrnt_data_ptr;
            if (list -> size == 0 && elmt == NULL) /*the list is empty*/
                {
                    /*list_init(list,NULL);*/
                list -> head = new_element;
                list -> tail = new_element;
                new_element -> next = NULL;
                (list -> size)++;
                }
            else
                {
                    if (elmt == NULL) /*insert new element at the start of the list*/
                        {
                            new_element -> next = list -> head;
                            list -> head = new_element;
                        }
                    else if (elmt -> next == NULL) /*insert new element at the end of the list*/
                        {
                            elmt -> next = new_element;
                            new_element -> next = NULL;
                            list -> tail = new_element;
                        }
                    else 
                        {
                            new_element -> next = elmt -> next;
                            elmt -> next = new_element;
                        }
                    (list -> size)++;

                }
        }
    //free(new_element); 
    return 0;
}

int list_rem_nxt(List *list, Listelmt *elmt, void **rmvd_data_handle)
{
    Listelmt *old_element;

    if (list -> size == 0) return -1;/*list is empty..nothin 2 remove*/
    else if (elmt == NULL) /*remove the head of the list*/
        {
            old_element = list -> head;
            rmvd_data_handle =  &(old_element -> data_ptr);
            list -> head = old_element -> next;
        }
    else if (elmt -> next == NULL) /*remove the tail of the list*/
        {
            old_element = list -> tail;
            rmvd_data_handle = &(old_element -> data_ptr);
            list -> tail = elmt;
        }
    else 
        {
            old_element = elmt -> next;
            rmvd_data_handle = &(old_element -> data_ptr);
            elmt -> next = old_element -> next;
        }
    //free(old_element);
    (list -> size)--;
    return 0;
}

void displaylist(List *list)
{
    Listelmt *tmp_elmt_handle;
    int elmt_idx = 0;

    //*tmp_elmt_handle = (Listelmt*)malloc(sizeof(Listelmt));//allocate space for the new elmt..initially holds the head
    tmp_elmt_handle = (list -> head);
    puts("");
    while (tmp_elmt_handle -> next != NULL)
        {
            printf("\telement no. %d : %d\n ",elmt_idx,*(int*)(tmp_elmt_handle -> data_ptr));
            tmp_elmt_handle = (tmp_elmt_handle->next);
            elmt_idx++;
        }
    if (tmp_elmt_handle -> next == NULL)
            printf("\telement no. %d : %d\n ",elmt_idx,*(int*)(tmp_elmt_handle->data_ptr));

    /*free(tmp_elmt_handle);*/
    return;
}

And it is this following piece of output that I am concerned about:
Code:
before while,the var. head = 0x217c0. head holds the following data = 6 Iteration no. 1 I can still use that memory location after executing free head =0x217c0,head now holds the following data = 6 Iteration no. 2 I can still use that memory location after executing free head =0x21790,head now holds the following data = 5 Iteration no. 3 I can still use that memory location after executing free head =0x217f0,head now holds the following data = 7
This thus shows that all those memory locations are still very much accessible and they show the same result as they did before 'free' was called with them. What I do not understand is that even after calling free with 'head', head still holds the same memory address though u said the memory address still remains but head should now be not accessible. I am getting a bit confused.

Could you also explain why we need the following in case of the list.h file:
CPP / C++ / C Code:
#ifndef LIST_H
#define LIST_H
and
CPP / C++ / C Code:
#endif
at the end of the file. What purpose does it serve?

Hope to hear from you,
__________________
Hope to hear from you guys!

--------------------------------------------------

Best Regards,
Aijaz Baig.
  #8  
Old 17-Aug-2007, 08:43
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 5,303
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold

Re: need 'pointers' on deaing with segmentation faults


Quote:
Originally Posted by aijazbaig1
Iu said the memory address still remains but head should now be not accessible. I am getting a bit confused.
I did not say it, "should be not accessible."

I chose my words very carefully. What I said was:
Quote:
Originally Posted by davekw7x
Dereferencing a pointer that does not point to a legally accessible memory location leads to undefined behavior.

Note the word legally. Note the word undefined. How many times did I use the word legally?

I don't mean that if you do something "illegal" in your C program that the C Police will knock down your door, put you in handcuffs, and carry you off to jail. I mean that if you do something that is "illegal" and it leads to undefined behavior then your program has a bug. Even though the bug may not manifest itself in your test case, it is a bug.

I also said
Quote:
Originally Posted by davekw7x
Undefined behavior is undefined. Looking at unallocated memory with a debugger or with a print statement is absolutely unproductive. Why bother?

If you want to print out values of the contents of memory that has been deallocated just to see what happens, you are perfectly free to do so (without fear of imprisonment), but I am really (really) not interested.

I really don't see any point, at this stage of the game, in investigating what happens when a program deliberately indulges in undefined behavior. You have already established that sometimes the memory still contains what had been previously stored there. So what? The behavior is still undefined.

The program is not guaranteed to crash, but it might. The system is not guaranteed to save old values in memory after it is deallocated, but it might. The C language allows you to do many things with invalid code with results that sometimes give something that you did or did not expect.


Sigh. End of transmission. Over and out. -30-


Regards,

Dave
Last edited by davekw7x : 17-Aug-2007 at 10:11.
 
 

Recent GIDBlogVista ?Widgets? on Windows XP by LocalTech

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
Sort an array of structures sassy99 C Programming Language 10 15-Feb-2007 08:46
Pointer Usage in C++: Beginner to Advanced varunhome C++ Forum 0 19-Aug-2005 10:25
[Tutorial] Pointers in C (Part II) Stack Overflow C Programming Language 0 27-Apr-2005 18:36
[Tutorial] Pointers in C (Part I) Stack Overflow C Programming Language 1 08-Apr-2005 19:35

Network Sites: GIDNetwork · GIDWebHosts · GIDSearch · Learning Journal by J de Silva, The

All times are GMT -6. The time now is 16:26.


vBulletin, Copyright © 2000 - 2010, Jelsoft Enterprises Ltd.