CSR and BFS always finds with 0 steps - c

I am trying to create a program that creates a graph in the CSR (Compressed Sparse Rows) format with two arrays where one array is the offset of each node and the second one are the edges. The data are read from a file, and I am using dictionary/map to reserve on memory. Then, it asks for the node and edge and using the BFS way of searching a graph, it must print if a path exists. However, no matter what I type, the program always returns that it found but does not print that it exists and the steps are 0.
The file looks like this:
737 6340
1740 1199
1738 1199
1738 1811
1738 2085
1739 1199
1741 214
1741 1199
1741 1419
1741 1496
1741 1723
The program looks like this:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct{
int* num;
int size;
int top;
} stack;
int nodesdoublesize(int** array,int n){
int* new_array=malloc(n*2*sizeof(int));
if(new_array==NULL){
printf("Error allocating memory\n");
abort();
}
n*=2;
for(int i=0;i<n;i++){
new_array[i]=(*array)[i];
}
free(*array);
*array=new_array;
return n;
}
void stack_destroy(stack *s){
free(s->num);
free(s);
}
int hashcmp(const void *a,const void *b){
return ( *(int*)a - *(int*)b );
}
int hashdoublesize(int** hash,int nodes){
int* new_array=malloc(nodes*2*sizeof(int));
if(new_array==NULL){
printf("Error allocating memory\n");
abort();
}
for(int i=0;i<nodes;i++){
new_array[i]=(*hash)[i];
}
nodes*=2;
free(*hash);
*hash=new_array;
return nodes;
}
typedef struct {
int start;
int end;
} path;
stack* stack_create(){
stack *s=malloc(sizeof(stack));
if(s==NULL){
printf("Error allocating memory for stack\n");
abort();
}
s->top=0;
s->size=10;
s->num=malloc(s->size*sizeof(int));
if(s->num==NULL){
printf("Error allocating memory\n");
abort();
}
return s;
}
int cmp(const void *a,const void *b){
int l=((path*)a)->start;
int r=((path*)b)->start;
if(l>r)
return 1;
if(l<r)
return -1;
else
return 0;
}
int doublesize(path** array,int n){
path* new_array=malloc(n*2*sizeof(path));
if(new_array==NULL){
printf("Error allocating memory\n");
abort();
}
for(int i=0;i<n;i++){
new_array[i]=(*array)[i];
}
free(*array);
*array=new_array;
n*=2;
return n;
}
int bfs(int* arraynodes,int* arrayedges,int n,int st,int end){
stack *s=stack_create();
int color[n];
for(int i=0;i<n;i++){
color[i]=-1;
}
color[st]=0;
s->num[s->top]=st;
while (s->top!=0){
for (int i = arraynodes[st]; i < arraynodes[st+1];i++){
if (color[i]==-1){
color[i]=0;
s->top++;
s->num[s->top]=i;
if(s->top==s->size){
s->top=nodesdoublesize(&s->num,s->size);
}
if(s->num[s->top]==end){
printf("Exists\n");
return 0;
}
}
s->top--;
color[i]=1;
}
}
return 1;
}
int main()
{
int maxsize=10;
int test;
char buff[200];
int counter=0;
char c;
int i;
path* array=malloc(maxsize*sizeof(path));
if(array==NULL) {
printf("Error allocating memory\n");
abort();
}
FILE* fd=fopen("Wiki-Vote.txt","r");
if(fd==NULL) {
printf("Error opening file\n");
abort();
}
while(fgets(buff,200,fd)) {
c=buff[0];
if(c=='#') {
continue;
}
sscanf(buff,"%d%d",&array[counter].start,&array[counter].end);
counter++;
if(counter==maxsize){
maxsize=doublesize(&array,maxsize);
}
}
maxsize=counter;
counter=0;
qsort(&array[0],maxsize,sizeof(path),cmp);
counter=1;
int nodes=10;
int* hash=malloc(nodes*sizeof(int));
if(hash==NULL){
printf("Error allocating memory\n");
abort();
}
for(i=0;i<maxsize;i++){
if(hash[counter-1]==array[i].start)
continue;
hash[counter]=array[i].start;
counter++;
if(counter==nodes){
nodes=hashdoublesize(&hash,nodes);
}
}
int j;
for(i=0;i<maxsize;i++){
for(j=0;j<counter;j++){
if(hash[j]==array[i].end)
break;
}
if(j!=counter)
continue;
hash[counter]=array[i].end;
counter++;
if(counter==nodes)
nodes=hashdoublesize(&hash,nodes);
}
nodes=counter;
qsort(&hash[0],nodes,sizeof(int),hashcmp);
int* arraynodes=malloc(nodes*sizeof(int));
int* arrayedges=malloc(maxsize*sizeof(int));
if(arraynodes==NULL||arrayedges==NULL){
printf("Error allocating memory\n");
abort();
}
int edge_count=maxsize;
int edge_offset=0;
for(int i=0;i<nodes;i++){
int current_node=hash[i];
arraynodes[i]=edge_offset;
while(edge_offset<edge_count&& array[edge_offset].start == current_node){
edge_offset++;
}
}
for (int i = 0; i < edge_count; i++){
arrayedges[i]=array[i].end;
}
int x;
printf("give number to search: ");
scanf("%d",&x);
for(i=0;i<nodes;i++){
if(x==hash[i]){
printf("found \n");
break;
}
}
if(i==nodes){
printf("not found \n");
abort();
}
/* for(j=arraynodes[i];j<arraynodes[i+1];j++){
printf("%d\n",arrayedges[j]);
}*/
int en=hash[i];
int st;
printf("From where would you like to start: ");
scanf("%d",&st);
printf("\n");
int found;
found=bfs(arraynodes,arrayedges,nodes,st,en);
if(found){
printf("Found\n");
}
else
printf("Not found\n");
free(arraynodes);
free(arrayedges);
free(hash);
fclose(fd);
free(array);
return 0;
}
Thank you for your time and any help will be apreciated.

Your stack_doublesize function is very wrong, and could be a reason behind your problems as using it will lead to undefined behavior.
Currently as shown (as I write this answer), it will basically reallocate a single stack structure into an array of 20 stack structures. It will then treat the single original stack structure as an array of 10 structure, and copy those 10 to the new array. This will of course go out of bounds since you don't have an array of 10 structures, only one single structure.
Furthermore you don't reallocate the memory pointed to by the stack structure itself, the num member will still be the same. That means you will go out of bounds of this memory as well.
As a solution for these issues I suggest you change your reallocation functions to something like this:
// Reallocate a dynamically allocated array, doubling its size
int nodesdoublesize(int **array,int n)
{
int* new_array = realloc(*array, n * 2 * sizeof *new_array);
if (new_array == NULL)
{
fprintf(stderr, "Out of memory\n");
abort();
}
*array = new_array;
return n * 2;
}
// Reallocate the data of the stack
void stack_doublesize(stack *s)
{
s->size = nodesdoublesize(&s->num, s->size);
}
Change your call to stack_doublesize to follow the new funciton.
There are probably more errors and problems in your code that I haven't found. I suggest you start by building with extra warnings enabled (-Wall -Wextra -Wpedantic if using GCC or Clang, and /W4 if using MSVC), and treat all warnings as errors that you need to fix.

Related

Can't identify memory access error in code, keeps giving segmentation faults

I have tried creating a program that uses simple stack functions like push to add the contents of the statement onto a stack from where I then print out each character and then reverse the statement. I have used the '.' and '->' member access variables to change the contents of the struct based stack. Upon compiling it prints out the original statement, but after that it gives a segmentation error, saying I am attempting to dereference an uninitialised pointer. Can someone guide me as to how I should solve this problem as it isn't stating the line I have made the problem either.
#include <stdio.h>
#define MAX 1000
#define FULL (MAX - 1)
#define EMPTY -1
typedef struct stack {char s[MAX]; int top;} stack;
int top = EMPTY;
int isFull()
{
if(top == FULL)
return 1;
else
return 0;
}
int isEmpty()
{
if(top == EMPTY)
return 1;
else
return 0;
}
void reset(stack *stk)
{
stk -> top = EMPTY;
}
void push(char c, stack *stk)
{
stk -> top++;
(*stk).s[(*stk).top] = c;
}
char pop(stack *stk)
{
return (*stk).s[(*stk).top--];
}
void print(stack *stk)
{
int i;
while(1)
{
if(isEmpty())
{
printf("Stack underflow\n");
break;
}
for(i = 0; i <= top; i++)
{
printf("%c\n", (*stk).s[i]);
}
printf("\n");
return;
}
}
void reverse(stack *stk)
{
int i;
while(1)
{
if(isEmpty())
{
printf("Stack underflow\n");
break;
}
for(i = top; i >= 0; i--)
{
printf("%c", (*stk).s[i]);
}
printf("\n");
return;
}
}
char peek(const stack *stk)
{
while(1)
{
if(isEmpty())
{
printf("Stack underflow\n");
break;
}
return (*stk).s[(*stk).top];
}
}
int main()
{
stack stack_of_char;
char *str = "i am otto am i";
int i;
reset(&stack_of_char);
printf("original is: %s\n", str);
while(str[i] != '\0')
{
push(str[i++], &stack_of_char);
}
print(&stack_of_char);
reverse(&stack_of_char);
return 0;
}
There are several issues with your program. Let's begin with the global variable top. This is causing problems because on the one hand you have a stack struct responsible for maintaining a stack, and that has its own top. But then you have this global which you're not even using anywhere. It's almost like you added it to get around compiler errors that you didn't understand ;)
So let's ditch that, and fix your stack functions. I'm rearranging the parameters of the push function so that the stack is the first argument. This is a bit more conventional.
typedef struct stack {
char s[MAX];
int top;
} stack;
int isFull(stack *stk)
{
return stk->top == FULL;
}
int isEmpty(stack *stk)
{
return stk->top == EMPTY;
}
void reset(stack *stk)
{
stk->top = EMPTY;
}
void push(stack *stk, char c)
{
if (isFull(stk))
return;
stk->s[++stk->top] = c;
}
char pop(stack *stk)
{
if (isEmpty(stk))
return '\0';
return stk->s[stk->top--];
}
For the pop function, I arbitrarily return a NUL character if the stack is empty, because something must be returned. But really, you should never call this function if the stack is empty.
Let's look at your display functions now. The first thing I notice is that these are really convoluted. There is no need for that complexity. Look here:
void print(stack *stk)
{
for(int i = 0; i <= stk->top; i++)
{
printf("%c\n", stk->s[i]);
}
printf("\n");
}
void reverse(stack *stk)
{
for(int i = stk->top; i >= 0; i--)
{
printf("%c", (*stk).s[i]);
}
printf("\n");
}
char peek(const stack *stk)
{
if (isEmpty(stk))
{
printf("Stack empty!\n");
return '\0';
}
return stk->s[stk->top];
}
And so all that remains is a little tidy-up of your main function, and adjust the parameter order for push.
int main()
{
const char *str = "i am otto am i";
printf("original is: %s\n", str);
stack stack_of_char;
reset(&stack_of_char);
for (int i = 0; str[i]; i++)
{
push(&stack_of_char, str[i]);
}
print(&stack_of_char);
reverse(&stack_of_char);
}
Note also that you shouldn't really be walking over your stack with those functions. The typical way you would use a stack to reverse something is to push values onto it and then pop them off. So, you can print the string in reverse like this:
// Pop characters from stack to print in reverse
while (!isEmpty(&stack_of_char))
{
char c = pop(&stack_of_char);
putc(c, stdout);
}
putc('\n', stdout);
Without initialization, the integer will be a random value. It is the root cause of the memory access error.
You will need to initialize the variable properly. In main function, instead of
int i;,
you should use
int i = 0;.
Assume that you plan to access the value starting from index 0.

Segmenattion fault using malloc , array of structures for mergesort

This code tries to apply merge sort on an array of structures and sort it.There is segmentation fault in mergesort function which i'm uable to predict why. I've attached the output as well and if anything is needed then please let me know.
#include<stdio.h>
#include<stdlib.h>
typedef struct node node;
struct node{
int index; // record-key
char fname[20], lname[20], dob[20], location[20], dept[20];
}demo,delta;
node delta ={-1,'a','a','a','a','a'};
void merge(node [], int, int, int );
void mergesort(node [], int , int );
void mergesort(node a[], int start, int end){
int mid = (start+end)/2;
if(start<end){
mergesort(a,start,mid);
mergesort(a,mid+1,end);
merge(a,start,mid,end);
}
}
void merge(node a[], int start, int mid, int end){
node *b = malloc(sizeof(demo)*end*2); //creating two arrays
node *c = malloc(sizeof(demo)*end*2);
int j=0,k=0,i=0,e=0,f=0;
for(i=start;i<mid+1;i++){ //storing first half of main array into b
b[i] = a[i];
}
b[i+1]=delta; //this is a check value used for checking the length in a loop below
for(k=mid+1;k<end+1;k++){ //storing second part of main array into c
c[j]=a[k];
j++;
}
c[j+1]=delta; //this is just a check value to check length
for(i=start;i<end+1;i++){
if(b[e].index==delta.index){ //if array b ends
while(c[f].index!=delta.index){
a[i]=c[f]; //copy remaining contents of c into a
i++;
f++;
}
break;
}
if(c[f].index==delta.index){ //if c ends
while(b[e].index!=delta.index){ //copy remaining contents of b into a
a[i]=b[e];
i++;
e++;
}
break;
}
if(b[e].index>c[f].index){ //compring first element of both b and c and overriding smaller value in main array
a[i]=c[f];
f++;
}
else if(b[e].index<=c[f].index){ //compring first element of both b and c and overriding smaller value in main array
a[i]=b[e];
e++;
}
}
for(i=0;i<end+1;i++){
printf("arr index: %d \n",a[i].index); //just for checking
}
}
int main(int argc ,char *argv[]){
printf("entered in main\n");
char temp[20];
int i;
FILE *fp =fopen(argv[1],"r");
// printf("bakri\n");
if(fp==NULL){
printf("file not opened\n");
exit(1);
}
node demo;
printf("demo made %ld\n",sizeof(demo));
int var = atoi(argv[2]);
node *arr = malloc(sizeof(demo)*var*2);
if(arr==NULL){
printf("arr is null\n");
exit(2);
}
printf("array made\n");
for(i=0;i<(atoi(argv[2]));i++){
fgetc(fp);
fscanf(fp,"%s %s %s %s %s %s",temp,arr[i].fname,arr[i].lname,arr[i].dob,arr[i].location,arr[i].dept);
arr[i].index=atoi(temp);
}
fclose(fp);
for(i=0;i<atoi(argv[2]);i++){
printf("\n%d",arr[i].index);
}
int len = atoi(argv[2]);
mergesort(arr,0,len-1);
for(i=0;i<len;i++){
printf("%d \n",arr[i].index);
}
return 0;
}
The output is -
entered in main
demo made 104
array made
28053
31163
3786
33086
16355
4792
26524
21076
21367
27286arr index: 28053
arr index: -414853824
Segmentation fault (core dumped)
The max index of the array you allocate with:
node *c = malloc(sizeof(demo)*end);
is end - 1. And then you have:
for(k=mid+1;k<end+1;k++){
c[j]=a[k];
j++;
}
You're going out of the boundaries of the array, which will cause segmentation fault.

Push and Pop function [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
Im trying to replicate the push and pop functions using integers and an int array. However Im having trouble with finding the size of the array in the push function. How would I find the size or 'push' a new value into the array
typedef int data_t;
int
main(int argc, char **argv){
int *S, i;
S = malloc(10*sizeof(int));
S = NULL;
push(1,S);
push(3,S);
for(i = 0; S[i]; i++){
printf("%d\n",S[i]);
}
return 0;
}
void
push(data_t n,int *S ){
int size = 0, i = 0;
if (S == NULL){
S[0] = n;
}
else{
while(S[i] != NULL){
size++;
i++;
}
S[size] = n;
}
}
You first allocate an array of ten integers and assign the pointer to S. You then reassign S, making it point to NULL. That is not a valid pointer you can dereference. Dereferencing a null-pointer leads to undefined behavior.
You need to keep the size of the stack separately, and pass it along to the functions. Or use a structure containing both the pointer and the size.
I've written the below code on the fly! It seems to run good! It implements a stack management with stack overflow/underflow controls.
The main contains code to demonstrate the use of all the stack functions:
int initStack(StackType * stack, size_t numOfElement);
int freeStack(StackType * stack);
int push(StackType * stack, int value);
int mayPush(StackType *stack);
int pop(StackType * stack, int * value);
int pop2(StackType * stack);
int mayPop(StackType *stack);
StackError getError(StackType * stack);
The code uses the following basic stack operations:
stack init: sp="stack dimension".
push: stack[--sp]=value;
pop: stack[sp++]=value;
Stack overflow: (sp==0) [when we try to push a value]
Stack underflow: (sp=="stack dimension") [when we try to pop a value]
The code:
#include <stdio.h>
#include <malloc.h>
typedef enum {
NO_ERROR,
MEMORY_ERROR,
STACK_OVERFLOW,
STACK_UNDERFLOW
} StackError;
typedef struct {
int * stack;
size_t numOfElem;
size_t sp; //stack pointer
StackError err;
} StackType;
int initStack(StackType * stack, size_t numOfElement);
int freeStack(StackType * stack);
int push(StackType * stack, int value);
int mayPush(StackType *stack);
int pop(StackType * stack, int * value);
int pop2(StackType * stack);
int mayPop(StackType *stack);
StackError getError(StackType * stack);
int initStack(StackType * stack, size_t numOfElement)
{
if ( (stack->stack=malloc(sizeof(*stack->stack)*numOfElement))==NULL ) {
stack->err=MEMORY_ERROR;
return stack->err;
}
stack->err=NO_ERROR;
stack->numOfElem=numOfElement;
stack->sp=numOfElement; //The stack is void!
return stack->err;
}
int freeStack(StackType * stack)
{
if (stack->stack==NULL){
stack->err=MEMORY_ERROR;
return stack->err;
}
stack->err=NO_ERROR;
free(stack->stack);
stack->stack=NULL;
return stack->err;
}
int push(StackType * stack, int value)
{
if (stack->stack==NULL) {
stack->err=MEMORY_ERROR;
return stack->err;
}
if (!stack->sp) {
stack->err=STACK_OVERFLOW;
return stack->err;
}
stack->err=NO_ERROR;
stack->stack[--stack->sp]=value;
return stack->err;
}
int pop(StackType * stack, int * value)
{
if (stack->stack==NULL) {
stack->err=MEMORY_ERROR;
return stack->err;
}
if (stack->sp>=stack->numOfElem) {
stack->err=STACK_UNDERFLOW;
return stack->err;
}
stack->err=NO_ERROR;
*value=stack->stack[stack->sp++];
return stack->err;
}
int pop2(StackType * stack)
{
int value;
pop(stack,&value);
return value;
}
int mayPush(StackType *stack)
{
return (stack->stack!=NULL && stack->sp>0)?1:0;
}
int mayPop(StackType *stack)
{
return (stack->stack!=NULL && stack->sp<stack->numOfElem)?1:0;
}
StackError getError(StackType * stack)
{
return stack->err;
}
int main(void)
{
StackType stack;
int res,i,j;
size_t max=20;
if ( (res=initStack(&stack, max))!=NO_ERROR ) {
printf("Error: %d\n",res);
return res;
}
//Fill the stack;
printf("Pushing: ");
i=0;
while(mayPush(&stack)) {
push(&stack,++i);
printf("%d ",i);
}
puts("");
//Try to push another element into the stack
res=push(&stack,i);
if (res!=NO_ERROR) {
printf("Push error: %d\n",res);
}
//Read all the stack
printf("Popping: ");
while(mayPop(&stack)) {
printf("%d ",pop2(&stack));
}
puts("");
//Try to pop another element into the stack form 1
res=pop(&stack,&i);
if (res!=NO_ERROR) {
printf("Pop error: %d\n",res);
}
//Try to pop another element into the stack form 2
i=pop2(&stack);
res=getError(&stack);
if (res!=NO_ERROR) {
printf("Pop error: %d\n",res);
}
//Fill an half of the stack
printf("Pushing: ");
for(i=1;i<=(int)max/2;i++) {
push(&stack,i);
printf("%d ",i);
}
puts("");
//Get some value from the stack
printf("Popping: ");
for(i=1;i<=(int)max/4;i++) {
printf("%d ",pop2(&stack));
}
puts("");
//Put some value in the stack (also generates errors)
for (j=0;j<3;j++) {
printf("Pushing: ");
for(i=1;i<=(int)max/3;i++) {
printf("%d ",i*3+j);
if ( (res=push(&stack,i*3+j))!=NO_ERROR ) {
printf("Push error: %d\n",res);
}
}
puts("");
}
//Get some value from the stack (also generates errors)
printf("Popping: ");
for(i=0;i<(int)max+2;i++) {
if ( (res=pop(&stack,&j))!=NO_ERROR ) {
printf("\nPop error: %d",res);
} else {
printf("%d ",j);
}
}
puts("");
puts("Deallocating the stack!");
freeStack(&stack);
printf("Pushing: ");
if ( (res=push(&stack,415))!=NO_ERROR ) {
printf("Push error: %d\n",res);
}
puts("Re-Deallocating the stack!");
if ( (freeStack(&stack))!=NO_ERROR ) {
printf("freeStack Error: %d\n",res);
}
return 0;
}
Firstly, so glad to see that you didn't cast the result of malloc.
Your
int
main(int argc, char **argv){
Be assured that it doesn't have any side effect on the code behaviour, but as I have seen most of the people doing it this way, improves readability. should be,
int main(int argc, char **argv){
This
S = malloc(10*sizeof(int));
S = NULL;
should be
S = NULL;
S = malloc(10*sizeof(int));
I don't comprehend what you are trying through this:
for(i = 0; S[i]; i++)
May be this should be something like,
for(i = 0; i < MAX_LENGTH; i++) //MAX_LENGTH should be some integer #defined somewhere in the code
Apart from these obvious mistakes, you can actually think about adding a check to ensure that, in the while loop in the function push() you don't overrun the value of size than what s can accommodate.
Then, instead of doing
if (S == NULL){
S[0] = n;
}
in push(), I would have preferred checking if the memory is allocated after malloc. So,
S = malloc(10*sizeof(int));
if (S == NULL)
{
//Error handling supposed to be done if no memory is allocated
}
This should do what you are looking forward to:
#include <stdio.h>
#include <stdlib.h>
typedef int data_t;
int top;
void push(data_t,int*);
int pop(int*);
int
main(int argc, char **argv)
{
int *S = NULL, i;
top = -1;
S = malloc(10*sizeof(int));
if(S == NULL)
{
printf("Memory Allocation failed");
//other error handling implementation if any
}
push(1,S);
push(2,S);
push(3,S);
for(i = 0; i <= top; i++){
printf("%d\n",S[i]);
}
printf("\n Popping:\n");
pop(S);
for(i = 0; i <= top; i++){
printf("%d\n",S[i]);
}
return 0;
}
void
push(data_t n,int *S )
{
//Check if Stack is full
if (top == 10)
{
printf("Stack Full");
//other implementation
}
else
{
++top;
S[top] = n;
}
}
int
pop(int *S)
{
//Check if Stack is empty
if (top == -1)
{
printf("Stack Empty");
//other implementation
}
else
{
return S[top--];
}
}
The code is untested as I am travelling.

Allocate memory dynamically of a vector of struct

I can't access my pointer by index notation in main function. The way I'm passing the pointer as paramter to the functions, is that right ? I tried without the & and It didnt work neither. Here is my code:
//My Struct
typedef struct{
int a;
double d;
char nome[20];
}contas;
//Function to allocate memory
void alloca_vetor(contas *acc, int linhas){
acc = malloc(linhas * sizeof(contas));
if(acc == NULL){
printf("ERRO AO ALOCAR MEMORIA\n");
exit(0);
}
printf("ALLOCATION SUCCESSFUL");
}
//Function to fill the vector
void fill_vetor(contas *acc, int linhas){
int i,a;
for(i=0; i< linhas; i++){
acc[i].a = i;
}
printf("FILL SUCCESSFUL !\n");
for(i=0; i< linhas; i++){
printf("%i\n", acc[i].a);
}
}
int main()
{
int i, num_linhas = 5;
contas *array;
alloca_vetor(&array, num_linhas);
fill_vetor(&array, num_linhas);
// ERROR HAPPENS HERE - Segmentation Fault
for(i=0; i < num_linhas; i++){
printf("%i\n", array[0].a);
}
free(array);
return 0;
}
Rewrite function alloca_vetor the following way
void alloca_vetor( contas **acc, int linhas ){
*acc = malloc(linhas * sizeof(contas));
if(*acc == NULL){
printf("ERRO AO ALOCAR MEMORIA\n");
exit(0);
}
printf("ALLOCATION SUCCESSFUL");
}
And call function fill_vetor like
fill_vetor(array, num_linhas);

Memory Allocation for a Dynamic List of Strings

I'm writing a program in C that's supposed to take several string of text from a file and put them inside a dynamic list.
For some reason (probably memory allocation) I get this error every time I try to put more than fifteen strings into the structure:
*** glibc detected *** ./driver: realloc(): invalid next size: 0x000000000241e250 ***
The code is as follows:
dlist.h
struct dlist
{
int size;
int maxSize;
char item[1][1024];
};
#define INITSIZE 6
#define INCRSIZE 9
#define DLISTSIZE(n) ((size_t)(sizeof(struct dlist) + (n*1024)))
struct dlist *initDlist(int num);
int insDlist(char data[], struct dlist **p);
void printDlist(struct dlist *p);
void debugDlist(struct dlist *p);
int stringCmp(const void *a, const void *b);
dlist.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dlist.h"
struct dlist *initDlist(int num)
{
struct dlist *p;
p = malloc( DLISTSIZE(num) );
if(p == NULL)
return(NULL);
p->size = 0;
p->maxSize = num;
return(p);
}
int insDlist(char data[], struct dlist **p)
{
struct dlist *q;
//printf(" DEBUG: Checking remaining memory.\n");
if ((*p)->size == (*p)->maxSize)
{
//printf(" DEBUG: Out of memory, reallocating now...\n");
q = realloc(*p, DLISTSIZE((*p)->maxSize + INCRSIZE));
if(q == NULL)
return(-1);
q->maxSize += INCRSIZE;
*p = q;
}
//printf(" DEBUG: Space available.\n");
int i;
(*p)->size++;
//adding data to the list
for(i = 0; i < 1024; i++)
(*p)->item[(*p)->size][i] = data[i];
return(0);
}
void printDlist(struct dlist *p)
{
int i;
for(i = 0; i <= p->size; i++)
printf("%s", p->item[i]);
}
void debugDlist(struct dlist *p)
{
int i;
fprintf(stderr, "\nDynamic List Debug Data\n\n");
fprintf(stderr, " size = %d\n", p->size);
fprintf(stderr, " maxSize = %d\n", p->maxSize);
for(i = 0; i <= p->maxSize; i++)
fprintf(stderr, " %s\n", p->item[i]);
}
int stringCmp(const void* a, const void* b)
{
const char *ia = (const char *)a;
const char *ib = (const char *)b;
return strncmp(ia, ib, 1023);
}
driver.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "dlist.h"
int main(int argc, char *argv[])
{
printf("\n");
FILE *fp;
char text[1024];
//check the command line
if(argc != 2)
{
fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
return(-1);
}
//open file given on command line
fp = fopen(argv[1], "r");
if(fp == NULL)
{
perror(argv[1]);
return(-1);
}
//initialize the dynamic list
struct dlist *p;
p = initDlist(INITSIZE);
if(p == NULL)
{
perror("Unable to malloc dlist");
return(-1);
}
//read each line then store it in the dynamic list
while(fgets(text, 1024, fp) != NULL)
{
//printf("DEBUG: Preparing to insert data.\n");
if( insDlist(text,&p) == -1)
{
perror("Unable to realloc dlist");
return(-1);
}
//printf("DEBUG: Data inserted successfully.\n\n");
}
//debugDlist(p);
printDlist(p);
//printf("\nNow sorting...\n\n");
//qsort(&(p->item), p->size, 1, stringCmp);
//debugDlist(p);
//printDlist(p);
return(0);
}
Any help is appreciated, thanks in advance.
The issue is almost definitely that you are incrementing the size of the list before copying the data:
(*p)->size++;
//adding data to the list
for(i = 0; i < 1024; i++)
(*p)->item[(*p)->size][i] = data[i];
You should reorder these statements:
//adding data to the list
for(i = 0; i < 1024; i++)
(*p)->item[(*p)->size][i] = data[i];
(*p)->size++;
Also, if you're allowed, the following is equivalent:
// adding data to the list
memcpy( (*p)->item[(*p)->size],
data,
1024 );
(*p)->size++;
To elaborate, the indices are zero-based. As an example, when you allocate 6 arrays, you copy into the indexes [1], [2], [3], [4], [5], and [6].
You want to copy into indexes [0], [1], ... [5].
Additionally, the reason that you see the error only after allocating some specific number has to do with the heap allocator.

Resources