Segmentation fault / list initializing
I want to create a list with the following structure:
- list.h: Contains function prototypes and defines data types
- lt.c: main function to test the list
- list.c: actual implementation of the list
When executing it I always get a segfault error. When trying to identify it with gdb it is shown that it is the fault of the following line in lt.c:
list_t *li=list_init();
The rest of my lt.c file looks as follows:
#include <stdio.h>
#include <stdlib.h>
#include "list.h"
int main ( int argc, char *argv [ ], char *envp [ ] )
{
list_t *li=list_init();
//li=list_init();
/* if((li=list_init())==NULL)
{
perror (" Cannot allocate memory" ) ;
exit(-1);
}*/
}
My implementation of the list.c function list_init() is as follows:
list_t *list_init ()
{
list_t* newlist = malloc(sizeof(*newlist));
if (!newlist)
{
perror ("malloc-newlist");
exit (EXIT_FAILURE);
}`enter code here`
//newlist->first=NULL;
//newlist->last=NULL;
newlist->first = (struct list_elem *) malloc(sizeof(struct list_elem));
newlist->last = (struct list_elem *) malloc(sizeof(struct list_elem));
return newlist;
}
My list.h file is as follows:
struct list_elem {
struct list_elem *next; // Zeiger auf das naechste Element
char *data; // Zeiger auf ein Datenobject
};
typedef struct list {
struct list_elem *first;// erstes Element in der Liste
struct list_elem *last; // letztes Element in der Liste
} list_t;
/* function prototypes */
list_t *list_init ();
However, I do not know how I could change the implementation so that it does not occur anymore.
Thank you very much for your help.
c
add a comment |
I want to create a list with the following structure:
- list.h: Contains function prototypes and defines data types
- lt.c: main function to test the list
- list.c: actual implementation of the list
When executing it I always get a segfault error. When trying to identify it with gdb it is shown that it is the fault of the following line in lt.c:
list_t *li=list_init();
The rest of my lt.c file looks as follows:
#include <stdio.h>
#include <stdlib.h>
#include "list.h"
int main ( int argc, char *argv [ ], char *envp [ ] )
{
list_t *li=list_init();
//li=list_init();
/* if((li=list_init())==NULL)
{
perror (" Cannot allocate memory" ) ;
exit(-1);
}*/
}
My implementation of the list.c function list_init() is as follows:
list_t *list_init ()
{
list_t* newlist = malloc(sizeof(*newlist));
if (!newlist)
{
perror ("malloc-newlist");
exit (EXIT_FAILURE);
}`enter code here`
//newlist->first=NULL;
//newlist->last=NULL;
newlist->first = (struct list_elem *) malloc(sizeof(struct list_elem));
newlist->last = (struct list_elem *) malloc(sizeof(struct list_elem));
return newlist;
}
My list.h file is as follows:
struct list_elem {
struct list_elem *next; // Zeiger auf das naechste Element
char *data; // Zeiger auf ein Datenobject
};
typedef struct list {
struct list_elem *first;// erstes Element in der Liste
struct list_elem *last; // letztes Element in der Liste
} list_t;
/* function prototypes */
list_t *list_init ();
However, I do not know how I could change the implementation so that it does not occur anymore.
Thank you very much for your help.
c
Comments are not for extended discussion; this conversation has been moved to chat.
– Samuel Liew♦
Nov 25 '18 at 3:53
add a comment |
I want to create a list with the following structure:
- list.h: Contains function prototypes and defines data types
- lt.c: main function to test the list
- list.c: actual implementation of the list
When executing it I always get a segfault error. When trying to identify it with gdb it is shown that it is the fault of the following line in lt.c:
list_t *li=list_init();
The rest of my lt.c file looks as follows:
#include <stdio.h>
#include <stdlib.h>
#include "list.h"
int main ( int argc, char *argv [ ], char *envp [ ] )
{
list_t *li=list_init();
//li=list_init();
/* if((li=list_init())==NULL)
{
perror (" Cannot allocate memory" ) ;
exit(-1);
}*/
}
My implementation of the list.c function list_init() is as follows:
list_t *list_init ()
{
list_t* newlist = malloc(sizeof(*newlist));
if (!newlist)
{
perror ("malloc-newlist");
exit (EXIT_FAILURE);
}`enter code here`
//newlist->first=NULL;
//newlist->last=NULL;
newlist->first = (struct list_elem *) malloc(sizeof(struct list_elem));
newlist->last = (struct list_elem *) malloc(sizeof(struct list_elem));
return newlist;
}
My list.h file is as follows:
struct list_elem {
struct list_elem *next; // Zeiger auf das naechste Element
char *data; // Zeiger auf ein Datenobject
};
typedef struct list {
struct list_elem *first;// erstes Element in der Liste
struct list_elem *last; // letztes Element in der Liste
} list_t;
/* function prototypes */
list_t *list_init ();
However, I do not know how I could change the implementation so that it does not occur anymore.
Thank you very much for your help.
c
I want to create a list with the following structure:
- list.h: Contains function prototypes and defines data types
- lt.c: main function to test the list
- list.c: actual implementation of the list
When executing it I always get a segfault error. When trying to identify it with gdb it is shown that it is the fault of the following line in lt.c:
list_t *li=list_init();
The rest of my lt.c file looks as follows:
#include <stdio.h>
#include <stdlib.h>
#include "list.h"
int main ( int argc, char *argv [ ], char *envp [ ] )
{
list_t *li=list_init();
//li=list_init();
/* if((li=list_init())==NULL)
{
perror (" Cannot allocate memory" ) ;
exit(-1);
}*/
}
My implementation of the list.c function list_init() is as follows:
list_t *list_init ()
{
list_t* newlist = malloc(sizeof(*newlist));
if (!newlist)
{
perror ("malloc-newlist");
exit (EXIT_FAILURE);
}`enter code here`
//newlist->first=NULL;
//newlist->last=NULL;
newlist->first = (struct list_elem *) malloc(sizeof(struct list_elem));
newlist->last = (struct list_elem *) malloc(sizeof(struct list_elem));
return newlist;
}
My list.h file is as follows:
struct list_elem {
struct list_elem *next; // Zeiger auf das naechste Element
char *data; // Zeiger auf ein Datenobject
};
typedef struct list {
struct list_elem *first;// erstes Element in der Liste
struct list_elem *last; // letztes Element in der Liste
} list_t;
/* function prototypes */
list_t *list_init ();
However, I do not know how I could change the implementation so that it does not occur anymore.
Thank you very much for your help.
c
c
edited Nov 23 '18 at 7:25
asked Nov 23 '18 at 4:46
SQLLearner
85
85
Comments are not for extended discussion; this conversation has been moved to chat.
– Samuel Liew♦
Nov 25 '18 at 3:53
add a comment |
Comments are not for extended discussion; this conversation has been moved to chat.
– Samuel Liew♦
Nov 25 '18 at 3:53
Comments are not for extended discussion; this conversation has been moved to chat.
– Samuel Liew♦
Nov 25 '18 at 3:53
Comments are not for extended discussion; this conversation has been moved to chat.
– Samuel Liew♦
Nov 25 '18 at 3:53
add a comment |
2 Answers
2
active
oldest
votes
While it is impossible to tell where your problem lies exactly, I suspect it lies in one of two places. One, you are initializing each data
member with a string literal which is read-only on all but a very few systems. So if anywhere in your code you attempt to modify data
you could expect a SegFault. The same would apply if you later attempt to free (pointer->data);
Two, you fail of assign your node->next
pointers correctly leading to your traversal attempting to derefernce a NULL
pointer or indeterminate pointer leading to the same SegFault. This can occur if your append
function fails to handle the if (!list->first) { ... }
case correctly or the else
case where you will be required to set pointer->next = newnode;
There is really no way to tell unless you post a A Minimal, Complete, and Verifiable Example (MCVE), but given list operations are somewhat generic, you could correct the shortcomings with something similar to the following for your init()
and append()
functions (with an added print()
and free()
functions thrown in for good measure), e.g.
#include <stdio.h>
#include <stdlib.h>
struct list_elem {
struct list_elem *next; // Zeiger auf das naechste Element
char *data; // Zeiger auf ein Datenobject
};
typedef struct list {
struct list_elem *first;// erstes Element in der Liste
struct list_elem *last; // letztes Element in der Liste
} list_t;
/* function prototypes */
list_t *list_init ();
struct list_elem *list_append (list_t *list, char *data);
void list_print (list_t *list);
void list_free (list_t *list);
int main (void)
{
list_t *li = list_init();
if (list_append (li, (char){"erstes"}) == NULL ||
list_append (li, (char){"zweites"}) == NULL ||
list_append (li, (char){"drittes"}) == NULL) {
perror ("Cannot allocate memory" ) ;
exit (EXIT_FAILURE);
}
list_print (li);
list_free (li);
exit (EXIT_SUCCESS);
}
list_t *list_init (void)
{
list_t *newlist = malloc (sizeof *newlist);
if (!newlist) {
perror ("malloc-newlist");
exit (EXIT_FAILURE);
}
newlist->first = NULL;
newlist->last = NULL;
return newlist;
}
struct list_elem *list_append (list_t *list, char *data)
{
struct list_elem *node = NULL;
if (!list)
return NULL;
if (!(node = malloc (sizeof *node))) {
perror ("malloc-node");
return NULL;
}
node->data = data;
node->next = NULL;
if (!list->first)
list->first = node;
else {
struct list_elem *iter = list->first;
while (iter->next)
iter = iter->next;
iter->next = node;
}
return (list->last = node);
}
void list_print (list_t *list)
{
struct list_elem *iter = NULL;
if (!list)
return;
iter = list->first;
while (iter) {
printf ("%sn", iter->data);
iter = iter->next;
}
}
void list_free (list_t *list)
{
struct list_elem *iter = NULL;
if (!list)
return;
iter = list->first;
while (iter) {
struct list_elem *victim = iter;
iter = iter->next;
free (victim);
}
free (list);
}
Example Use/Output
$ ./bin/ll_list_elem
erstes
zweites
drittes
Memory Use/Error Check
There is no need to cast the return of malloc
, it is unnecessary. See: Do I cast the result of malloc?
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind
is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/ll_list_elem
==22383== Memcheck, a memory error detector
==22383== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==22383== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==22383== Command: ./bin/ll_list_elem
==22383==
erstes
zweites
drittes
==22383==
==22383== HEAP SUMMARY:
==22383== in use at exit: 0 bytes in 0 blocks
==22383== total heap usage: 4 allocs, 4 frees, 64 bytes allocated
==22383==
==22383== All heap blocks were freed -- no leaks are possible
==22383==
==22383== For counts of detected and suppressed errors, rerun with: -v
==22383== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Using last
pointer with Forward-Chaining
Since you have a last
pointer there is no need for a generic iteration of the list to find the last pointer. I suspect you are intending to use forward-chaining. In that case, you can simply modify append()
as follows:
if (!list->first)
list->first = node;
else
list->last->next = node;
(note: the list->last = node
assignment is handled in the return
)
I suspect you are correct -- added an example of forward-chaining withlast
.
– David C. Rankin
Nov 23 '18 at 7:13
Thank you for your answer. You have written: "You are initializing each data member with a string literal which is read-only on all but a very few systems.". -> How can I change that?
– SQLLearner
Nov 23 '18 at 7:34
Look how I used a "Compound Literal" to cast the string literals to(char ){...}
making them an array of char (which you can change -- but not make longer). Note: the compound literal is only available C99+ or by specific compiler extension.
– David C. Rankin
Nov 23 '18 at 7:45
add a comment |
i think you are not allocate memory in proper way.
TList *list_init()
{
TList *newList = (TList *) malloc(sizeof(TList));
newList->first = (struct list_elem *) malloc(sizeof(structlist_elem));
newList->last = (struct list_elem *) malloc(sizeof(struct list_elem));
newList->first->next= NULL;
newList->last->next= NULL;
return newList;
}
This code is weird, there are typos, the types are not the same as in the question and it doesn't answer the question at all.
– Jabberwocky
Nov 23 '18 at 7:05
1
Allocating forfirst
andlast
ininit()
will greatly complicate yourappend()
function. (not to mention updatinglast
)
– David C. Rankin
Nov 23 '18 at 7:05
@Jabberwocky , because we don't have enough information of list append.
– raka
Nov 23 '18 at 7:10
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53440775%2fsegmentation-fault-list-initializing%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
While it is impossible to tell where your problem lies exactly, I suspect it lies in one of two places. One, you are initializing each data
member with a string literal which is read-only on all but a very few systems. So if anywhere in your code you attempt to modify data
you could expect a SegFault. The same would apply if you later attempt to free (pointer->data);
Two, you fail of assign your node->next
pointers correctly leading to your traversal attempting to derefernce a NULL
pointer or indeterminate pointer leading to the same SegFault. This can occur if your append
function fails to handle the if (!list->first) { ... }
case correctly or the else
case where you will be required to set pointer->next = newnode;
There is really no way to tell unless you post a A Minimal, Complete, and Verifiable Example (MCVE), but given list operations are somewhat generic, you could correct the shortcomings with something similar to the following for your init()
and append()
functions (with an added print()
and free()
functions thrown in for good measure), e.g.
#include <stdio.h>
#include <stdlib.h>
struct list_elem {
struct list_elem *next; // Zeiger auf das naechste Element
char *data; // Zeiger auf ein Datenobject
};
typedef struct list {
struct list_elem *first;// erstes Element in der Liste
struct list_elem *last; // letztes Element in der Liste
} list_t;
/* function prototypes */
list_t *list_init ();
struct list_elem *list_append (list_t *list, char *data);
void list_print (list_t *list);
void list_free (list_t *list);
int main (void)
{
list_t *li = list_init();
if (list_append (li, (char){"erstes"}) == NULL ||
list_append (li, (char){"zweites"}) == NULL ||
list_append (li, (char){"drittes"}) == NULL) {
perror ("Cannot allocate memory" ) ;
exit (EXIT_FAILURE);
}
list_print (li);
list_free (li);
exit (EXIT_SUCCESS);
}
list_t *list_init (void)
{
list_t *newlist = malloc (sizeof *newlist);
if (!newlist) {
perror ("malloc-newlist");
exit (EXIT_FAILURE);
}
newlist->first = NULL;
newlist->last = NULL;
return newlist;
}
struct list_elem *list_append (list_t *list, char *data)
{
struct list_elem *node = NULL;
if (!list)
return NULL;
if (!(node = malloc (sizeof *node))) {
perror ("malloc-node");
return NULL;
}
node->data = data;
node->next = NULL;
if (!list->first)
list->first = node;
else {
struct list_elem *iter = list->first;
while (iter->next)
iter = iter->next;
iter->next = node;
}
return (list->last = node);
}
void list_print (list_t *list)
{
struct list_elem *iter = NULL;
if (!list)
return;
iter = list->first;
while (iter) {
printf ("%sn", iter->data);
iter = iter->next;
}
}
void list_free (list_t *list)
{
struct list_elem *iter = NULL;
if (!list)
return;
iter = list->first;
while (iter) {
struct list_elem *victim = iter;
iter = iter->next;
free (victim);
}
free (list);
}
Example Use/Output
$ ./bin/ll_list_elem
erstes
zweites
drittes
Memory Use/Error Check
There is no need to cast the return of malloc
, it is unnecessary. See: Do I cast the result of malloc?
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind
is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/ll_list_elem
==22383== Memcheck, a memory error detector
==22383== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==22383== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==22383== Command: ./bin/ll_list_elem
==22383==
erstes
zweites
drittes
==22383==
==22383== HEAP SUMMARY:
==22383== in use at exit: 0 bytes in 0 blocks
==22383== total heap usage: 4 allocs, 4 frees, 64 bytes allocated
==22383==
==22383== All heap blocks were freed -- no leaks are possible
==22383==
==22383== For counts of detected and suppressed errors, rerun with: -v
==22383== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Using last
pointer with Forward-Chaining
Since you have a last
pointer there is no need for a generic iteration of the list to find the last pointer. I suspect you are intending to use forward-chaining. In that case, you can simply modify append()
as follows:
if (!list->first)
list->first = node;
else
list->last->next = node;
(note: the list->last = node
assignment is handled in the return
)
I suspect you are correct -- added an example of forward-chaining withlast
.
– David C. Rankin
Nov 23 '18 at 7:13
Thank you for your answer. You have written: "You are initializing each data member with a string literal which is read-only on all but a very few systems.". -> How can I change that?
– SQLLearner
Nov 23 '18 at 7:34
Look how I used a "Compound Literal" to cast the string literals to(char ){...}
making them an array of char (which you can change -- but not make longer). Note: the compound literal is only available C99+ or by specific compiler extension.
– David C. Rankin
Nov 23 '18 at 7:45
add a comment |
While it is impossible to tell where your problem lies exactly, I suspect it lies in one of two places. One, you are initializing each data
member with a string literal which is read-only on all but a very few systems. So if anywhere in your code you attempt to modify data
you could expect a SegFault. The same would apply if you later attempt to free (pointer->data);
Two, you fail of assign your node->next
pointers correctly leading to your traversal attempting to derefernce a NULL
pointer or indeterminate pointer leading to the same SegFault. This can occur if your append
function fails to handle the if (!list->first) { ... }
case correctly or the else
case where you will be required to set pointer->next = newnode;
There is really no way to tell unless you post a A Minimal, Complete, and Verifiable Example (MCVE), but given list operations are somewhat generic, you could correct the shortcomings with something similar to the following for your init()
and append()
functions (with an added print()
and free()
functions thrown in for good measure), e.g.
#include <stdio.h>
#include <stdlib.h>
struct list_elem {
struct list_elem *next; // Zeiger auf das naechste Element
char *data; // Zeiger auf ein Datenobject
};
typedef struct list {
struct list_elem *first;// erstes Element in der Liste
struct list_elem *last; // letztes Element in der Liste
} list_t;
/* function prototypes */
list_t *list_init ();
struct list_elem *list_append (list_t *list, char *data);
void list_print (list_t *list);
void list_free (list_t *list);
int main (void)
{
list_t *li = list_init();
if (list_append (li, (char){"erstes"}) == NULL ||
list_append (li, (char){"zweites"}) == NULL ||
list_append (li, (char){"drittes"}) == NULL) {
perror ("Cannot allocate memory" ) ;
exit (EXIT_FAILURE);
}
list_print (li);
list_free (li);
exit (EXIT_SUCCESS);
}
list_t *list_init (void)
{
list_t *newlist = malloc (sizeof *newlist);
if (!newlist) {
perror ("malloc-newlist");
exit (EXIT_FAILURE);
}
newlist->first = NULL;
newlist->last = NULL;
return newlist;
}
struct list_elem *list_append (list_t *list, char *data)
{
struct list_elem *node = NULL;
if (!list)
return NULL;
if (!(node = malloc (sizeof *node))) {
perror ("malloc-node");
return NULL;
}
node->data = data;
node->next = NULL;
if (!list->first)
list->first = node;
else {
struct list_elem *iter = list->first;
while (iter->next)
iter = iter->next;
iter->next = node;
}
return (list->last = node);
}
void list_print (list_t *list)
{
struct list_elem *iter = NULL;
if (!list)
return;
iter = list->first;
while (iter) {
printf ("%sn", iter->data);
iter = iter->next;
}
}
void list_free (list_t *list)
{
struct list_elem *iter = NULL;
if (!list)
return;
iter = list->first;
while (iter) {
struct list_elem *victim = iter;
iter = iter->next;
free (victim);
}
free (list);
}
Example Use/Output
$ ./bin/ll_list_elem
erstes
zweites
drittes
Memory Use/Error Check
There is no need to cast the return of malloc
, it is unnecessary. See: Do I cast the result of malloc?
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind
is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/ll_list_elem
==22383== Memcheck, a memory error detector
==22383== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==22383== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==22383== Command: ./bin/ll_list_elem
==22383==
erstes
zweites
drittes
==22383==
==22383== HEAP SUMMARY:
==22383== in use at exit: 0 bytes in 0 blocks
==22383== total heap usage: 4 allocs, 4 frees, 64 bytes allocated
==22383==
==22383== All heap blocks were freed -- no leaks are possible
==22383==
==22383== For counts of detected and suppressed errors, rerun with: -v
==22383== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Using last
pointer with Forward-Chaining
Since you have a last
pointer there is no need for a generic iteration of the list to find the last pointer. I suspect you are intending to use forward-chaining. In that case, you can simply modify append()
as follows:
if (!list->first)
list->first = node;
else
list->last->next = node;
(note: the list->last = node
assignment is handled in the return
)
I suspect you are correct -- added an example of forward-chaining withlast
.
– David C. Rankin
Nov 23 '18 at 7:13
Thank you for your answer. You have written: "You are initializing each data member with a string literal which is read-only on all but a very few systems.". -> How can I change that?
– SQLLearner
Nov 23 '18 at 7:34
Look how I used a "Compound Literal" to cast the string literals to(char ){...}
making them an array of char (which you can change -- but not make longer). Note: the compound literal is only available C99+ or by specific compiler extension.
– David C. Rankin
Nov 23 '18 at 7:45
add a comment |
While it is impossible to tell where your problem lies exactly, I suspect it lies in one of two places. One, you are initializing each data
member with a string literal which is read-only on all but a very few systems. So if anywhere in your code you attempt to modify data
you could expect a SegFault. The same would apply if you later attempt to free (pointer->data);
Two, you fail of assign your node->next
pointers correctly leading to your traversal attempting to derefernce a NULL
pointer or indeterminate pointer leading to the same SegFault. This can occur if your append
function fails to handle the if (!list->first) { ... }
case correctly or the else
case where you will be required to set pointer->next = newnode;
There is really no way to tell unless you post a A Minimal, Complete, and Verifiable Example (MCVE), but given list operations are somewhat generic, you could correct the shortcomings with something similar to the following for your init()
and append()
functions (with an added print()
and free()
functions thrown in for good measure), e.g.
#include <stdio.h>
#include <stdlib.h>
struct list_elem {
struct list_elem *next; // Zeiger auf das naechste Element
char *data; // Zeiger auf ein Datenobject
};
typedef struct list {
struct list_elem *first;// erstes Element in der Liste
struct list_elem *last; // letztes Element in der Liste
} list_t;
/* function prototypes */
list_t *list_init ();
struct list_elem *list_append (list_t *list, char *data);
void list_print (list_t *list);
void list_free (list_t *list);
int main (void)
{
list_t *li = list_init();
if (list_append (li, (char){"erstes"}) == NULL ||
list_append (li, (char){"zweites"}) == NULL ||
list_append (li, (char){"drittes"}) == NULL) {
perror ("Cannot allocate memory" ) ;
exit (EXIT_FAILURE);
}
list_print (li);
list_free (li);
exit (EXIT_SUCCESS);
}
list_t *list_init (void)
{
list_t *newlist = malloc (sizeof *newlist);
if (!newlist) {
perror ("malloc-newlist");
exit (EXIT_FAILURE);
}
newlist->first = NULL;
newlist->last = NULL;
return newlist;
}
struct list_elem *list_append (list_t *list, char *data)
{
struct list_elem *node = NULL;
if (!list)
return NULL;
if (!(node = malloc (sizeof *node))) {
perror ("malloc-node");
return NULL;
}
node->data = data;
node->next = NULL;
if (!list->first)
list->first = node;
else {
struct list_elem *iter = list->first;
while (iter->next)
iter = iter->next;
iter->next = node;
}
return (list->last = node);
}
void list_print (list_t *list)
{
struct list_elem *iter = NULL;
if (!list)
return;
iter = list->first;
while (iter) {
printf ("%sn", iter->data);
iter = iter->next;
}
}
void list_free (list_t *list)
{
struct list_elem *iter = NULL;
if (!list)
return;
iter = list->first;
while (iter) {
struct list_elem *victim = iter;
iter = iter->next;
free (victim);
}
free (list);
}
Example Use/Output
$ ./bin/ll_list_elem
erstes
zweites
drittes
Memory Use/Error Check
There is no need to cast the return of malloc
, it is unnecessary. See: Do I cast the result of malloc?
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind
is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/ll_list_elem
==22383== Memcheck, a memory error detector
==22383== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==22383== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==22383== Command: ./bin/ll_list_elem
==22383==
erstes
zweites
drittes
==22383==
==22383== HEAP SUMMARY:
==22383== in use at exit: 0 bytes in 0 blocks
==22383== total heap usage: 4 allocs, 4 frees, 64 bytes allocated
==22383==
==22383== All heap blocks were freed -- no leaks are possible
==22383==
==22383== For counts of detected and suppressed errors, rerun with: -v
==22383== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Using last
pointer with Forward-Chaining
Since you have a last
pointer there is no need for a generic iteration of the list to find the last pointer. I suspect you are intending to use forward-chaining. In that case, you can simply modify append()
as follows:
if (!list->first)
list->first = node;
else
list->last->next = node;
(note: the list->last = node
assignment is handled in the return
)
While it is impossible to tell where your problem lies exactly, I suspect it lies in one of two places. One, you are initializing each data
member with a string literal which is read-only on all but a very few systems. So if anywhere in your code you attempt to modify data
you could expect a SegFault. The same would apply if you later attempt to free (pointer->data);
Two, you fail of assign your node->next
pointers correctly leading to your traversal attempting to derefernce a NULL
pointer or indeterminate pointer leading to the same SegFault. This can occur if your append
function fails to handle the if (!list->first) { ... }
case correctly or the else
case where you will be required to set pointer->next = newnode;
There is really no way to tell unless you post a A Minimal, Complete, and Verifiable Example (MCVE), but given list operations are somewhat generic, you could correct the shortcomings with something similar to the following for your init()
and append()
functions (with an added print()
and free()
functions thrown in for good measure), e.g.
#include <stdio.h>
#include <stdlib.h>
struct list_elem {
struct list_elem *next; // Zeiger auf das naechste Element
char *data; // Zeiger auf ein Datenobject
};
typedef struct list {
struct list_elem *first;// erstes Element in der Liste
struct list_elem *last; // letztes Element in der Liste
} list_t;
/* function prototypes */
list_t *list_init ();
struct list_elem *list_append (list_t *list, char *data);
void list_print (list_t *list);
void list_free (list_t *list);
int main (void)
{
list_t *li = list_init();
if (list_append (li, (char){"erstes"}) == NULL ||
list_append (li, (char){"zweites"}) == NULL ||
list_append (li, (char){"drittes"}) == NULL) {
perror ("Cannot allocate memory" ) ;
exit (EXIT_FAILURE);
}
list_print (li);
list_free (li);
exit (EXIT_SUCCESS);
}
list_t *list_init (void)
{
list_t *newlist = malloc (sizeof *newlist);
if (!newlist) {
perror ("malloc-newlist");
exit (EXIT_FAILURE);
}
newlist->first = NULL;
newlist->last = NULL;
return newlist;
}
struct list_elem *list_append (list_t *list, char *data)
{
struct list_elem *node = NULL;
if (!list)
return NULL;
if (!(node = malloc (sizeof *node))) {
perror ("malloc-node");
return NULL;
}
node->data = data;
node->next = NULL;
if (!list->first)
list->first = node;
else {
struct list_elem *iter = list->first;
while (iter->next)
iter = iter->next;
iter->next = node;
}
return (list->last = node);
}
void list_print (list_t *list)
{
struct list_elem *iter = NULL;
if (!list)
return;
iter = list->first;
while (iter) {
printf ("%sn", iter->data);
iter = iter->next;
}
}
void list_free (list_t *list)
{
struct list_elem *iter = NULL;
if (!list)
return;
iter = list->first;
while (iter) {
struct list_elem *victim = iter;
iter = iter->next;
free (victim);
}
free (list);
}
Example Use/Output
$ ./bin/ll_list_elem
erstes
zweites
drittes
Memory Use/Error Check
There is no need to cast the return of malloc
, it is unnecessary. See: Do I cast the result of malloc?
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind
is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/ll_list_elem
==22383== Memcheck, a memory error detector
==22383== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==22383== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==22383== Command: ./bin/ll_list_elem
==22383==
erstes
zweites
drittes
==22383==
==22383== HEAP SUMMARY:
==22383== in use at exit: 0 bytes in 0 blocks
==22383== total heap usage: 4 allocs, 4 frees, 64 bytes allocated
==22383==
==22383== All heap blocks were freed -- no leaks are possible
==22383==
==22383== For counts of detected and suppressed errors, rerun with: -v
==22383== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Using last
pointer with Forward-Chaining
Since you have a last
pointer there is no need for a generic iteration of the list to find the last pointer. I suspect you are intending to use forward-chaining. In that case, you can simply modify append()
as follows:
if (!list->first)
list->first = node;
else
list->last->next = node;
(note: the list->last = node
assignment is handled in the return
)
edited Nov 23 '18 at 7:13
answered Nov 23 '18 at 6:56
David C. Rankin
40.3k32647
40.3k32647
I suspect you are correct -- added an example of forward-chaining withlast
.
– David C. Rankin
Nov 23 '18 at 7:13
Thank you for your answer. You have written: "You are initializing each data member with a string literal which is read-only on all but a very few systems.". -> How can I change that?
– SQLLearner
Nov 23 '18 at 7:34
Look how I used a "Compound Literal" to cast the string literals to(char ){...}
making them an array of char (which you can change -- but not make longer). Note: the compound literal is only available C99+ or by specific compiler extension.
– David C. Rankin
Nov 23 '18 at 7:45
add a comment |
I suspect you are correct -- added an example of forward-chaining withlast
.
– David C. Rankin
Nov 23 '18 at 7:13
Thank you for your answer. You have written: "You are initializing each data member with a string literal which is read-only on all but a very few systems.". -> How can I change that?
– SQLLearner
Nov 23 '18 at 7:34
Look how I used a "Compound Literal" to cast the string literals to(char ){...}
making them an array of char (which you can change -- but not make longer). Note: the compound literal is only available C99+ or by specific compiler extension.
– David C. Rankin
Nov 23 '18 at 7:45
I suspect you are correct -- added an example of forward-chaining with
last
.– David C. Rankin
Nov 23 '18 at 7:13
I suspect you are correct -- added an example of forward-chaining with
last
.– David C. Rankin
Nov 23 '18 at 7:13
Thank you for your answer. You have written: "You are initializing each data member with a string literal which is read-only on all but a very few systems.". -> How can I change that?
– SQLLearner
Nov 23 '18 at 7:34
Thank you for your answer. You have written: "You are initializing each data member with a string literal which is read-only on all but a very few systems.". -> How can I change that?
– SQLLearner
Nov 23 '18 at 7:34
Look how I used a "Compound Literal" to cast the string literals to
(char ){...}
making them an array of char (which you can change -- but not make longer). Note: the compound literal is only available C99+ or by specific compiler extension.– David C. Rankin
Nov 23 '18 at 7:45
Look how I used a "Compound Literal" to cast the string literals to
(char ){...}
making them an array of char (which you can change -- but not make longer). Note: the compound literal is only available C99+ or by specific compiler extension.– David C. Rankin
Nov 23 '18 at 7:45
add a comment |
i think you are not allocate memory in proper way.
TList *list_init()
{
TList *newList = (TList *) malloc(sizeof(TList));
newList->first = (struct list_elem *) malloc(sizeof(structlist_elem));
newList->last = (struct list_elem *) malloc(sizeof(struct list_elem));
newList->first->next= NULL;
newList->last->next= NULL;
return newList;
}
This code is weird, there are typos, the types are not the same as in the question and it doesn't answer the question at all.
– Jabberwocky
Nov 23 '18 at 7:05
1
Allocating forfirst
andlast
ininit()
will greatly complicate yourappend()
function. (not to mention updatinglast
)
– David C. Rankin
Nov 23 '18 at 7:05
@Jabberwocky , because we don't have enough information of list append.
– raka
Nov 23 '18 at 7:10
add a comment |
i think you are not allocate memory in proper way.
TList *list_init()
{
TList *newList = (TList *) malloc(sizeof(TList));
newList->first = (struct list_elem *) malloc(sizeof(structlist_elem));
newList->last = (struct list_elem *) malloc(sizeof(struct list_elem));
newList->first->next= NULL;
newList->last->next= NULL;
return newList;
}
This code is weird, there are typos, the types are not the same as in the question and it doesn't answer the question at all.
– Jabberwocky
Nov 23 '18 at 7:05
1
Allocating forfirst
andlast
ininit()
will greatly complicate yourappend()
function. (not to mention updatinglast
)
– David C. Rankin
Nov 23 '18 at 7:05
@Jabberwocky , because we don't have enough information of list append.
– raka
Nov 23 '18 at 7:10
add a comment |
i think you are not allocate memory in proper way.
TList *list_init()
{
TList *newList = (TList *) malloc(sizeof(TList));
newList->first = (struct list_elem *) malloc(sizeof(structlist_elem));
newList->last = (struct list_elem *) malloc(sizeof(struct list_elem));
newList->first->next= NULL;
newList->last->next= NULL;
return newList;
}
i think you are not allocate memory in proper way.
TList *list_init()
{
TList *newList = (TList *) malloc(sizeof(TList));
newList->first = (struct list_elem *) malloc(sizeof(structlist_elem));
newList->last = (struct list_elem *) malloc(sizeof(struct list_elem));
newList->first->next= NULL;
newList->last->next= NULL;
return newList;
}
answered Nov 23 '18 at 7:02
raka
11
11
This code is weird, there are typos, the types are not the same as in the question and it doesn't answer the question at all.
– Jabberwocky
Nov 23 '18 at 7:05
1
Allocating forfirst
andlast
ininit()
will greatly complicate yourappend()
function. (not to mention updatinglast
)
– David C. Rankin
Nov 23 '18 at 7:05
@Jabberwocky , because we don't have enough information of list append.
– raka
Nov 23 '18 at 7:10
add a comment |
This code is weird, there are typos, the types are not the same as in the question and it doesn't answer the question at all.
– Jabberwocky
Nov 23 '18 at 7:05
1
Allocating forfirst
andlast
ininit()
will greatly complicate yourappend()
function. (not to mention updatinglast
)
– David C. Rankin
Nov 23 '18 at 7:05
@Jabberwocky , because we don't have enough information of list append.
– raka
Nov 23 '18 at 7:10
This code is weird, there are typos, the types are not the same as in the question and it doesn't answer the question at all.
– Jabberwocky
Nov 23 '18 at 7:05
This code is weird, there are typos, the types are not the same as in the question and it doesn't answer the question at all.
– Jabberwocky
Nov 23 '18 at 7:05
1
1
Allocating for
first
and last
in init()
will greatly complicate your append()
function. (not to mention updating last
)– David C. Rankin
Nov 23 '18 at 7:05
Allocating for
first
and last
in init()
will greatly complicate your append()
function. (not to mention updating last
)– David C. Rankin
Nov 23 '18 at 7:05
@Jabberwocky , because we don't have enough information of list append.
– raka
Nov 23 '18 at 7:10
@Jabberwocky , because we don't have enough information of list append.
– raka
Nov 23 '18 at 7:10
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53440775%2fsegmentation-fault-list-initializing%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Comments are not for extended discussion; this conversation has been moved to chat.
– Samuel Liew♦
Nov 25 '18 at 3:53