Array of strings linked list - Segmentation fault - c

I have a function that takes an array of strings. It separates all those strings by the presence of a particular character, in this case '|'. See my previous question for a better idea Split an array of strings based on character
So, I have an array of strings that looks like this:
char ** args = {"ls", "-l", "|", "cd", "."}
My parseCmnds function is supposed to go through each string in the array and create a new array of strings with all the strings before the '|' character. Then it creates a linked list where each node points to each of the array of strings I created, essentially separating the original array of strings into separate arrays of strings linked to each other.
So, my parse loop should create something like this for example:
On the first iteration:
char ** command = {"ls", "-l", NULL}
On the second iteration
char ** command = {"cd", ".", NULL}
After each iteration my function creates a new linked list node and populates it. I built code based on some of the answers I got on my previous question (thanks a million). But for some reason I'm getting a segmentation fault that I can't figure out. Can someone check out my code and let me know what I'm doing wrong?
typedef struct node {
char ** cmnd;
struct node * next;
} node_cmnds;
node_cmnds * parseCmnds(char **args) {
int i;
int j=0;
int numArgs = 0;
node_cmnds * head = NULL; //head of the linked list
head = malloc(sizeof(node_cmnds));
if (head == NULL) { //allocation failed
return NULL;
}
else {
head->next = NULL;
}
node_cmnds * currNode = head; //point current node to head
for(i = 0; args[i] != NULL; i++) { //loop that traverses through arguments
char ** command = (char**)malloc(maxArgs * sizeof(char*)); //allocate an array of strings for the command
if(command == NULL) { //allocation failed
return NULL;
}
while(strcmp(args[i],"|") != 0) { //loop through arguments until a | is found
command[i] = (char*)malloc(sizeof(args[i])); //allocate a string to copy argument
if(command[i] == NULL) { //allocation failed
return NULL;
}
else {
strcpy(command[i],args[i]); //add argument to our array of strings
i++;
numArgs++;
}
}
command[i] = NULL; //once we find | we set the array element to NULL to specify the end
while(command[j] != NULL) {
strcpy(currNode->cmnd[j], command[j]);
j++;
}
currNode->next = malloc(sizeof(node_cmnds));
if(currNode->next == NULL) {
return NULL;
}
currNode = currNode->next; //
numArgs = 0;
}
return head;
}

You're never allocating any memory for the cmnd member of node_cmds. So the line strcpy(currNode->cmnd[j], command[j]); is writing to...somewhere. Likely to memory you don't own. And when you do add those mallocs, your indexing (using j) is going to be very incorrect on the second pass through the outside for loop.
Also, you're leaking memory like a sieve. Try throwing some frees in there.

while(command[j] != NULL) {
strcpy(currNode->cmnd[j], command[j]);
j++;
}
At this statement you haven't allocated memory for the cmnd pointer(string). I believe this may be causing part of your problem. You have allocated memory for the struct, but you need to allocate memory for each pointer in the struct as well.

Related

Load function trie segmentation fault

I keep getting segfault for my load function.
bool load(const char *dictionary)
{
//create a trie data type
typedef struct node
{
bool is_word;
struct node *children[27]; //this is a pointer too!
}node;
//create a pointer to the root of the trie and never move this (use traversal *)
node *root = malloc(sizeof(node));
for(int i=0; i<27; i++)
{
//NULL point all indexes of root -> children
root -> children[i] = NULL;
}
FILE *dptr = fopen(dictionary, "r");
if(dptr == NULL)
{
printf("Could not open dictionary\n");
return false;
}
char *c = NULL;
//scan the file char by char until end and store it in c
while(fscanf(dptr,"%s",c) != EOF)
{
//in the beginning of every word, make a traversal pointer copy of root so we can always refer back to root
node *trav = root;
//repeat for every word
while ((*c) != '\0')
{
//convert char into array index
int alpha = (tolower(*c) - 97);
//if array element is pointing to NULL, i.e. it hasn't been open yet,
if(trav -> children[alpha] == NULL)
{
//then create a new node and point it with the previous pointer.
node *next_node = malloc(sizeof(node));
trav -> children[alpha] = next_node;
//quit if malloc returns null
if(next_node == NULL)
{
printf("Could not open dictionary");
return false;
}
}
else if (trav -> children[alpha] != NULL)
{
//if an already existing path, just go to it
trav = trav -> children[alpha];
}
}
//a word is loaded.
trav -> is_word = true;
}
//success
free(root);
return true;
}
I checked whether I properly pointed new pointers to NULL during initialization. I have three types of nodes: root, traversal (for moving), and next_node. (i.) Am I allowed to null point the nodes before mallocing them? (ii.) Also, how do I free 'next_node' if that node is initialized and malloced inside an if statement? node *next_node = malloc(sizeof(node)); (iii.) If I want to set the nodes as global variables, which ones should be global? (iv.) Lastly, where do I set global variables: inside the main of speller.c, outside its main, or somewhere else? That's alot of questions, so you don't have to answer all of them, but it would be nice if you could answer the answered ones! Please point out any other peculiarities in my code. There should be plenty. I will accept most answers.
The cause of segmentation fault is the pointer "c" which you have not allocated memory.
Also, in your program -
//scan the file char by char until end and store it in c
while(fscanf(dptr,"%s",c) != EOF)
Once you allocate memory to pointer c, c will hold the word read from file dictionary.
Below in your code, you are checking for '\0' character-
while ((*c) != '\0')
{
But you are not moving the c pointer to point to next character in the string read because of which this code will end up executing infinite while loop.
May you can try something like this-
char *tmp;
tmp = c;
while ((*tmp) != '\0')
{
......
......
//Below in the loop at appropriate place
tmp++;
}

Segmentation Fault with Character Pointer Array

I am fairly new to C and have been having a lot of difficulty trying to copy the values of an array of pointers to strings. I have created a struct that contains such a pointer array (part of an implementation of a doubly linked list)
typedef struct Node
{
int value;
char *args[41];
....
} Node;
When I want to add a node, I have been using the following method
void addNew(char *args[], Node *current)
{
// first node is passed in, so loop until end of list is reached
while ((*current).next != NULL
current = (*current).next;
// create new node that is linked with the last node
(*current).next = (Node *)malloc(sizeof(Node));
((*current).next)).prev = current;
current = (*current).next;
// assign value to new node
(*current).value = some-new-value;
// allocate space for new argument array
(*current).args[41] = (char*)malloc(41 * sizeof(char*));
int i=0;
// loop through the arg array and copy each of the passed-in args into the node
for (i=0; i<41; i++)
strcpy((*current).args[i], args[i]);
(*current).next = NULL;
}
I think the root of my problem is in how I am allocating space for the pointers in the new node, but I haven't been able to figure out what I was doing wrong. As it stands, I get a Segmentation Fault (core dumped) as soon as the strcpy line is reached.
Any idea what Im doing wrong?
The line
(*current).args[41] = (char*)malloc(41 * sizeof(char*));
does not make sense at all. I am not sure what you were trying to accomplish there. Remove that line.
In order to be able to use:
for (i=0; i<41; i++)
strcpy((*current).args[i], args[i]);
you need to allocate memory for each element of (*current).args. Here's one way:
for (i=0; i<41; i++)
{
int len = strlen(args[i]);
(*current).args[i] = malloc(len+1);
strcpy((*current).args[i], args[i]);
}

C pointers, inserting elements to HEAD of linked list

I am working on a problem in the K&R book (#6.3) where the user inputs a sequence of words, and you have to create a list of these words along with the lines that each one appears on. It's supposed to involve structures so these are the ones I have right now:
struct entry {
int line;
int count;
struct entry *next;
};
struct word {
char *str;
struct entry *lines;
struct word *next;
};
static struct word *wordlist = NULL; // GLOBAL WORDLIST
However when I input something and the program tries to add a new entry to the structure (which is somewhat like a linked list), there is a problem and the program terminates with no error message. Code for that:
void add_entry(char *word, int line)
{
if (word == NULL || line <= 0 || is_blocked_word(word))
return;
struct word *w;
for (w = wordlist; w != NULL && w->next != NULL && !strcmp(w->str, word); w = w->next);
// If word is found in the wordlist, then update the entry
if (w != NULL) {
struct entry *v;
for (v = w->lines; v != NULL && v->next != NULL && v->line != line; v = v->next);
if (v == NULL) {
struct entry *new = (struct entry*) malloc(sizeof(struct entry));
new->line = line;
new->count = 1;
new->next = NULL;
if (w->lines == NULL)
w->lines = new;
else
v->next = new;
}
else v->count++;
}
// If word is not found in the word list, then create a new entry for it
else {
struct word *new = (struct word*) malloc(sizeof(struct word));
new->lines = (struct entry*) malloc(sizeof(struct entry));
new->next = NULL;
new->str = (char*) malloc(sizeof(char) * strlen(word));
new->lines->line = line;
new->lines->count = 1;
new->lines->next = NULL;
strcpy(new->str, word);
// If the word list is empty, then populate head first before populating the "next" entry
if (wordlist == NULL)
wordlist = new;
else
w->next = new;
}
}
The program terminates even after adding just the first word to wordlist. This is on the line that says if (wordlist == NULL) wordlist = new; where new contains the pointer to a valid structure that I malloc'ed. How can this be possible?
As far as I know it's a problem with my pointer usage but I'm not sure where exactly it lies. Can someone help?
Some fairly evident, and some not-so-evident things.
The for-loop limit for w stops one short
for (w = wordlist; w != NULL && w->next != NULL && !strcmp(w->str, word); w = w->next);
This will start with the first and continue until
We have run out of nodes
We have almost (one short) run out of nodes.
The word in the current node does NOT match
Almost the same problem, different for-loop
for (v = w->lines; v != NULL && v->next != NULL && v->line != line; v = v->next);
As above, this has similar attributes (but not the third option, as this correctly continues so long as the line numbers do not match. The prior loop broke as soon as any word did not match.
And that is in the first ten lines of this function.
String allocation size fails to account for the nulchar terminator
This falls short by one char of the allocation size needed for a zero-terminated string:
malloc(sizeof(char) * strlen(word))
You always need space for the terminator. The easiest way to remember that is to consider how many chars are needed for a zero-length C string? Answer: one, because the terminator needs to go somewhere. After that is simply length+1
One possible way to do this is via a pointer-to-pointer approach, shown below:
void add_entry(const char *word, int line)
{
if (word == NULL || line <= 0 || is_blocked_word(word))
return;
struct word **pp = &wordlist;
for (; *pp && strcmp((*pp)->str, word); pp = &(*pp)->next);
if (*pp)
{
// search for matching line number
struct entry **vv = &(*pp)->lines;
for (; *vv && (*vv)->line != line; vv = &(*vv)->next);
if (!*vv)
{
*vv = malloc(sizeof(**vv));
if (!*vv)
{
perror("Failed to allocate line entry.");
exit(EXIT_FAILURE);
}
(*vv)->count = 1;
(*vv)->line = line;
(*vv)->next = NULL;
}
else
{ // found an entry. increment count.
(*vv)->count++;
}
}
else
{ // no matching word. create a new word with a new line entry
size_t len = strlen(word);
*pp = malloc(sizeof(**pp));
if (!*pp)
{
perror("Failed to allocate word entry.");
exit(EXIT_FAILURE);
}
(*pp)->lines = malloc(sizeof(*(*pp)->lines));
if (!(*pp)->lines)
{
perror("Failed to allocate line count entry.");
exit(EXIT_FAILURE);
}
(*pp)->str = malloc(len + 1);
if (!(*pp)->str)
{
perror("Failed to allocate word string entry.");
exit(EXIT_FAILURE);
}
(*pp)->lines->count = 1;
(*pp)->lines->line = line;
(*pp)->lines->next = NULL;
(*pp)->next = NULL;
memcpy((*pp)->str, word, len+1);
}
}
How It Works
In both cases, we use a pointer-to-pointer. They are a most-hand construct when the desire is to perform tail-end insertion on a linked list without having to keep a "one-back" or "previous" pointer. Just like any pointer, they hold an address. Unlike a regular pointer-to-something, a pointer-to-pointer-to-something holds the address of another pointer. With it we can "loop" by initially setting it to the address of the head pointer, the entering the search.
struct word **pp = &wordlist;
for (; *pp && strcmp((*pp)->str, word); pp = &(*pp)->next);
Here we start with the address of our head pointer. the loop will terminate if the pointer at the address held in pp is NULL, or if the word actually matches. Otherwise it sets the address of (not the address in) the next pointer of the current node.If we run out of words and never find a match the loop will break, but with a most-handy consequence: pp contains the address of the pointer that we need to set to the new allocation. If the list were initially empty, it contains the address of the head pointer.
With that, we can then do this:
if (*pp)
{
// search for matching line number
struct entry **vv = &(*pp)->lines;
for (; *vv && (*vv)->line != line; vv = &(*vv)->next);
Notice we use the same idea on the line-entry list. Either we're going to find an entry, or the loop will exit with *vv being NULL, and vv contains the address of the next pointer we want to set to our new allocation.
I strongly urge you to step through this code in a debugger line-by-line, and understand how it works. utilizing this technique has many redeeming qualities, among them the incredibly brief method of populating a forward-linked list in O(n) complexity without having to check for a head pointer or walking the list for each insertion and retaining the original order (as opposed to reversing the order as a stack-like solution would result):
struct node *head = NULL;
struct node **pp = &head;
while (get-data-for-our-list)
{
*pp = malloc(sizeof(**pp));
// TODO: populate (*pp)->members here
pp = &(*pp)->next;
}
*pp = NULL;

Why is this C linked list program giving 'segmentation fault'?

The first function reads a file that has a bunch of 'char's and puts them in a linked list. It is not working :(.
#include <stdio.h>
#include <stdlib.h>
struct list {
char val;
struct list* next;
};
typedef struct list element;
int lcreate(char* fname, element* list);
int ldelete(element* list);
int linsert(char a, char b, element* list);
int lremove(char a, element* list);
int lsave(char* fname, element* list);
int lcreate(char* fname, element* list) {
element* elem = list;
char c = 0;
FILE * file = NULL;
file = fopen(fname, "r");
while ((c = getc(file)) != EOF)
{
if(list == NULL) {
list = (element*)malloc(sizeof(element));
if(list == NULL) {
return 0;
}
list->val = c;
}
else {
elem->next=(element*)malloc(sizeof(element));
elem = elem->next;
elem-> val = c;
}
}
fclose(file);
elem->next = NULL;
return 1;
}
int main(void) {
int i = 0;
element * list = NULL;
lcreate("list.txt", list);
for(i = 0; i<4; ++i) {
printf("%c", list->val);
list = list->next;
}
return 0;
}
Fixed problem with 'file' being null.
One obvious problem is right here:
FILE * file = NULL;
fopen(fname, "r");
For the fopen to accomplish much, you need to assign the result from fopen to your FILE *:
file = fopen(fname, "r");
Edit: Since you're working in C, you can't pass the pointer by reference. As an alternative, you can pass a pointer to a pointer:
int lcreate(char *fname, element **list) {
// ...
*list = malloc(sizeof(element));
(*list)->next = null;
(*list)->val = c;
// ...
}
Basically, all the code inside of lcreate will need to refer to *list instead of just list. Alternatively, you can take a pointer to an existing list as input, and return a pointer to the list, so in main you'd have something like: list = lcreate("list.txt", list);
file is NULL, and you never assign a file handle to it.
In your main function, you are also passing list by value to lcreate. Within the lcreate() function, you are overwriting a local copy of list, not changing the value of list in the main function. Since list is initialized to NULL, you will get a segfault when you call list->val.
Yep -- what the others said about the FILE pointer, and passing list by value rather than reference to lcreate(), is true.
You also aren't returning the size of the list from lcreate() -- you should probably return this via the return value or a pointer argument.
You are attempting to iterate through the list 4 times in the main() function, but there may be less than 4 items in the list. Eventually the printf() will cause a segmentation fault if list is NULL.
If you still have issues after making these changes, I would recommend adding tracing to your code to work out at which point the segmentation fault is happening.
Update:
Also please remember to free the memory you have allocated after you traverse the list, otherwise you'll end up with a memory leak (although in practice this won't really be an issue for you as the program is ending, but freeing memory is a good habit to get into).
I can see an additional problem as well. In the while statement of lcreate() the true clause of the if statement malloc's some memory and assigns it to list however elem is not updated.
while ((c = getc(file)) != EOF)
{
if(list == NULL) {
list = (element*)malloc(sizeof(element));
if(list == NULL) {
return 0;
}
list->val = c;
}
else {
Next time through the while loop list will not be non-null but elem is still null so the assignment of elem->next tries to deference the null pointer and thus the segmentation fault (which, btw, means that you tried to access memory that has not been assigned to your process):-
else {
elem->next=(element*)malloc(sizeof(element));
As others have pointed out you also don't return list back to main so it will still be NULL when you hit the printf() loop.
Finally, the debugger is your friend when looking at these problems. You'll see exactly which line triggers the seg fault and what the state of the variables were.
It would be good to check if the malloc was successful by checking for a non null pinter.
Also, you might want to allocate the head/first link outside of the while to avoid the null check for the head every time in the while loop. Of course, these are optimizations, in case your linked list grows really large!

Creating a singly linked list in C

I'm trying to create a singly linked list from an input text file for an assignment. I'm trying to do it a little bit at a time so I know my code is not complete. I tried creating the head pointer and just printing out its value and I can't even get that to work, but I'm not sure why. I included the struct, my create list, and print list functions. I didn't include the open file since that part works.
typedef struct List
{
struct List *next; /* pointer to the next list node */
char *str; /* pointer to the string represented */
int count; /* # of occurrences of this string */
} LIST;
LIST *CreateList(FILE *fp)
{
char input[LINE_LEN];
LIST *root; /* contains root of list */
size_t strSize;
LIST *newList; /* used to allocate new list members */
while (fscanf(fp, BUFFMT"s", input) != EOF) {
strSize = strlen(input) + 1;
/* create root node if no current root node */
if (root == NULL) {
if ((newList = (LIST *)malloc(sizeof(LIST))) == NULL) {
printf("Out of memory...");
exit(EXIT_FAILURE);
}
if ((char *)malloc(sizeof(strSize)) == NULL) {
printf("Not enough memory for %s", input);
exit(EXIT_FAILURE);
}
memcpy(newList->str, input, strSize); /*copy string */
newList->count = START_COUNT;
newList->next = NULL;
root = newList;
}
}
return root;
}
/* Prints sinly linked list and returns head pointer */
LIST *PrintList(const LIST *head)
{
int count;
for (count = 1; head != NULL; head = head->next, head++) {
printf("%s %d", head->str, head->count);
}
return head; /* does this actually return the start of head ptr, b/c I want to
return the start of the head ptr. */
}
root has an undefined value, so it won't initialize. The second line of CreateList should be
LIST *root = NULL;
Also, further down there is allocation apparently for the details of the item, but a) the code fails to capture the allocation and save it anywhere, and b) the size of the allocation should be strSize, not the length of the variable itself. There are several ways to fix it, but the most straightforward would be:
newList->str = (char *)malloc(strSize);
if (newList->str == NULL)
The second malloc allocates memory but its return value is not assigned to anything, so that allocated memory is lost.
newList is allocated but not initialized, so using a memcpy to copy memory to newList->str will fail since newList->str points to nothing. Probably you wanted the result of the second malloc to be assigned to newList->str, but you forgot it.
You shouldn't be incrementing head after head = head->next in the for loop. PrintList will return NULL every time since the loop wont stop until head is NULL. Why do you need to return the head of the list you just passed to the function anyway?
Edit:
LIST *current = head;
while (current != NULL) {
printf("%s %d", current->str, current->count);
current = current->next;
}

Resources