I am trying to create a database in c and I am trying to figure out what is going on in a simplified version.
Now hear this: No matter what value I assign N to be (which is the size of database measured in logs) I get a segfault in the third entry,even if N is 1! (or 1000).
There is no way of knowing which chunk of prohibetted memory is parsed because all that gdb reports is the line of code that the exception occured.Seems like debugging is useless here.What am I doing wrong? Thank you all in advance.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 1 //the initial size of the database
#define STRLIM 30
typedef struct log{
int id;
}log_t;
typedef struct index{
int sarcount;
int sarcap;
}index_t;
log_t* init_log(log_t** log,index_t* index);
int printList(log_t** log,index_t* index);
int menu(void);
log_t* init_log(log_t** cat,index_t* index){
cat[index->sarcount]->id=index->sarcount;
index->sarcount ;
return *cat;
}
int menu(void){
printf("1. Insert a new log\n");
printf("5. Exit\n");
printf("6. Print the list\n");
return 0;
}//just prints the menu
int printList(log_t** cat,index_t* index){
int i=0;
for(i=0;i<index->sarcount;i ){
printf("#%dID:%d\n",i,cat[i]->id);
}
}
int main(int argc, char const *argv[])
{
log_t* log=malloc(sizeof(log_t)*N);
if(!log){
perror("failed to malloc:");
exit(EXIT_FAILURE);
}
index_t* index=malloc(sizeof(index_t));
index->sarcount=0;
int choice=0;
while(1){
menu();
scanf("%d", &choice);
if(choice==1){
printf("enter a log\n");
log=init_log(&log,index);
}
if(choice==5){
printf("exiting now\n");
exit(0);
}
if(choice==6){
system("clear");
printf("printing all existing movies:\n");
printList(&log,index);
}
}//end of while
return 0;
}
CodePudding user response:
I think the problem is in init_log and printList function.
Try the below changes
In init_log
change cat[index->sarcount]->id=index->sarcount;
to (*cat index->sarcount)->id = index->sarcount;
In printList
change printf("#%dID:%d\n",i,cat[i]->id);
to printf("#%dID:%d\n",i,(*cat i)->id);
Also I would suggest you to change the structs like below (remove log and index name):
typedef struct{
int id;
}log_t;
typedef struct{
int sarcount;
int sarcap;
}index_t;
CodePudding user response:
I'm not even sure of the right terminology to describe it, but you're abstracting one more level than you should be passing the parameters to your functions. When you do
log_t* log=malloc(sizeof(log_t)*N);
You're reserving memory to N
log_t
s, and log
points to them:
______________________________________
log -----> | log_t 0 | log_t 1 | ... | log_t N-1|
--------------------------------------
When you pass &log
to init_log
(and printList
), you're passing a pointer of log
to those functions. So you have:
cat ------> log -------> (as above)
Now, when you do cat[index->sarcount]
, you're dereferencing an index of cat. However, cat
only has a length of 1, it only points to one log_t*
. Anything more than cat[0]
is out of bounds. log
is the pointer that points to log_t
objects with dimensionality beyond 0. So you need to do something like
cat ------> log[index-sarcount]
to select the appropriate log. As suggested in the other answer, you could do that like:
(*cat)[index->sarcount].id = index->sarcount;
Here, (*cat)
always dereferences to the first (and only) instance of log_t*
it points to, and [index->sarcount]
dereferences the actual log_t
object (max of N-1
) you want to modify.
But, having said all that, that extra level of indirection is really unnecessary. I would change your function prototypes to
void init_log(log_t** log,index_t* index); // well ok, still using log_t** here. Don't have to, but I consider that better practice than returning a log_t
void printList(log_t* log,index_t* index);
And then these functions would look like:
void init_log(log_t** cat,index_t* index){
(*cat)[index->sarcount].id=index->sarcount;
index->sarcount ;
}
void printList(log_t* cat,index_t* index){
int i=0;
for(i=0;i<index->sarcount;i ){
printf("#%dID:%d\n",i,cat[i].id);
// for your current `printList` function, this would need to be
//printf("#dID:%d\n", i, (*cat)[i].id);
}
}
And then you would call them like
init_log(&log,index);
printList(log,index);