Struct and Pointer Segmentation Error in C - c

can anyone help with this segmentation error i keep getting. this code is simple but the error is so hard to figure out.
struct Link {
int key;
unsigned data: 2;
struct Link *next;
struct Link *previous;
};
struct Link* addInOrder(struct Link *, struct Link);
int main() {
struct Link *head;
struct Link data1;
struct Link data2;
struct Link data3;
data1.key = 25;
data1.data = 1;
data1.next = NULL;
data2.key = 50;
data2.data = 0;
data2.next = NULL;
data3.key = 100;
data3.data = 2;
data3.next = NULL;
head = NULL;
head = addInOrder(head, data2);
}
struct Link* addInOrder(struct Link *srt, struct Link l) {
if(!srt) {
return &l;
}
struct Link *temp = srt;
while(temp->next && l.key > temp->key)
temp = temp->next;
printf("here\n");
if(l.key > temp->key) {
printf(" 1\n");
temp->next = &l;
l.previous = temp;
}
else {
printf(" 2\n");
l.previous = temp->previous;
l.next = temp;
printf( "2.2\n");
if(temp->previous) {
//printf("%i\n",temp->previous->key);
temp->previous->next = &l;
}
printf(" 2.3\n");
temp->previous = &l;
}
return srt;
}
i keep getting an error at the first line in addInOrder(). all the compiler says is Segmentation Error.
Edit: also, if i add printf("..."); right after the if statement and run it ... does not print

You're passing the second argument of addInOrder() by value (struct Link l). This creates a copy of the argument when you call the function, and in addInOrder(), l exists on the stack. You're then returning the address of the local variable and assigning it to head, but when the function exits, that variable is out of scope and is deallocated. So you're assigning an invalid address to head, and that results in a segfault.

The part (and everywhere &l is used)
if (!srt)
return &l;
is returning the address of a stack variable.
Your addInOrder function should probably have the signature
struct Link* addInOrder(struct Link* srt, struct Link* l);

Related

How to initialize struct values and output the struct correctly

I'm attempting some homework and not sure where to go from here, or if I'm on the right path to doing this correctly. This program was given to me with the goal of creating a function to create a new node with an array large enough to hold the input "count". From there I assume I'm supposed to output the created node.
I've tried setting up the node multiple ways with different pointers, I'm not sure how to initialize the 'newnode' correctly though. And every time I try to use the input 'count' such as 'newnode->array_length = count;' I get a segmentation fault, I don't understand why though, if count is input into the function, isn't it usable in the scope of it?
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<assert.h>
typedef struct node {
struct node* previous;
struct node* next;
int array_length;
int* values;
} node;
//creates a new node with an array large enough to hold `count` values
node* create_node(int count) {
//your code here:
node* newnode;
newnode = (node*) malloc(sizeof(node));
newnode->array_length = count;
newnode->values;
newnode->next=NULL;
newnode->previous=NULL;
return newnode;
}
void append(node* a, node* b) {
assert(a);
assert(b);
a->next = b;
b->previous = a;
}
int main() {
node* a = create_node(10);
assert(a->array_length == 10);
assert(a->next == NULL);
assert(a->previous == NULL);
node* b = create_node(20);
assert(b->array_length == 20);
assert(b->next == NULL);
assert(b->previous == NULL);
append(a, b);
assert(a->next == b);
assert(b->previous == a);
assert(a->previous == NULL);
assert(b->next == NULL);
for(node* cur = a; cur != NULL; cur = cur->next) {
for(int i = 0; i < cur->array_length; i++) {
cur->values[i] = i;
}
}
}
Compilation Errors:
problem2.c: In function ‘create_node’:
problem2.c:20:30: warning: implicit declaration of function ‘size’ [-Wimplicit-function-declaration]
newnode->values = malloc(size(int) * count);
^~~~
problem2.c:20:35: error: expected expression before ‘int’
newnode->values = malloc(size(int) * count);
^~~
You're not allocating memory for values. It's set by default to whatever memory was there before, which was probably an invalid pointer. This would cause a segfault when you tried to access values.
//creates a new node with an array large enough to hold `count` values
node* create_node(int count) {
//your code here:
node* newnode = malloc(sizeof(node));
newnode->array_length = count;
newnode->values = malloc(sizeof(int) * count); // malloc memory for values
newnode->next = NULL;
newnode->previous = NULL;
return newnode;
}

how to initializing a hash table in C

I have a program in C that creates a hash table.
memset is Okay but, i want to initialize with for loop.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define HSZ 127
#define HASHING(x) ((x)%HSZ)
struct node_t{
int val;
struct node_t *next;
};
struct node_t *hash_table[HSZ];
void init(void){
int i;
//memset(hash_table,0,sizeof(hash_table));
for(i=0; i<HSZ; i++){
hash_table[i]->val = 0;
hash_table[i]->next = NULL;
}
}
void insert_hash(int value){
int key = HASHING(value);
struct node_t *newNode = (struct node_t*)malloc(sizeof(struct node_t));
newNode->val = value;
newNode->next = NULL;
if(hash_table[key] == NULL){
hash_table[key] = newNode;
} else {
newNode->next = hash_table[key];
hash_table[key] = newNode;
}
}
int delete_hash(int value){
int key = HASHING(value);
if (hash_table[key] == NULL)
return 0;
struct node_t *delNode = NULL;
if (hash_table[key]->val == value){
delNode = hash_table[key];
hash_table[key] = hash_table[key]->next;
} else {
struct node_t *node = &hash_table[key];
struct node_t *next = hash_table[key]->next;
while (next){
if (next->val == value){
node->next = next->next;
delNode = next;
break;
}
node = next;
next = node->next;
}
}
return 1;
free(delNode);
}
void PrintAllHashData()
{
printf("###Print All Hash Data###\n");
for (int i = 0; i < HSZ; i++){
if (hash_table[i] != NULL){
printf("idx : %d ", i);
struct node_t *node = hash_table[i];
while (node->next){
printf("%d ", node->val);
node = node->next;
}
printf("%d\n", node->val);
}
}
}
int main(void){
init();
insert_hash(1);
insert_hash(3);
insert_hash(128);
PrintAllHashData();
}
look at this code.
for(i=0; i<HSZ; i++){
hash_table[i]->val = 0;
hash_table[i]->next = NULL;
}
The IDE I am using does not throw up a compilation error when I compile the code, but during the execution the code faults and is terminated/haulted. I tried debugging the code, it faults at this line and is stopped, I think BAD ACCESS points to Segmentation Error.
then, I changed this line to
for(i=0; i<HSZ; i++){
hash_table[i].val = 0;
hash_table[i]->next = NULL;
}
but, then I got the compilation error stating 'structure type require instead of 'struct node_t *'
I think that I don't understand clearly about struct in C.
How to fix this problem?
What you are dealing with is Undefined Behavior.
See, struct node_t *hash_table[HSZ];
So, hash_table is an array of HSZ (127) pointers of the data type struct node_t.
When you do,
for(i=0; i<HSZ; i++){
hash_table[i]->val = 0;
hash_table[i]->next = NULL;
}
hash_table[0] to hash_table[126] pointers are not pointing to anything.
So, each of them (or all of them) should be initialized first to point to an object of the type struct node_t and then you can initialize them. For that matter, Using a memset does not cause a problem because memset is filling the contents of the pointers with all zeros. There is difference between filling the pointers with all zeros and filling all zeros to the memory pointed by pointers.
Trying this,
for(i=0; i<HSZ; i++){
hash_table[i].val = 0;
hash_table[i]->next = NULL;
}
is plain wrong.
To fix the issue you are facing, you need to allocate memory dynamically using malloc. You can do the in your for loop.
for(i = 0; i < HSZ; i++)
{
//Allocate memory of the size struct_node_t
hash_table[i] = malloc(sizeof(struct node_t)); //Do not cast!
//Check if memory is allocated
if(hash_table[i] == NULL)
{
//Memory not allocated, set some error state to handle and break
break;
}
//Initialize to zero
hash_table[i]->val = 0;
hash_table[i]->next = NULL;
}
struct node_t{
int val;
struct node_t *next;
};
struct node_t *hash_table[HSZ];
when you have *hash_table[HSZ], this varible hash_table is a pointer. so whatever your action is , use hash_table-> ,syntax for pointer, mean point to somewhere.
a suggestion that when you use pointer you should always allocate memory hash_table[i] = malloc(sizeof(struct node_t));
struct node_t hash_table;
but if you initilize your varible like this, you can use hash_table.val = 0
so the way of assign value depend on how you declare your varibles
struct node_t *hash_table[HSZ];
gives you an array of pointers that are unset (i.e. not pointing to anything)
void init(void) {
int i;
// memset(hash_table,0,sizeof(hash_table));
for (i = 0; i < HSZ; i++) {
hash_table[i]->val = 0;
hash_table[i]->next = NULL;
tries writing to your invalid pointers which gives undefined behavior.
Either make the array an array of structs (instead of pointers):
struct node_t hash_table[HSZ];
...
/* note use of . instead of -> since we have structs not pointers */
hash_table[i].val = 0;
or allocate the necessary structs so the array points to something:
for (i = 0; i < HSZ; i++) {
hash_table[i] = malloc(sizeof(struct node_t));
hash_table[i]->val = 0;
hash_table[i]->next = NULL;
}

C: passing address of pointer vs passing address of array

This was an remote coding test I got a few days ago, and I've already submitted the answers so I'm not cheating here.
The question is fairly simple: implement a function to delete an item from a linked list. But with one catch: the linked list is in the form of an array.
typedef struct _Node{
int val;
struct _Node* next;
} Node;
Test input provided by the interviewer, which we can modify slightly
void printLL(Node* root){
Node* current = root;
while (current){
printf("%d\n", current->val);
current = current->next;
}
}
int main(){
Node list[6];
list[0].value =1; list[0].next = list+1;
list[1].value =2; list[1].next = list+2;
list[2].value =3; list[2].next = list+3;
list[3].value =4; list[3].next = list+4;
list[4].value =5; list[4].next = list+5;
list[5].value =6; list[5].next = 0;
delete(&list, 3) // this gives segmentation error with my implementation;
printLL(list);
return 0;
}
My answer, which is standard for linked list deletion:
void delete(Node** root, int val){
Node* current = *root;
Node* prev = NULL;
if ((*root)->val == val){
*root = (*root)->next;
//free(current); // test case not dynamically allocated
return;
}
while (current && (current->val != val)){
prev = current;
current = current->next;
}
if (!current){
printf("value not found\n");
return ;
}
else{
prev->next = current->next;
//free(current);
}
}
However, if I use pointers instead, then the function works
Node* p = list;
delete(&p, 3);
I think I understand the difference between &list and &p as function argument:
**Variable name | Variable value | Variable address**
list | address of first elem | address of first elem
p | address of first elem | some random address of the pointer
But since in the delete function we are operating with *list and *p respectively, their value should also be the same.
My guess now is because of in
*root = (*root)->next;
if *root is an array name, then it's illegal as we cannot reassign it. But if *root is a pointer, then we are freely to reassign them. Am I correct on this?
Thank you for reading through this long and messy post.

Making of linked list by head and node

here's my code in C for making of linked list. Its giving runtime error after the while loop gets executed for one time. Plz help me in correcting my code. (totally confused that where's the error.) I am making a head node first and then adding child nodes to it.
#include <stdio.h>
#include <stdlib.h>
typedef struct node nd;
typedef nd *link;
struct node{
int data;
link next;
};
typedef struct {
int size;
link head;
}list;
void create(link temp)
{
link new;
new=(link)malloc(sizeof(nd));
printf("enter data: ");
scanf("%d",new->data);
temp->next=new;
temp=temp->next;
}
list createlist()
{
list sl;
sl.size=0;
sl.head=0;
return sl;
}
int main()
{
list sl;
sl=createlist();
link temp;
temp=sl.head;
char c;
while (1)
{
printf("Add node?: ");
scanf(" %c",&c);
if (c=='y')
{
create(temp);
sl.size++;
}
else
break;
}
return 0;
}
your createlist() function is returning a reference to a local variable that goes out of scope after it returns. You should instead return a heap based value:
list* createlist() {
list* sl = (list*)malloc(sizeof(list));
sl->size=0;
sl->head=0;
return sl;
}
Initially temp points to NULL. temp = sl.head;
In create(temp) temp->next = new;
You are dereferencing a NULL, address 0x0. I get a segmentation fault when I do that.
Need to change the algorithm.
A debugger shows this problem immediately.
You could use a pointer to pointer for temp. It would be easier to read if you didn't use a typedef for a pointer to node. I haven't tested this, but it should be close:
nd ** create(nd **temp)
{
nd *new;
new=(nd *)malloc(sizeof(nd)); /* this cast shouldn't be needed */
printf("enter data: ");
scanf("%d",&(new->data));
new->next = NULL;
*temp = new;
return &(new->next);
}
/* ... */
int main()
{
nd **temp;
temp = &(sl.head);
/* ... */
temp = create(temp);
/* ... */
}

linked list operations (core dumped)

Recently I've been improving my programming skills by coding different data structures, and this is the very beginning!!!
Now I'm writing the linked list, but something annoyed happen and the trouble has been annoyed me for a long time since I am not quite sure about this error,
Segmentation fault(core dumped), but I did know I made something wrong in the operation of memory.
link_list.h:
struct LINK_LIST {
char *string;
struct LINK_LIST *next;
}link_list;
==============================
link_list.c:
#include<stdio.h>
#include<stdlib.h>
int init_link_list(struct LINK_LIST *new_link) {
//char *new_string;
int i;
//new_string = (char *)malloc(sizeof(char) * STRING_SIZE);
new_link = (struct LINK_LIST *)malloc(sizeof(struct LINK_LIST));
if (new_link==NULL) {
fprintf(stderr, "Insufficient memory!!!");
return ERROR;
}
//new_link->string = new_string;
new_link->string = NULL;
//new_link->next = NULL;
return OK;
}
Here I defined the init operation, then the insert operation:
int insert(struct LINK_LIST *link, int pos, char *in) {
int i;
if (get_length(link)>=STRING_SIZE) {
fprintf(stderr, "Link list is full!!!");
return ERROR;
}
else {
if (pos < 0 || pos-1 > get_length(link)) {
fprintf(stderr, "Invalid position");
return ERROR;
}
else {
i = 0;
do {
struct LINK_LIST *new_node;
init_link_list(new_node);
new_node->next = link->next;
link->next = new_node;
new_node->string = in;
i += 1;
} while(i<pos-1);
}
}
return OK;
}
You have a bug there :
struct LINK_LIST *new_node;
init_link_list(new_node);
In init_link_list, the value of the argument is modified :
new_link = (struct LINK_LIST *)malloc(sizeof(struct LINK_LIST));
but that modification is only local to the function ; once you get back to your calling function, that change is lost :
struct LINK_LIST *new_node;
init_link_list(new_node);
// Oops ! new_node's new value is lost !
You have a memory leak (the malloc's result is lost) and new_node is not initialized. When you try to access *new_node, you access a random position in memory, hence core dumps.
There are a few possible corrections, the easiest is to discard your OK/ERROR return values and return either a non-null pointer if malloc succeeded, or NULL if it failed :
struct LINK_LIST *init_link_list(void) {
struct LINK_LIST *new_link = malloc(sizeof(struct LINK_LIST));
if (new_link==NULL) {
fprintf(stderr, "Insufficient memory!!!");
return NULL;
}
new_link->next = NULL;
return new_link;
}
Then, code in insert becomes :
...
else {
i = 0;
do {
struct LINK_LIST *new_node = init_link_list();
// Note : here, should check whether new_node is NULL and deal with the situation
new_node->next = link->next;
link->next = new_node;
...

Resources