segmentation fault at c program when input is large - c

I'm working on a program that checks whether or not a graph given from an input file has some specific criteria (e.g. it's connected etc).
Although yesterday I made it work, I'm trying to tweak it a bit so it runs faster, but that leads me to the well-known segmentation fault error.
What I'm findind really frustrating is that, after tried debugging of my own, I realised that I get the error after allocating the memory I need for the graph and only when the graph gets really big, for example over 500000 nodes and edges. (I'm using a linked list for the graph).
I've been writing in C for some years and I know (or at least I think I do) that "segmentation fault" pops up when the process tries to access memory that is not supposed to, but I can't understand why it's happening in that case.
GDB gave me the below info:
Program received signal SIGSEGV, Segmentation fault.
0x0000555555554b28 in checkConnectivity (hd=<error reading variable: Cannot access memory at address 0x7fffff7feff8>, currentNode=<error reading variable: Cannot access memory at address 0x7fffff7feff0>, pointerToNode=<error reading variable: Cannot access memory at address 0x7fffff7fefe8>) at test.c:140
140 void checkConnectivity(node *hd, node *currentNode, node *pointerToNode[N])
checkConnectivity is a function that, using DFS, tries to check if the graph is connected or not. It has 3 arguments, hd the head pointer of my linked list, currentNode the node I am right now and pointerToNode, an array of pointers for getting to nodes faster (this is the tweak I wrote before about).
As you can tell hd and pointerToNode never change. I also call recursively the function after testing that I've not been yet to currentNode. So why i get this kind of error after calling it over again and again?
Any help/ideas would be much appreciated.
PS: I know that providing some code would be way more enlightening,
but my code is too long to include it in the question.
/edit/
void *safeMalloc(size_t size) {
void *p;
if((p = malloc(size)) == NULL) {
printf("Error 1 at safeMalloc.\nTerminating the program...\n");
exit(0);
}
return p;
}
typedef struct node {
long int id;
long int numOfNeighbors;
int visited;
struct neighbor *nextNeighbor;
struct node *nextNode;
} node;
typedef struct neighbor {
long int id;
struct neighbor *nextNeighbor;
} neighbor;
void checkConnectivity(node *hd, node *currentNode, node *pointerToNode[N]) {
//Mark our current node as visited.
currentNode->visited = 1;
//Find its first unvisited neighbor and call the function recursively.
if (currentNode->nextNeighbor == NULL) {
//No neighbors, return.
return;
} else {
neighbor *currentNeighbor = currentNode->nextNeighbor;
while (1) {
//If we haven't visited this neighbor yet...
if (pointerToNode[currentNeighbor->id - 1]->visited == 0) {
//Visit it.
checkConnectivity(hd, pointerToNode[currentNeighbor->id - 1], pointerToNode);
}
//Find the next neighbor of our node.
if (currentNeighbor->nextNeighbor != NULL) {
currentNeighbor = currentNeighbor->nextNeighbor;
} else {
return;
}
}
}
}
I think that the code above is enough to give you some idea of what I'm trying to do.
Node struct is for every node of my graph and every node points to every one of its neighbors (that's what neighbor struct is for), besides the next (numerically) node of the graph. Note that a link between two nodes struct doesn't mean an edge between them. This whole idea of representing a graph is taken from this article, but the code is mine.
Hope this helps! Thanks for your time.

Related

Run time Error- c project

i make a function to print an BTree in level order none recursive way.
and i have a problem to find my mistake.. the following problem showing up.
Run-Time Check Failure #2 - Stack around the variable 'pq' was corrupted.
if some one can tell where is the problem is, or how i can find it by my self next time...?
i add the full project if is needed.
enter link description here
void PrintTreeLevelOrder(bstree tree){ //The problem some where here.....
queue *pq = (queue*)malloc(sizeof(queue)); // is struct of : *front, *rear
node *current;// is struct of : root
create_queue(&pq);//create queue- items_num = 0,front = NULL,rear = NULL
if (tree.root == NULL) {
printf("Your Tree Is Empty:\n");
return;
}
current = tree.root;
enqueue(current, &pq);
printf("Your Tree Displayed As Queue:\n");
while ((size_of_queue(&pq) )!=0) {
current = pq->front;
printf("%d ", current->data);
if (current->left != NULL)
enqueue(current->left, &pq);
if (current->right)
enqueue(current->right, &pq);
dequeue(&pq, &current);
}
}
First of all, I want to say that your algorithm is correct, please read the below.
Your code has multiple mistakes that should take care of
You used the pq functions in a wrong way, you passed a pointer to a pointer instead of the original pointer, so you overwrote the code
Create_queue should allocate unless you call it init but that's not the main issue
You should check if create_queue succeeded
You are saving addresses in the queue which are queue* as int which is wrong and not portable for an architecture different than 32bit
you are assigning current which is a node (node tree struct) a queue_element element pointer struct, which is also not correct because they are different types and architectures
Please work on these points, if you want more details please contact me
I would be happy to help

Standard C - Crashing at malloc (despite working ~10 minutes ago)

Not sure what is going on with my code. Was implementing a simple binary search tree and got everything to work - had no problem inserting a bunch of elements. Then, while trying to add some file IO functionalities, all of the sudden my program was crashing. I thought perhaps I had messed something up with the file pointers and writing (though that doesn't really make sense either, since it leaves the rest of the code untouched), so I pulled up an archived version of the code, and BAM - crashing after 2 inputs even though it was fully working the last time I tried it!
Adding a bunch of debug print statements (sorry still need to learn to use the debugger), it seems the crash most often occurs at my malloc - but sometimes it randomly crashes at different points if I keep rerunning the program too.
I'm really confused by this. How is it that I was able to insert ~10 elements and now I somehow cant even insert 3? Task manager says I have ~4Gb of RAM free, and it's not like I'm doing some massive amount of inputs - this should cost memory absolutely nothing. Also how is it crashing in different places even though I'm running the exact same code?
I'd be very grateful for any insights. Running Windows 10, Codeblocks as the IDE. Code for the main and the function in question below. In most of my runs, the program crashes before the third insert reaches "Space Allocated", but sometimes it manages to insert it - and then the program crashes anyways, for no apparent reason.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef struct node *BSTREE;
struct node
{
int data;
BSTREE left;
BSTREE right;
};
BSTREE insert(BSTREE root, int number);
BSTREE find(BSTREE root, int number);
void inOrderTraversal(BSTREE subtree);
int main(){
BSTREE root = NULL;
root = (insert(root, 2));
insert(root, 4);
insert(root, 1);
}
BSTREE insert(BSTREE root, int number)
{
printf("\n\nInside insert");
BSTREE temp = NULL;
if(!(root)){
printf("\nInside empty root");
temp = (BSTREE*)malloc(sizeof(BSTREE));
printf("\nSpace allocated");
temp->left = NULL;
temp->right = NULL;
printf("\nleft and right set to null");
temp->data = number;
printf("\n data set to number");
root = temp;
printf("\nroot is now temp; Before returning root");
printf("\n node data: %d %d %d", root->data, root->left, root->right);
return root;
}
if(number < root->data){
root->left = (insert(root->left, number));
}
else if(number > root->data){
root->right = (insert(root->right, number));
}
else if(number == root->data){
return root;
}
}
The line:
temp = (BSTREE*)malloc(sizeof(BSTREE));
is an excellent example of why Is it a good idea to typedef pointers? recommends 'No'.
You have two problems:
You're allocating a pointer to a pointer to a struct node to a pointer to a struct node — you don't need the * in the cast (and there are those who'd argue you don't need to cast the result of malloc()).
You're only allocating enough space for a pointer but you're using it as if it was big enough to hold a struct node; it isn't.
The basic fix is one of these lines:
temp = (BSTREE)malloc(sizeof(struct node));
temp = malloc(sizeof(*temp));
There isn't a way to use BSTREE in the first sizeof operator that I can think of. The second is actually a sound technique; it remains valid even if the type of temp changes. You can create various hybrids too.
I'd recommend using:
typedef struct BSTree BSTree;
struct BSTree
{
int data;
BSTree *left;
BSTree *right;
};
and then you'd write:
BSTree *temp;
temp = (BSTree *)malloc(sizeof(BSTree));
temp = malloc(sizeof(*temp));
You might note that the second alternative hasn't changed.
It seems as you are not returning the memory that you reserve with malloc. When using dynamic memory, it's important to release it again, otherwise you'll have a so called memory leak and the size will just increase until program crashes.
Function for releasing (freeing) memory is free();
A call should look something like free(temp);
I can not try it to make sure because I don't have your library used so I can't guarantee it works, but I hope it solves it.

How to free recursive struct (trie)

FINAL EDIT
My function that frees the memory works properly, and as milevyo has suggested, the problem lies in node creation, which I had fixed. I now have a separate problem where the program segfaults when run normally, but it cannot be reproduced in gdb or valgrind. However, that is a separate question altogether.
I have since found out that this segfault happened because I did not check for the EOF character properly. As per Cliff B's answer in this question, the check for EOF happens only after the last character in the file. As a result, in my function that loads the dictionary file, I had assigned the last character of the file to some i (which in this case was -1 according to a printf call), and tried to create and access a child node if index -1. This caused a segmentation fault, and also caused problems with my unload function, which would not unload the very last node I created.
As to why the segmentation fault does not appear when I run the program in gdb or valgrind, I have no idea.
EDIT 3
While stepping through my load function where the node creation happens, I notice an unexpected behaviour. I believe the problem lies somewhere in these lines of code, which are embedded within a for loop. The casting to (node*) is just to be safe, though it does not affect the running of the code to my knowledge.
// if node doesnt exist, calloc one, go to node
if (current_node->children[i] == NULL)
{
current_node->children[i] = (node*) calloc(1, sizeof(node));
nodes++;
}
current_node = current_node->children[i];
While stepping through the load function, I see that my current_node->children[i] seem to be calloc'ed properly (all children set to NULL), but the moment I step into current_node->children[i] and examine its children (see image below), I see that the addresses get screwed up. Specifically, the i'th child in the children node gets set to 0x0 for some reason. While 0x0 is supposed to be equal to NULL (correct me if I'm wrong), my free_all function seems to want to go into the 0x0 pointer, which of course results in a segfault. Can anyone shed light on how this might happen?
Values of children[i]
EDIT 2: I'm using calloc to create my nodes
root = calloc(1, sizeof(node));
For my child nodes, they are created within a for loop where I iterate over characters of the dictionary file I'm reading in.
if (current_node->children[i] == NULL)
{
current_node->children[i] = calloc(1, sizeof(node));
nodes++;
}
c in this case represents the character of the word being read in. I get i using the following:
if (c == '\'')
i = 26;
else if (isalpha(c))
i = c - 97;
EDIT: I'm thinking that something in my node creation is faulty, as milevyo suggested. This is because if I print out the addresses, it goes from 0x603250 to 0x603340 to 0x603430 to 0x603520, then finally to (nil), before it segfaults. I have verified that the root node gets passed in correctly by printing out its value in gdb. I'll try to figure it out.
ORIGINAL QUESTION
I'm running into a segfault when trying to free a recursive struct, but cannot figure out why, and would like some help.
My struct is defined as follows:
typedef struct node
{
bool is_word;
struct node* children[27];
}
node;
This is meant to implement a trie structure in which to load a dictionary into, for purposes of a spellcheck. After the spellcheck is done, I need to free the memory that I've allocated to the trie.
This is my current function which should free the trie when passed the root node, but it segfaults when doing so, though not immediately:
void free_all(node* curs)
{
int i;
// recursive case (go to end of trie)
for (i = 0; i < 27; i++)
{
if (curs->children[i] != NULL)
{
free_all(curs->children[i]);
}
}
// base case
free(curs);
}
Where could I have gone wrong? If more information is needed, please let me know.
i think, root node is faulty ( maybe it is null). if not, look elsewhere. in node creation for example.
void free_all(node* curs)
{
int i;
if(!curs) return; // safe guard including root node.
// recursive case (go to end of trie)
for (i = 0; i < 27; i++)
free_all(curs->children[i]);
// base case
free(curs);
}
The free_all function is ok. You have to check you set to NULL all children not allocated. This includes nodes that are not leaves, but don't have all the 27 children.
If that is ok, or fixing it doesn't fix the segfault, you have to debug.

Segmentation Fault 11, bad variable?

When I compile a source file I receive a segmentation fault: 11 error. I have been able to narrow it down, and I know that the error is coming from this function:
struct drecord { /* use this struct for double-linked lists */
int value;
struct drecord *previous;
struct drecord *next;
};
void sort()
{
struct drecord *currentNode;
struct drecord *end;
for(end=head->previous; end!=NULL && end!=head; end=end->previous)
{
for(currentNode = head; currentNode != NULL && currentNode != end; currentNode = currentNode->next)
{
if (currentNode->value > currentNode->next->value)
{
swap(currentNode, currentNode->next);
}
currentNode = currentNode->next;
}
}
printf("\n");
printf("%d", numElements);
while(numElements > 0)
{
currentNode = head;
printf("Sorted elements: %d", currentNode->value);
delete(currentNode->value);
numElements = numElements - 1;
}
}
void swap(struct drecord *drecord1, struct drecord *drecord2)
{
int aux = drecord1->value;
drecord1->value = drecord2->value;
drecord2->value = aux;
}
Even more specifically, I think that it is coming from the part of the code after printf("\n"), because printf("\n") works but nothing past it does. I had thought that it was a problem with the variable numElements, but I have this same exact code in another source file and it works perfectly. numElements is a global variable. What is wrong?
There are a few issues with your code, but let's focus on the one likely to cause the crash you're seeing:
You call delete(currentNode->value); but isn't value an int? At least, that's how you treat it in your implementation of swap. If it is an int, then what exactly are you deleting?
Perhaps your intent was to delete currentNode, instead. But even that is wrong: please note that that while that will successfully delete currentNode (assuming that it was allocated with new of course), it won't change the head pointer. It will continue to point to where it pointed before: the memory you just called delete on.
So, either way, you're screwed and you should rethink what you're doing in that loop.
As a postscript: while this kind of bug is trivial to find even without a debugger by casual inspection of the code, please invest the time to learn how to use a debugger. It's a critical skill for anyone who wants to program and it will pay dividends: not only will it help you track bugs down, but it will give you a deeper understanding of what is happening and make you a better programmer in the process.

Can anyone help me with my binary search tree

I'm a computer engineering student and I have to write BST as an assignment but the code is not like what everyone written(so far as I search for some example,so I'm desperate now) Here is my code so far(My classroom use C as a main language not C++)
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
typedef struct bst_node
{
int data;
struct bst_node *right;
struct bst_node *left;
}BST_NODE;
typedef struct bst
{
int size;
BST_NODE *root;
}BST;
void print(BST_NODE *pos)
{
printf("%d(0)",pos->data);
if(pos->left != NULL)
{
printf("%d(L)\n",pos->left->data);
pos=pos->left;
}
if(pos->right != NULL)
{
printf("%d(R)\n",pos->right->data);
pos=pos->right;
}
if(pos->left != NULL)
print(pos->left);
if(pos->right != NULL)
print(pos->right);
}
int main()
{
int number;
BST b;
BST_NODE *pos;
b.root=NULL;
while(1)
{
scanf("%d",&number);
printf("value=%d",number);
if(number<=0)
break;
if(b.root==NULL)
{
b.root=(BST_NODE*)malloc(sizeof(BST_NODE));
pos=b.root;
pos->data=number;
pos->left=NULL;
pos->right=NULL;
}
else
{
pos=b.root;
while(pos)
{
if(number>pos->data)
{
if(pos->right==NULL)
{
pos->right=(BST_NODE*)malloc(sizeof(BST_NODE));
pos->right->left=NULL;
pos->right->right=NULL;
pos->right->data= number;
pos=pos->right;
}
else
{
pos->right->data= number;
pos=pos->right;
}
}
if(number<pos->data)
{
if(pos->left==NULL)
{
pos->left=(BST_NODE*)malloc(sizeof(BST_NODE));
pos->left->left=NULL;
pos->left->right=NULL;
pos->left->data=number;
pos=pos->left;
}
else
{
pos->left->data=number;
pos=pos->left;
}
}
}
}
}
print(b.root);
return 0;
}
I don't know what wrong with this code because it can only receives 2 value then it stops working. The only thing I found out so far to be a problem is while(pos)loop and I try to fix this for week.I would be grateful,if anyone help me solve this problem. Print it out to would be great.
P.S -stop working mean the windows I run program in just freeze or hang.
You want to break out of your while(pos) loop as soon as you malloc a new node. You are done inserting so stop working.
Also you don't want to overwrite all ->data values while traversing the tree in your else branches.
When you add a value to the tree, it looks like you always replace the existing value with the input number instead of just traversing to the next level. Remove
pos->right->data = number;
And
pos->left->data = numbér;
From main()
You also should add an 'else' before the left node check. As it stands, you're checking the right branch and then the left branch every time through the loop. If you check the right branch and make a hit, you'll always check the left branch, too. Probably not a problem, but unnecessary.
Not sure that's the reason 'it stops working' as 'it stops working' is awful darn vague, but that looks suspicious to me.
Additionally...
Be consistent on your indentation. Sometimes the indentation is more spaces than other times
add spaces between struct definitions and Breen function declarations. Think of these things as chapters in a book. Use the whitespace to make separate things clearly separate.
add a prompt within the loop to indicate that it's expecting input. If you think your app has frozen, it may simply be waiting for input
add a check at the start of print() and sensibly handle null roots. This could occur if you type a negative number as your input the first time around. Missing such a check and typing a negative as your first input may crash.
Oh! And use calloc() instead of malloc(). Calloc initializes new memory to nulls, while malloc does not. Malloc just gives you whatever memory it happens to give you, containing whatever random garbage it may contain. If you use calloc, you will have less liklihood of issues with bad memory.

Resources