I wrote a c program, compiled it and it ran fine. After a few compiles - it started giving me a segmentation fault. I renamed the folder, recompiled and it worked again.
Is this something normal? To have an inconsistent segmentation fault? I change the output name, change folder names etc.. and it bounces from giving segmentation fault to not giving seg fault. I don't know what to do anymore.
I mean, if it is a coding problem, seg fault should be consistent, right? I should get it every time. here's the code:
file my_set.c:
#include <stdio.h>
#include <stdlib.h>
#include "list.h"
/*
The program acceps a set of numbers from stdin until EOF
And then prints them (not storing duplicate numbers)
*/
int main ()
{
int num;
nodePtr head; /*head of the list*/
while (scanf("%d", &num) != EOF)
{
addToList(num, &head);
}
printList(head);
freeList(head);
return 0;
}
file list.c:
#include <stdio.h>
#include <stdlib.h>
#include "list.h"
/*
Implements a linked list, each element of which contains a dynamic array.
I used a linked list to maximize potential memory in case it is fragmented.
I use a dynamic array in each node to minimize the percentage of overhead
from creating a list (the pointer, the index...);
*/
/*
Adds number n to list *h
4 cases:
1. list is empty:
creating one
updating h with new list
creating a new dynamic array in the list
updating it and the index
2. can reallocate current node's array for 1 more int
3. cannot reallocate current node's array:
creating a new node
initializing it
4. cannot create a new node
printing the current list, an "out of memory error" and freeing all memory.
*/
void addToList(int n, nodePtr *h)
{
static nodePtr p; /*points to current last node*/
int *temp; /*for use in reallocation*/
if (!*h) /*first item of set*/
{
*h = malloc (sizeof(node));
(*h)->arr = malloc(sizeof(int));
(*h)->arr[0] = n;
(*h)->i = 1;
p = *h;
return;
}
/*if n is already in the list, no need to add it
the call comes after first item, because first item cannot be in the list*/
if(existsInList(n, *h)) return;
/*using realloc while still possible*/
if ((temp = realloc(p->arr, (p->i+1)*sizeof(int))))
{
p->arr = temp;
p->arr[p->i] = n;
p->i++;
return;
}
/*if realloc no longet possible - start new node*/
if ((p->next = malloc(sizeof(node))))
{
p = p->next;
p->arr = malloc(sizeof(int));
p->arr[0] = n;
p->i = 1;
return;
}
/*can no longer start new nodes - quit with error, after printing*/
printf("out of memory!");
printList(*h);
freeList(*h);
}
/*checks if n is in p assuming p is not null
it can asume so because the call for it comes after the check for first item*/
int existsInList(int n, nodePtr p)
{
int i;
for (; p ; p = p->next)
for (i = 0; i < p->i; i++)
if (p->arr[i] == n)
return 1;
return 0;
}
/*frees the list*/
void freeList(nodePtr p)
{
nodePtr temp = p;
if (!p) return; /*list is empty*/
while (p)
{
free(p->arr);
p = p->next;
free(temp);
}
}
/*prints the content of the list to stdout*/
void printList(nodePtr p)
{
if (!p) return;
int i;
printf("\n");
for (; p ; p = p->next)
for (i = 0; i < p->i; i++)
printf("%d ", p->arr[i]);
printf("\n");
}
file list.h:
/*
pointer to a node
declare a variable of this type to create a list
then start adding to the list
*/
typedef struct s *nodePtr;
/*the struct that represents each node of the list
reason for dynamic array is in "list.c"
*/
typedef struct s
{
int *arr;
int i; /*index for next num, also size of array;*/
nodePtr next;
}node;
/*Adds the int to list at nodePtr omitting duplicates*/
void addToList(int, nodePtr*);
/*prints a list*/
void printList(nodePtr);
/*returns 1 if an int exists in list referenced by nodePtr, 0 otherwise*/
int existsInList(int, nodePtr);
/*frees all dynamically allocated memory*/
void freeList(nodePtr);
Basically all I do is get numbers from stdin, put them in a list(no duplicates) and then print them. I use a list of dynamic arrays.
Initialize your variables!
int num = 0;
nodePtr head = NULL; /*head of the list*/
ADD: The inconsistent behaviour can come from debug vs release compilation, usually compilers in debug mode set the non-initialized variables to weird values like 0xDDDDDDDD to make the problem immediately visible. In release mode if the memory block is zeroed it will happen that the content of the variables is 0 but there is no guarantee for it.
You should check the returns values from malloc() in case it's returning NULL (out of memory).
Intermittent segfaults in c/c++ programs are usually caused by uninitialised memory, often in pointer variables.
You've posted a lot of code, which makes it hard to debug just be reading it. I suggest going through the code and, wherever a variable is declared, giving it an initial value (e.g. zero or NULL). Remember that the compiler will not initialise them for you.
You should probably start by initialising the values of num and head in main(). E.g.
int num = 0;
nodePtr head = NULL; /*head of the list*/
EDIT 1
Another bug is in addToList(). If the first if block in that function is not executed then the value of the local variable p will be uninitailised when you later call realloc(p->arr, ...). When you dereference p to get p->arr, ifp` is uninitialised then you will usually get a segfault.
EDIT 2
Two useful techniques when programming in C/C++ :
Always initialise variables at the point that you declare them. If you don't then their value is undefined. Note that this doesn't solve all problems. If you dereference an uninitialised pointer then you will usually get a segfault. If you initailise it to null and then dereference it then you will always get a segfault. Easier to debug, but it still crashes.
Always declare variables as near as possible to the point in the code that you first use them. This has the effect of reducing the chances of using an uninitialised variable because the compiler will generate an 'undeclared variable' error. The practice of declaring all variables at the start of a function is a hangover from old-style 'K&R' C, where you had to do that. Modern C doesn't require it.
So, instead of:
int foo() // Warning: bad code
{
int a;
int b;
func1();
a=func2(&b);
return a;
}
try something like:
int foo()
{
func1();
int b = 42;
int a = func2(&b);
return a;
}
Related
I am trying to code an easy list in C, which is able to store numbers.
With number SIZE, an index will be calculated and the numbers have to be stored in a kind of linear list at the array index.
However, sometimes I get a "segmentation fault", like 2 of 10 tries the output is correct.
I've gone a long search, but I couldn't find the problem.
Please keep in mind that my "solution" isn't implemented fully, so currently it's only working when the calculated index has no pointer thats stored. (Couldn't continue to code because of the error.)
Here is my code:
#define SIZE 3
#define NULL 0
typedef struct node_s node_t;
struct node_s {
node_t* next;
int number;
};
static node_t nodeArray[SIZE];
int addNumber(int numb){
int index = number % SIZE;
if(nodeArray[index].next == NULL){
node_t* node = (node_t*) malloc(sizeof(node_t));
node->number = number;
nodeArray[hash].next = node;
}
}
void print(){
for(int i = 0; i < SIZE; i++){
node_t* ptr = nodeArray[i].next;
while(ptr != NULL){
printf("%d -> ", ptr->number);
ptr = ptr->next;
}
printf("\n");
}
}
#include "dictionary.h"
#include <stdio.h>
int main(){
insert(1);
insert(2);
print();
return 0;
}
What causes the "segmentation fault" sometimes?
I appreciate any kind of help, thanks in advance!
Just after malloc you do init one member.
node->number = number;
But you do not init the other member, there is no
node->next = NULL;
Also, in your loop condition inside print(), you check ptr against NULL, but that is in most of the looping the non-initialised ptr->next from previous loop.
ptr = ptr->next;
I.e. you rely on it to be initialised to NULL.
That is probably causing the segfault.
Useful background, as pointed out by yano (thanks):
Malloc doesn't initialize memory to 0. In order to do that you can malloc followed by a memset or you can use calloc.
I am trying to insert an integer into a hash table. To do this, I'm creating an array of node*'s and I'm trying to make assignments like listarray[i]->data=5 possible. However, I'm still very confused with pointers and I'm crashing at the line with the comment '//crashes here' and I don't understand why. Was my initialization in main() invalid?
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
int data;
struct node * next;
} node;
//------------------------------------------------------------------------------
void insert (node **listarray, int size)
{
node *temp;
int value = 11; //just some random value for now, eventually will be scanned in
int index = value % size; // 11 modulo 8 yields 3
printf ("index is %d\n", index); //prints 3 fine
if (listarray[index] == NULL)
{
printf("listarray[%d] is NULL",index); //prints because of loop in main
listarray[index]->data = value; //crashes here
printf("listarray[%d] is now %d",index,listarray[index]->data); //never prints
listarray[index]->next = NULL;
}
else
{
temp->next = listarray[index];
listarray[index] = temp;
listarray[index]->data = value;
}
}//end insert()
//------------------------------------------------------------------------------
int main()
{
int size = 8,i; //set default to 8
node * head=NULL; //head of the list
node **listarray = malloc (sizeof (node*) * size); //declare an array of Node *
//do i need double pointers here?
for (i = 0; i < size; i++) //malloc each array position
{
listarray[i] = malloc (sizeof (node) * size);
listarray[i] = NULL; //satisfies the first condition in insert();
}
insert(*&listarray,size);
}
output:
index is 3
listarray[3] is NULL
(crash)
desired output:
index is 3
listarray[3] is NULL
listarray[3] is now 11
There are various issues here:
If you have a hash table of a certain size, then the hash code must map to a value between 0 and size - 1. Your default size is 8, but your hash code is x % 13, which means that your index might be out of bounds.
Your insert function should also pass the item to insert (unless that's the parameter called size, in which case it is severely misnamed).
if (listarray[index] == NULL) {
listarray[index]->data = value; //crashes here
listarray[index]->next = NULL;
}
It's no wonder that it crashes: When the node is NULL, you cannot dereference it with either * or ->. You should allocate new memory here.
And you shouldn't allocate memory here:
for (i = 0; i < size; i++) //malloc each array position
{
listarray[i] = malloc (sizeof (node) * size);
listarray[i] = NULL; //satisfies the first condition in insert();
}
Allocating memory and then resetting it to NULL is nonsense. NULL is a special value that means that no memory is at the pointed-to location. Just set all nodes to NULL, which means that the hash table starts out without any nodes. Allocate when you need a node at a certain position.
In the else clause, you write:
else
{
temp->next = listarray[index];
listarray[index] = temp;
listarray[index]->data = value;
}
but temp hasn't been allocated, but you dereference it. That's just as bad as dereferencing ´NULL`.
Your hash table also needs a means to handle collisions. It looks as if at every index in the hash table, there is a linked list. That's a good way to deal with it, but you haven't implemented it properly.
You seem to have problems to understand pointers. Perhaps you should start with a simpler data structure like a linked list, just to practice? When you have gotten a firm grasp of that, you can use what you've learned to implement your hash table.
I have an issue when using pointer parameters in a function to return values. The function correctly loads all values inside the function, but then somehow fails to pass the pointer value to the variable in the arguments.
In my case, i wrote a function witch returns 1 or 0 depending on whether allocation of memory in question failed or not, and as one of the parameters, takes a pointer to a list that needs to be entered. The structure of the list looks like this:
typedef struct sList {
int id;
char first_name[30];
char last_name[30];
struct sList *next;
} tList;
The function looks like this:
int readList(tList *start, int n){
tList *head = NULL;
tList *tail = NULL;
int i;
for (i = 0; i < n; i++){
tList *tmp = malloc(sizeof(tList));
if (tmp == NULL) return 0;
scanf("%d %s %s", &tmp->id, &tmp->first_name, &tmp->last_name);
tmp->next = NULL;
if (!head) head = tmp;
else tail->next = tmp;
tail = tmp;
}
start = head;
return 1;
}
And the main method:
void main(){
tList *start = NULL;
int n;
scanf("%d", &n);
readList(start, n);
tList *tmp = start;
while (tmp){
printf("%d %s %s\n", tmp->id, tmp->first_name, tmp->last_name);
tmp = tmp->next;
}
system("PAUSE");
return;
}
During debugging, i have concluded that the list head and start inside the function have all the entered values, but as soon as I leave the function and return to the main program the start list goes bananas. So, my question is, am I doing something wrong, because, to my knowledge, this should work in theory. Thanks in advance.
If you want to change a variable from within a function, you need to pass a pointer to it and dereference that pointer within said function. That's how C emulates pass-by-reference.
When that variable is itself a pointer, that means you need to pass a pointer to the pointer, such as with:
int readList(tList **pStart, int n){
// blah blah blah, setting up head.
*pStart = head;
return 1;
}
int main(void){
tList *start = NULL;
int n;
scanf("%d", &n);
readList(&start, n); // Note this, using address-of
// more blah
return 0;
}
The text below is an aside to your specific problem but I thought I'd mention it for completeness.
Your main function doesn't conform to the canonical ones allowed by the standard - I've changed it to make that more acceptable but it may not be necessary for your particular implementation, depending on how lax it is. It's still a good idea to follow the standard.
It's also dangerous to assume (in robust code) that scanf() always works. If it returns zero (number of items successfully scanned), n will almost certainly not be what you expect.
You make the same mistake with readList() in that you don't check its return value either. It also has the annoying aspect of causing memory leaks if an allocation fails.
I've written a simple program including linked lists. When I try to display the linked list in the function it is created, it works alright; however, when I return to main and try to display it, it does not work properly.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#define LEN 20
struct Node {
char word[LEN];
int count;
Node * next;
};
Node* build_linked_list (char array[][LEN], int N);
Node* make_ordered_copy (Node * head);
void print_list(Node * head);
int main()
{
#define NUMBER 10
char array[NUMBER][LEN]; // array which the words will be recorded
int N=6;
for(int a=0; a<N; ++a) strcpy(array[a], "test");
print_list(build_linked_list(array, N));
getchar();
return 0;
}
Node* build_linked_list (char array[][LEN], int N)
{
Node ndArray[N];
Node *head, *newnode;
head = &ndArray[0];
strcpy(head->word, array[0]); // writing the first element to the head
head->count = 0;
head->next = NULL;
for(int a=1; a<N; ++a) // writing the elements in a linked list
{
newnode = &ndArray[a];
strcpy(newnode->word, array[a]);
newnode->count = 0;
newnode->next = head; // first location now becomes second location
head = newnode;
}
print_list(head);
printf("Previous values were shown in build_linked_list\n");
return head;
}
void print_list(Node* head)
{
Node* traverse;
traverse = head;
while(traverse) // while traverse is not NULL
{
printf("\"%s\" with the frequency of %d\n", traverse->word, traverse->count);
traverse = traverse->next;
}
return;
}
When debugging in print_list function called from main, "traverse->word" shows the correct value at first but it does not print it right and then it changes to some another value.
The elements of ndArray are only valid within the scope of build_linked_list. Once the program exists that function, any access to those elements yields undefined behavior. You are building your linked list with those elements. Instead, you need to allocate memory for the nodes of your linked list on the heap, or you need to move the ndArray variable to the file scope so that it exists for the lifetime of your main method.
Inside build_linked_list you are declaring
Node ndArray[N];
which is the Node you are filling within that function. But when the execution ends the block of the build_linked_list function ndArray is deallocated therefore the pointer returned points to the memory previously allocated for ndArray but that now is no more occupied by that array.
The usual implementation of linked lists is done using the heap and dynamic memory allocation.
When building your Node array you should write:
Node* ndArray = new ndArray[N];
But at this point I higly suggest you to read about Garbage collectors and how to properly manage dynamic memory, because this is a whole new topic which has been discussed over and over here on StackOverflow.
For this answer I'll just anticipate to you that when allocating with new or new[] (for malloc and free see the C reference) you should as well delete with delete or delete[] respectively. In this case, when you are done with a linked list or ndArray you should write:
delete[] ndArray;
to free the memory. Otherwise you'll have a memory leak.
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!