0

I'm trying to create two lists, pros and cons and then print them. But I can't figure out what am I doing wrong.

I tried to debug the program with gdb online and I found out that the error is in function fgets().

#include <stdio.h>
#include <string.h>
typedef struct list{
    char ** reason;

} list;
void printMenu();
void printList(list * myList, int len1);


int main(void)
{
    int keepGoing = 0;
    int choice = 0;
    int i = 0;
    int j = 0;
    list * pros;
    list * cons;

    while (!keepGoing){

        printMenu(); 
        scanf("%d", &choice);

        pros = (list*)malloc(sizeof(list));
        cons = (list*)malloc(sizeof(list));
        switch (choice){
        case 1:
            i++;
            printf("Enter a reason to add to list PRO: ");
            pros = (list*)realloc(pros, i*sizeof(list));
            fgets(pros->reason[i], 50, stdin);
            pros->reason[strcspn(pros->reason[i], "\n")] = 0;
            break;
        case 2:
            j++;
            cons = (list*)realloc(cons->reason, j*sizeof(list));
            printf("Enter a reason to add to list CON: ");
            fgets(cons->reason[j], 50, stdin);
            cons->reason[strcspn(cons->reason[j], "\n")] = 0;
            break;
        case 3:
            printf("PROS:\n");
            printList(pros, i);
            printf("CONS:\n");
            printList(cons, j);

            break;
        case 4:
            keepGoing = 1;
            break;
        default:
            printf("Invalid value.");
            keepGoing = 1;
        }
    }

    free(pros);
    free(cons);

    getchar();
    return 0;
}

void printList(list * reasons, int len1){
    int i = 0;
    for (i = 0; i < len1; i++){
        printf("%s\n", reasons->reason[i]);
    }
}
void printMenu(){
    printf("Choose option:\n");
    printf("1 - Add PRO reason\n");
    printf("2 - Add CON reason\n");
    printf("3 - Print reasons\n");
    printf("4 - Exit\n");
}
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
Saga
  • 67
  • 1
  • 8
  • what is `count`? – Sourav Ghosh May 04 '17 at 07:53
  • [Please see this discussion on why not to cast the return value of `malloc()` and family in `C`.](http://stackoverflow.com/q/605845/2173917). – Sourav Ghosh May 04 '17 at 07:54
  • Well you `malloc` each loop the struct ... therefore erase the data each loop. Also you use `realloc` on something that never been allocate before [even if `realloc` will allocate the size, you should use `malloc`]. Alos `keepGoing` is always equals to 1; you've got an endless loop; and then you will never free it [you forget to free the list] – kaldoran May 04 '17 at 07:57
  • 1
    `while (!keepGoing)`? Really? How do you read that? The only way I know is "while not keep going (: keep going)". That makes no sense at all. – unwind May 04 '17 at 08:13
  • There are many issues, your `struct list` declaration is fishy and your program is overly complicated. Maybe you should show us the expected behaviour of your program. – Jabberwocky May 04 '17 at 08:29
  • Ok. I wan't to create a program which will be taking from the user each time(until he wants to exit) pro reason and con reason and then print him all reasons. And I have to use the function malloc(). – Saga May 04 '17 at 08:37
  • @MichaelWalz ^^^^ – Saga May 04 '17 at 09:49
  • @Saga you should put that into your question by editing it. – Jabberwocky May 04 '17 at 09:50
  • @MichaelWalz Thanks. – Saga May 04 '17 at 09:53

3 Answers3

2

There is no need to allocate these dynamically: list * pros; list * cons;. Code like pros = (list*)realloc(pros, i*sizeof(list)); doesn't make any sense.

Instead, declare them as plain variables. list pros.

What you instead need to allocate dynamically is the member pros.reason. You need to allocate an array of pointers that it points to, and then you need to allocate the individual arrays.

Lundin
  • 195,001
  • 40
  • 254
  • 396
1

You have a problem in

  fgets(pros->reason[i], 50, stdin);

as the memory you want to use is not valid. pros->reason does not point to a valid memory, so you cannot dereference it, this causes undefined behavior.

Before you can index-into pros->reason, you need to make pros->reason point to a valid memory location.

After that, you need to make pros->reason[i]s also to point to valid memory if you want them to be used as the destination of fgets().


Apart from this issue, you have another issue which makes this code nonsense, that is calling malloc() on every iteration of the loop. You need to call malloc() only once, to get a pointer (to memory) allocated by memory allocator function and then, use realloc() inside the loop to adjust that to the required memory.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • There is lot more problem then that :x (alloc list at each loop, realloc something that should be alloc first ( even if realloc will create the memory)) – kaldoran May 04 '17 at 07:56
  • You mean something like this? pros->reason = (char**)malloc(sizeof(char*)*SIZE); – Saga May 04 '17 at 08:33
  • @Saga something along that line, yes. – Sourav Ghosh May 04 '17 at 09:00
  • I tried to do it, however there's a new error exactly in this line of code. "Program received signal SIGSEGV, Segmentation fault." – Saga May 04 '17 at 09:13
  • @Saga yes, probably because `pros->reason[i]` is still pointing to invalid memory, check the last part of my answer. – Sourav Ghosh May 04 '17 at 09:14
  • First I have to allocate memory for pros->reason[i] and then to pros->reason? – Saga May 04 '17 at 09:23
  • @Saga nopes, the other way. – Sourav Ghosh May 04 '17 at 09:37
  • First allocate memory pros->reason and then to pros->reason[i]. I started doing it and it stopped in this line: pros->reason =(char**)malloc(sizeof(char*)*SIZE); Can you please write only where to write the 2 lines? As I understood, I should write this line of code outside the while loop and inside the while loop allocate memory for pros->reason[i] – Saga May 04 '17 at 09:43
  • @SouravGhosh ^^ – Saga May 04 '17 at 10:49
  • @Saga OK, i'll do, gimme some time please. – Sourav Ghosh May 04 '17 at 10:57
0

There are many issues. Previous comments and answers do still apply.

Here is a clean solution.

  • The list structure is now self contained, no need to track the number of strings in separate variables
  • added selfcontained AddString function
  • no more unnecessary mallocs
  • all allocated memory is freed correctly
  • some logic errors removed (inverted logic of keepGoing)

There is still room for improvement. Especially there is no error checking for the memory allocation functions.


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct list {
  int size;       // number of strings
  int chunksize;  // current of chunk
  char ** reason;
} list;

void printMenu();
void printList(list * reasons);
void freeList(list * l);
void AddString(list *l, const char *string);

int main(void)
{
  int keepGoing = 1;
  int choice = 0;

  list pros = { 0 };  // = {0} initializes all fields to 0
  list cons = { 0 };

  while (keepGoing) {

    printMenu();
    scanf("%d", &choice);

    char input[50];
    fgets(input, sizeof(input), stdin);  // absorb \n from scanf

    switch (choice) {
    case 1:
      printf("Enter a reason to add to list PRO: ");
      fgets(input, sizeof(input), stdin);
      AddString(&pros, input);    // Add string to pros
      break;
    case 2:
      printf("Enter a reason to add to list CONS: ");
      fgets(input, sizeof(input), stdin);
      AddString(&cons, input);    // Add string to cons
      break;
    case 3:
      printf("PROS:\n");
      printList(&pros);
      printf("CONS:\n");
      printList(&cons);
      break;
    case 4:
      keepGoing = 0;
      break;
    default:
      printf("Invalid value.");
      keepGoing = 1;
    }
  }

  freeList(&pros);
  freeList(&cons);

  getchar();
  return 0;
}


#define CHUNKSIZE 10

void AddString(list *l, const char *string)
{
  if (l->size == l->chunksize)
  {
    // resize the reason pointer every CHUNKSIZE entries
    l->chunksize = (l->chunksize + CHUNKSIZE);

    // Initially l->reason is NULL and it's OK to realloc a NULL pointer
    l->reason = realloc(l->reason, sizeof(char**) * l->chunksize);
  }

  // allocate memory for string (+1 for NUL terminator)
  l->reason[l->size] = malloc(strlen(string) + 1);

  // copy the string to newly allocated memory
  strcpy(l->reason[l->size], string);

  // increase number of strings
  l->size++;
}

void freeList(list * l) {
  for (int i = 0; i < l->size; i++) {
    // free string
    free(l->reason[i]);
  }

  // free the list of pointers
  free(l->reason);
}

void printList(list * l) {
  for (int i = 0; i < l->size; i++) {
    printf("%s\n", l->reason[i]);
  }
}

void printMenu() {
  printf("Choose option:\n");
  printf("1 - Add PRO reason\n");
  printf("2 - Add CON reason\n");
  printf("3 - Print reasons\n");
  printf("4 - Exit\n");
}
Jabberwocky
  • 48,281
  • 17
  • 65
  • 115