Segmentation Fault 11, bad variable? - c

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.

Related

linked list traversal goes infinitely

I'm trying to implement my own version of malloc() function in c.
I decided to keep track of my allocated blocks using a linked list of meta-data objects that would store some information about the allocated chunk and and place it right before the chunk.
Now long story short while debugging I came across the fact that my linked list is behaving very strangely.
here's a piece of the code to help understanding the problem.
typedef struct meta_data
{
size_t size;
int free;
struct meta_data* next;
}meta_data;
meta_data* global_base;
void *mymalloc(size_t size)
{
if(size > 0)
{
meta_data block_meta;
void* pointer = sbrk(size + block_size);
block_meta.size = size;
block_meta.next = NULL;
block_meta.free = 0;
if(!global_base) //first allocation
{
global_base = &block_meta;
}
else
{
block_meta.next = global_base;
}
return pointer;
}
else
{
return NULL;
}
}
I wrote this code which I assume will append a new item to the tail of my global_base (linked list) every time I call mymalloc(<some_size>);
however when I tried to debug and make sure that my linked list is in order by calling mymalloc() couple of times and check is my linked list is being populated properly
void printList()
{
meta_data * node = global_base;
while (node->next != NULL)
{
printf("%zu", node->size);
printf(" -> ");
node = node->next;
}
printf(" \n ");
}
int main()
{
mymalloc(10);
mymalloc(8);
mymalloc(4);
printList();
return 0;
}
I expected my output to be
10 -> 8 -> 4 however it was 4 -> 4 -> 4 -> 4 -> 4 ..... and goes into an infinite loop
any idea where am I going wrong with this code.
I'm a little new to programming with C so my only guess is that I'm making use of reference & and pointer * improperly.
furthermore I have seen tones of code where the assignment of struct's attribute is happening with the use of -> but I could only use . to make it (could this be the problem anyhow)?
help is appreciated thanks guys
There are multiple problems with your approach:
the meta_data block_meta; is a local variable. You cannot use that to link the blocks. Local variables are reclaimed when the function exits. You should use global memory retrieved from the system with sbrk, pointed to by pointer.
the print loop is incorrect: you should write while (node != NULL) to print all blocks.
Your code has dozens of issues which I will address.
Now the problem with your code, in fact the biggest issue with it is that the myalloc function doesn't create a new block_meta node. It just declares a block_meta variable (which will end up on the stack and even worse is a recipe for disastrous bugs I believe the infinite loop is a result of this). You should you use the sbrk function to create a meta_data node before doing anything like so:
...
meta_data *block_meta = sbrk(sizeof(meta_data));
block_meta->size = size;
block_meta->next = NULL;
block_meta->free = 0;
if(!global_base)
{
global_base = block_meta;
}
The myalloc function checks to see if global_base has been assigned, that is if there is a root node in the linked list. If there is one it should simply tell the current variable to link itself to the global_base that is point it's next variable at global_base, this is a big error. Firstly, the global_base is the root node and it makes no sense to tell the current node to link itself to the root of the linked list, it's supposed to link itself to the next node not the root. Secondly, the reference to the previous node is lost which means it's not a linked list anymore. A proper solution would be saving the current node in a variable using a static variable which prevents it from getting lost when the myalloc function exits:
...
static meta_data *curr;
then right before returning the pointer to the newly allocated block you add this line to hold the node that had been newly created:
...
curr = block_meta;
return pointer;
now return to the erring else statement and change that to to ensure that the previous node points to the current node:
...
else
{
curr->next = block_meta;
}

My linked list results in segmentation fault every time even though I cannot see a flaw

I've been learning programming for some while now and I've seen this concept of "linked list" a few times and decided to give it a try:
#include <stdio.h>
#include <stdlib.h>
typedef struct cell {
int number;
struct cell* next;
} cell;
typedef struct {
cell* head;
} cell_list;
void push_front(cell_list* list, int number) {
printf("here\n");
cell* n;
printf("here2\n");
n->number = number;
printf("here3\n");
n->next = list->head;
printf("here4\n");
list->head = n;
}
int main(int argc, char* argv[]) {
cell_list* L;
push_front(L, 5);
push_front(L, 8);
push_front(L, 19);
cell* n = L->head;
// this should print "19 8 5"
while(n != NULL) {
printf("Val: %d\n", n->number);
n = n->next;
}
return 0;
}
output:
here
here2
here3
Segmentation fault: 11
I am looking for an answer to the following two questions:
(1) What is the correct way of doing this
(2) What is actually happening in my example? What is going wrong?
I am thinking that it is the compiler that fails to assign "struct cell* next" to be equal to "cell* head", etc.) OR that the FIRST allocated memory for head and the fist cell with the next property is at fault here.
Also similar posts and questions have answer to questions identical to mine however they fail at multiple points:
(1) the code example posted by OP is overly complex
(2) the code answers are good but... check 3
(3) the code answers and not explained, just "omg just use malloc you are casting voids everywhere"
(4) 1 - 3 results in a complete post with Q&A that is above my level. If your answer is "use malloc" or "the pointers point at random memory" or "you are pointing at null". Please explain because these are just programming jargon/language sentences that don't actually go into depth so that I, a beginner, can understand.
I am fully aware there are identical posts but none truly explain to a beginner like me why they allocate memory will malloc and cast the allocated space to become a linked list struct. If your answer is the same as in any of those posts, then please explain why this way is faulty and not just "This is how you do, there are 12893 posts about malloc and linked lists." I understand malloc and casting if that was not obvious but not how they properly fit in here and how my current program is created on the stack.
In the function push_front,
cell* n;
is a pointer of type cell and as David C Rankin rightly said it is uninitialized and currently holds an indeterminate address as its value until you initialize it by assigning a valid address. It does not point to a memory of type cell just like that until you make it point to a cell type.
Use malloc to allocate memory. You can refer the manual page for malloc.
cell *n= malloc(sizeof(cell));
The very next thing your code should do is to check if call to malloc has successfully allocated memory or not and some error handling if memory is not allocated.
if(NULL == n)
{
//! handle memory allocation error here
}
You also need to free this memory once you are done using it, and make the pointer point to null.
free(n);
n = NULL;
Based on your critical rant/comment at the end of original post, let me explain the code you wrote to you.
void push_front(cell_list* list, int number)
{
/// This print helps you understand where the code is.
printf("here\n");
/// This declares is a pointer variable pointing to a `cell` type.
/// Not yet pointing since not initialized.
cell* n;
/// This print helps you understand where the code is.
printf("here2\n");
/// Tries to assign value of 'number' to 'number' variable present in
/// some memory accessed as data type `cell` via a pointer.
/// But wait, is pointer really pointing to a valid memory location
/// that can be access as `cell` type? NO!
n->number = number; // You try to sit in a chair which isn't there, you fall!
printf("here3\n");
n->next = list->head; // You try to sit on a chair which isn't there, you fall!
printf("here4\n");
list->head = n; // This is a different problem as of now.
// With 'n' not initialized, list->head also get
// corrupted since assigned with a garbage value.
}
Also, in your main() function,
cell_list* L;
and then you invoke
push_front(L, 5);
In this function, you do the following:
n->next = list->head;
You design does not consider if list->head is initialized or not. If it is NULL you just made n->next point to NULL.
I understand and agree to the fact that a lot of people find pointers hard to understand and use correctly. I'll suggest that you first get comfortable with pointers overall (in general) and then go for implementing data structures with them. We all started there! You can start here.
You have to allocate memory for nodes using malloc.
Here is the updated code, I have tested it, it is working fine :)
#include <stdio.h>
#include <stdlib.h>
typedef struct cell {
int number;
struct cell* next;
} cell;
typedef struct {
cell* head;
} cell_list;
void push_front(cell_list* list, int number) {
printf("here\n");
cell* n = malloc(sizeof(cell));
printf("here2\n");
n->number = number;
printf("here3\n");
n->next = list->head;
printf("here4\n");
list->head = n;
}
int main(int argc, char* argv[]) {
cell_list* L = malloc(sizeof(cell_list));
push_front(L, 5);
push_front(L, 8);
push_front(L, 19);
cell* n = L->head;
// this should print "19 8 5"
while(n != NULL) {
printf("Val: %d\n", n->number);
n = n->next;
}
return 0;
}

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.

Unable to reverse a linked list

I was trying to reverse a linked list, however whenever I execute the following function, I get only the last element. For example, if the list contained 11,12,13 earlier. After executing the function, it contains only 13. Kindly point out the bug in my code
void reverselist() {
struct node *a, *b, *c;
a = NULL;
b = c = start;
while (c != NULL) {
c = b->next;
b->next = a;
a = b;
b = c;
}
start = c;
}
Doesn't your loop guard insure that start is null?
If you aren't using start to identify the first element of the list, then the variable you ARE using is still pointing to what WAS the first element, which is now the last.
c is a helper pointer.
void reverselist()
{
struct node *a, *b, *c;
a=NULL;
b=start;
while(b!=NULL)
{
c=b->next
b->next=a;
a=b
b=c
}
start=a;
}
// You should assume that Node has a Node* called next that
// points to the next item in a list
// Returns the head of the reversed list if successful, else NULL / 0
Node *reverse( Node *head )
{
Node *prev = NULL;
while( head != NULL )
{
// Save next since we will destroy it
Node *next = head->next;
// next and previous are now reversed
head->next = prev;
// Advance through the list
prev = head;
head = next;
}
return previous;
}
I would have made a prepend function, and done the following:
struct node* prepend(struct node* root, int value)
{
struct node* new_root = malloc(sizeof(struct node));
new_root->next = root;
return new_root;
}
struct node* reverselist(struct node* inlist)
{
struct node* outlist = NULL;
while(inlist != NULL) {
struct node* new_root = prepend(outlist, inlist->value);
outlist = new_root;
inlist = inlist->next;
}
return outlist;
}
Have not tested this, but guess you grasp the idea of it. Might be just your variable names, which don't describe anything, but I think this approach is cleaner, and easier to understand what actually happens.
EDIT:
Got a question why I don't do it inplace, so I'll answer it here:
Can you do it inplace? Are you sure you don't wish to keep the
original list?
Do you need to do it inplace? Is the malloc to time consuming/is this a performance critical part of your code? Remember: premature optimization is the root of all evil.
Thing is, this is a first implementation. It should work, and not be optimized. It should also have a test written before this implementation is even thought of, and you should keep this slow, un-optimized implementation until the test passes, and you have proved that it's to slow for your use!
When you have a passing unit test, and proven the implementation to be to slow, you should optimize the code, and make sure it still passes the test, without changing the test.
Also, is it necessary inplace operations which is the answer? What about allocating the memory before reverting it, this way you only have one allocation call, and should hopefully get a nice performance boost.
This way everyone is happy, you have a cleaner code and avoid the risk of having Uncle Bob showing up at your door with a shotgun.

Failing to build a 'queue-like' structure - problems with struct declarations?

Hey guys. This is a very simple question, I'm sure, but I'm getting myself tangled up in C references/pointers as per usual. I am trying to build a... sort-of-queue, using a sort-of-linked list. Basically, I have a struct which has contents and a pointer to the next element. I also have a pointer to the first and last elements. I then have a loop that will be building the 'sort-of-queue'. My problem is that either my logic is failing and I'm not initialising the queue right, or my knowledge of C structs is failing (which is very probable) and I'm ending up just creating one struct and constantly referring to it.
My test code is as follows:
#include <stdio.h>
struct test {
int contents;
struct test *next;
};
main() {
struct test *first = NULL;
struct test *last = NULL;
int i;
for (i = 0; i < 2; i++) {
struct test tmp;
if (first == NULL) {
first = &tmp;
last = &tmp;
} else {
last->next = &tmp;
last = &tmp;
}
tmp.x = i;
tmp.next = NULL;
}
while (first != NULL) {
printf("%d\n", first->x);
first = first->next;
}
return 0;
}
Running this, I get the output that first seems to point to a test struct that has the value of '1' as it's 'x' variable - so not the initial one like I intended. So, am I failing at logic here, or am I failing at understanding how to declare new separate structs in a loop? Or maybe both? I'm very tired... >_<.
Thanks.
The problem you have is that you are taking the address of a temporary variable, tmp, and assigning it to a pointer which lives much longer than teh temporary, first and last. After every iteration of the loop the temporary is gone and continuing to access it via first and last results in undefined behavior.
You need to create a value on the heap in order to build up the list like so (error checking omitted for brevity)
struct test* tmp = malloc(sizeof(struct test));
Later though you'll need to go through and free all of the allocated nodes.

Resources