For context, I'm a new programmer to C and I wanted to make a toy implementation of a dictionary/map from a 'Person' struct to an integer. I'm using separate chaining, so I have a hash table of linked list pointers.
So far, I've been able to add one value to the linked list just fine, but when I call the function to get the value for the Person key I'm using, the memory at one of my nodes seems to get overwritten.
More info if it's helpful, using a singly linked list with one sentinel node at the head and a tail reference.
New to StackOverflow, so I can't actually embed the image, but pictured on left is the HashTable at the beginning of the function call, when nothing has been changed. The relevant stuff is the expanded part of the Variables menu, which shows that at position 58 is a pointer to 0x61f8e0, the linked list. The linked list has a head pointer to 0x61f760, which is the sentinel value, and a tail pointer to 0x61f864, currently pointing to a Node with the value (3) for a Person named Robert who's 36 years old. The tail pointer's next field points to 0x0 (not pictured), like intended. The picture follows: https://i.stack.imgur.com/F9EJ9.png
This is what happens as soon as the first statement (which hashes the Person pointer very naively) is executed: https://i.stack.imgur.com/UJvGy.png. As you'll see, the value is now some random long number, the intrinsic age is now 1 instead of 36, the saved name is now gibberish, and worst of all the next pointer now points somewhere completely random (0x61fb10).
The function in question follows.
int tableGet(HashTable t, Person key) {
int position = hash(&key) % 100;
List* listLoc = t.table[position];
if ((int) listLoc == 0) {
return -1;
}
Node curr = *(listLoc -> head);
while (curr.next != NULL) {
if (curr.savedAge == key.age && curr.savedName == key.name) {
return curr.val;
}
curr = *curr.next;
}
return -1;
}
Here is the hash function, in case that's what's causing the problems.
int hash(Person* p) {
int sum;
Person person = *p;
int i = 0;
char nameChar = person.name[i];
while (nameChar != '\0'){
sum += (int) nameChar;
i += 1;
nameChar = person.name[i];
}
return (int) (person.age + sum);
}
And just because why not, here's all of the short amount of code I've written for this.
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdbool.h>
typedef struct Node {
int val;
int savedAge;
char savedName[100];
struct Node* next;
} Node;
typedef struct {
int age;
char name[100];
} Person;
typedef struct {
Node* head;
Node* tail;
} List;
typedef struct {
List* table[100];
} HashTable;
int hash(Person*);
Person person(int age, char name[]) {
Person p;
p.age = age;
strcpy(p.name, name);
return p;
}
Node node(int val, Person p, Node* next) {
Node n;
n.val = val;
strcpy(n.savedName, p.name);
n.savedAge = p.age;
n.next = next;
return n;
}
List list() {
List l;
Node head = node(-1, person(0, "SENTINEL"), NULL);
l.head = &head;
l.tail = l.head;
return l;
}
void listAdd(List* l, Node n) {
Node* newTailPtr = &n;
l -> tail -> next = newTailPtr;
l -> tail = newTailPtr;
}
HashTable table() {
int table[100] = {0};
HashTable t;
memcpy(t.table, table, sizeof table);
return t;
}
HashTable tableAdd(HashTable t, Person key, int val) {
int num = hash(&key) % 100;
List* loc = t.table[num];
if ((int) loc == 0) {
List newList = list();
t.table[num] = &newList;
}
listAdd((List*) t.table[num], node(val, key, NULL));
return t;
}
int tableGet(HashTable t, Person key) {
int position = hash(&key) % 100;
List* listLoc = t.table[position];
if ((int) listLoc == 0) {
return -1;
}
Node curr = *(listLoc -> head);
while (curr.next != NULL) {
if (curr.savedAge == key.age && curr.savedName == key.name) {
return curr.val;
}
curr = *curr.next;
}
return -1;
}
int hash(Person* p) {
int sum;
Person person = *p;
int i = 0;
char nameChar = person.name[i];
while (nameChar != '\0'){
sum += (int) nameChar;
i += 1;
nameChar = person.name[i];
}
return (int) (person.age + sum);
}
int main() {
Person bob = person(36, "Robert");
printf(bob.name);
printf("\n");
HashTable tab = table();
tab = tableAdd(tab, bob, 3);
printf("Added Robert to table as 3\n");
int val = tableGet(tab, bob);
if (val == 3) {
printf("Success!\n");
} else {
printf("Failure, val is %d\n", val);
}
return 0;
}
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <limits.h>
#include <stdbool.h>
struct smallnode{
char name[4];
struct smallnode *next;
};
struct bignode {
int no;
struct smallnode *element;
struct smallnode *ehead;
struct bignode *next;
};
struct bignode *classes;
struct bignode *head;
void add_class(int no){
struct bignode *newclass = malloc(sizeof(struct bignode));
newclass->no=no;
newclass->element=NULL;newclass->ehead=NULL;
if(head==NULL){classes = newclass;head = classes;head->next=NULL;}
else{
head->next=newclass;
head = head->next;
head->next=NULL;
}
}
void add_student(int noc,char* name){
struct bignode *pointer;
pointer = classes;
int i;
// get the desired class
for(i=2;i<=noc;i++){
pointer=pointer->next;
}
//add student to class
struct smallnode *newstud;
newstud = malloc(sizeof(struct smallnode));
strcpy(newstud->name,name);
if(pointer->element==NULL){
pointer->element=newstud;
pointer->ehead = pointer->element;
pointer->ehead->next=NULL;
}
else{
pointer->ehead->next=newstud;
pointer->ehead = pointer->ehead->next;
pointer->ehead->next=NULL;
}
}
void resetdata(){
struct bignode *classpointer;
struct bignode *t;
struct smallnode *studentpointer;
struct smallnode *c;
classpointer = classes;
while(classpointer!=NULL){
t=classpointer;
studentpointer=classpointer->element;
while(studentpointer!=NULL){
c = studentpointer;
studentpointer= studentpointer->next;
free(c);
}
classpointer=classpointer->next;
free(t);
}
classes = NULL;
head = NULL;
}
int main()
{
FILE *fp,*op;
int sclasw=0;int adstud=0; int noc=1;int cp=0; char c; char sname[4]=""; int sc=0;
int cases;
classes = NULL;
head = NULL;
fp = stdin;
op = stdout;
if (fp == NULL){
printf("null");
}
cases =fgetc(fp)-'0';
fgetc(fp);
//reading
int i;
for(i=1;i<=cases;i++){
c = fgetc(fp);
while(c!='\n'){
c = fgetc(fp);
if(c==':'){sclasw=1;}
else if (c=='('&&sclasw==0){adstud=1;}
else if (c=='('&&sclasw==1){}
else if (c==')'&&sclasw==1){sclasw=0;add_class(noc);}
else if (c==')'&&adstud==1){adstud=0;add_student(cp,sname);sc=0;}
else if (sclasw==1&&c==','){
add_class(noc);
noc++;
}
else if (c==','&&adstud==1){
add_student(cp,sname);
sc=0;
}
else if (c==','&&sclasw==0&&adstud==0){
cp++;sc=0;
}
else if(adstud==1){
sname[sc]=c;
sc++;
}else if(sclasw==1){/*printf("-");*/}
}
//end reading
//coloring algo
struct bignode *classpointer;
struct bignode *classpointer2;
struct smallnode *studentpointer;
struct smallnode *studentpointer2;
int *color, totalcolor;
color=malloc((noc+1)*sizeof(int));
color[1]=1; totalcolor = 1;
int col,oldcol;
//breaker
int b1=0,b2=0,b3=0;
classpointer = classes->next;
while(classpointer!=NULL){
for(col=1;col<=totalcolor;){
color[classpointer->no]=col;
oldcol=col;
studentpointer = classpointer->element;
while (studentpointer!=NULL){//for the nth element
classpointer2 = classes;
while(classpointer2!=classpointer){//check the class
if (color[classpointer2->no]==col){
studentpointer2 = classpointer2->element;
while (studentpointer2!=NULL){// for an element
if(strcmp(studentpointer->name,studentpointer2->name)==0){//that has the same student as the nth element
col++;//if theres the same student next color
color[classpointer->no]=col;
if(col>totalcolor){//if there is no next color create one
totalcolor++;b1=1;
}
b2=1;
b3=1;
break;
}
studentpointer2 = studentpointer2->next;
}
}
classpointer2=classpointer2->next;
if(b3==1){b3=0;break;}
}
studentpointer = studentpointer->next;
if(b2==1){b2=0;break;}
}
if (color[classpointer->no]==oldcol){break;}
if(b1==1){b1=0;break;}
}
classpointer=classpointer->next;
}
//end algo
fprintf(op,"Case %i: (",i);
classpointer=classes;
while(classpointer!=NULL){
fprintf(op,"C%02i:%i",classpointer->no,color[classpointer->no]);
classpointer=classpointer->next;
if(classpointer!=NULL)fprintf(op,", ");
}
fprintf(op,")\n");
resetdata();
sclasw = 0; adstud = 0; noc=1;cp=0;sc = 0;
}
return 0;
fclose(fp);
fclose(op);
}
//EDIT
Input:
1
Case 1: (C01,C02,C03,C04,C05,C06,C07,C08,C09,C10,C11),(RDA,ALB,NAC,EDF,BMG,VLJ,IVL,LGM,EGN,KSO,EST,VIV),(MCA,EDF,SLF,ADG,BCG,AAI,RRK,LGM,RLM,JGP,LRQ,WAR,KLS,DDY),(ABC,BBD,GCF,ADG,AKL,BCL,MIN,JGP,RSQ,DBU,IEY,RAW,ESZ),(ANA,JCA,CAB,NAC,GCF,GLH,VLJ,LLM,MAN,PEP,PQQ,ERR,SET,MAV,REW),(BBC,EDD,HSE,EST,ELG,ISH,JEI,EMJ,RRK,TPL,RER,EPS,AVU,CDW,ELY),(ALA,MCA,ABB,BCF,GLH,AKL,HGN,RON,JGP,ALQ,EPR,ABT,KEV,YEZ),(CDC,ISH,ABI,DHJ,ESM,FBM,RMN,PEP,VIR,JLS,LOT,MAV,TEX),(AAA,HLA,BBD,WRE,ECG,HLH,DHJ,RON,TSO,PQQ,MBT,REW,BAX,TRY,BDZ),(MCA,JCA,BCF,EGG,AAI,XTK,WIL,CSM,HLO,RSP,APR,RER,JET,DBU),(RDA,BBB,CLC,ECG,MNH,EMJ,JOK,ARM,NFM,EGN,RCN,RSP,LEQ,YIR,AVU),(ADB,WDB,BKC,CLC,SDE,UKF,BMG,HRH,BTK,LGM,QJP,EPS,KLS,BST,YNZ)
Output(in codeblocks which works just fine):
Case 1: (C01:1, C02:2, C03:1, C04:2, C05:3, C06:3, C07:1, C08:4, C09:4, C10:2, C11:4)
PS. I've already edited my source code such that there are no minor mistakes like insufficient memory for array.
This program does graph coloring by using 2 arrays. One for the classes and the other or student. The bigger linked list, which is the one for classes, has an element of a smaller linked list in each node;
Hackerrank's compiler says that it has a segmentation error, but it works fine when I run it in code blocks.
I've been stuck with this for days and I dont have any clue why this is happening. Please help me :(
I am trying to do this data stucture in C. Connect another structure to another structure. Like this:
struct room
{
int roomnumber;
struct room * nextRoom;
struct person * personList;
}*top=NULL,*temp=NULL,top1;
struct person
{
int personnumber;
struct person *next;
}*node=NULL,temp1;
Struct room has a pointer to struct person. I am having a hard time on connecting it to another struct. Is this correct?
Here is my function
void insert()
{
int val;
printf("enter value: ");
scanf("%d",&val);
newnode=create_node(val);
if(top->personList==NULL)
{
top->personList=newnode;
}
else
{
node->next=newnode;
node=newnode;
}
}
Insert a person to the room. Room is like created already. create_node() is the one who does the malloc()
Here's a version that doesn't use globals, which makes your functions much more general and reusable:
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
typedef struct person
{
int personNumber;
struct person *next;
} person; /* NOTE: this is a typedef, not a global declaration like you did */
typedef struct room
{
int roomNumber;
person *personList;
person *lastInList;
struct room *nextRoom;
} room; /* NOTE: this is a typedef, not a global declaration like you did */
person *create_person(int val)
{
person *ret = calloc(1, sizeof(*ret));
if (ret)
{
ret->personNumber = val;
ret->next = NULL;
}
return ret;
}
int room_insert(room *r, int val)
{
person *p = create_person(val);
if (NULL == p)
return -1;
if (NULL != r->personList)
r->lastInList->next = p;
else
r->personList = p;
r->lastInList = p;
return 0;
}
int main(int argc, char **argv)
{
room my_room = { 0 }; /* important! initializes pointers to NULL */
room my_other_room = { 0 }; /* important! initializes pointers to NULL */
person *p;
room_insert(&my_room, 5);
room_insert(&my_other_room, -5);
room_insert(&my_room, 10);
room_insert(&my_other_room, -10);
room_insert(&my_room, 15);
room_insert(&my_other_room, -15);
for (p = my_room.personList; p; p = p->next)
printf("%d\n", p->personNumber);
for (p = my_other_room.personList; p; p = p->next)
printf("%d\n", p->personNumber);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#define n 5
struct node
{
int num;
char *symbol;
char *code;
struct node *left;
struct node *right;
}*root_ptr, *current, *previous;
void form_bst_of_dividing_positions();
void inorderTraversal(struct node *);
int dividing_positions[n], counter = 0;
int main(int argc, char *argv[])
{
//code to populate dividing_positions
//tree structure formation
counter = 0;
root_ptr = malloc(sizeof(struct node));
root_ptr->num = dividing_positions[0];
root_ptr->code = root_ptr->symbol = NULL;
root_ptr->left = root_ptr->right = NULL;
form_bst_of_dividing_positions();
inorderTraversal(root_ptr);
return 0;
}
void form_bst_of_dividing_positions()
{
for(i=1;i<n;i++)
{
if(dividing_positions[i]==-1)
break;
else
{
struct node nodeToAdd;
nodeToAdd.num = dividing_positions[i];
nodeToAdd.code = nodeToAdd.symbol = NULL;
nodeToAdd.left = nodeToAdd.right = NULL;
current = previous = root_ptr;
while(current!=NULL)
{
previous = current;
current = (dividing_positions[i]<(current->num))? current->left : current->right;
}
if(nodeToAdd.num<(previous->num))
previous->left = &nodeToAdd;
else
previous->right = &nodeToAdd;
}
}
}
void inorderTraversal(struct node *no)
{
if(no!=NULL)
{
inorderTraversal(no->left);
printf("%d ", no->num);
inorderTraversal(no->right);
}
}
Above code gives me Segmentation fault .. in Codeblocks the output window prints 4 infinitely. 2, 3, 1, 4 = to be inserted into BST. Ive converted my Java code to C, are there any specifics to be handled in my above code?
Thanks..
Your nodeToAdd is a local variable, its address becomes invalid once you leave that code block. You should use malloc to create new nodes (and free them with free eventually).
Use malloc everytime you add a new node.