1

I'm having a problem with my gdb debugger and every time I try to run the program, the debugger gives out the following error at the line where I use the "fgets"(): _IO_fgets (buf=0x7fffffffe330 "P\343\377\377\377\177", n=2, fp=0x0)

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

typedef struct _node {
   int value ;
   struct _node * next ;
} node ;

void print_avg(node * head, int n)
{
    int sum = 0 , i = 0;
    node * p = head ;
    for (i = 0 ; i < n ; i++) {
            sum += p->value ;
            p = p->next ;
    }
    printf("%f\n", ((float)sum / (float)n)) ;
}

int get_nums(node ** head)
{
    int n = 1 ;
    char line[4]  ;

    while (fgets(line, sizeof(line), stdin) != NULL) {
            //strtok(line, "\n") ;

            node * curr ;
            curr = (node *) malloc(sizeof(node)) ;
            curr->value = atoi(line) ;
            curr->next = *head ;
            *head = curr ;

            n++ ;
    }
    return n ;
}


int main()
{
    int n ;
    node * head = NULL;

    n = get_nums(&head) ;
    print_avg(head, n) ;
    return 0 ;
}

I have no clue what is wrong with my fgets(). Does anybody have an idea?

MasterGL
  • 111
  • 10
  • 2
    [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 09 '17 at 11:47
  • Maybe run the code with something like valgrind? That'll show you where you're trashing the memory. – Chris Turner May 09 '17 at 11:50
  • Yup. I fixed the overwriting head in every iteration issue with a double pointer(I edited the post), but the question is why do I see that sort of error with fgets()?? Because I do not see any logical or syntax errors in that line. – MasterGL May 09 '17 at 12:14
  • @MasterGL your usage of `fgets` looks correct to me. Read my answer below. If `fgets` still segfaults, try `char line[100];` and report if the problem goes away. And please check if the code you debug is the code you compiled, and check if the code you compiled is the code you show here, we've seen this kind of error too often here. – Jabberwocky May 09 '17 at 12:28
  • "*n=2*" is strange, as your code defines `line` to be of size 4. – alk May 09 '17 at 12:56

2 Answers2

1

Your usage of fgets looks correct to me, but there is another problem in your code: n is off by one.

Replace

int n = 1;

by

int n = 0;

because initially the list contains 0 elements, not 1 element.

But anyway this is better:

You should use this this in your for loop.

for (node * p = head; p != NULL; p = p->next)

The list is terminated by a NULL pointer in the next field. So you should check for this condition instead of testing for the number of elements.

Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
  • Michael I've done exactly what you told me to do by changing the index value to 100 in char line[100]. But the fgets error is still present. It's still showing the same error message. What do you think is the real problem here? – MasterGL May 09 '17 at 14:00
  • @MasterGL I have no idea what could be wrong. The way you use `fgets` is correct. What's your platform (operating system, compiler, IDE, versions of all that etc.)? – Jabberwocky May 09 '17 at 14:06
  • I just used nothing but gcc compiler with to compile the file and I'm currently using the gdb debugger for debugging. I set the get_num() line in the main function as the first breakpoint and gdb always gives error when I go to the fgets() in get_num – MasterGL May 09 '17 at 14:07
  • Which versions, which operation system (Linux, Windows 7,8,10.... other). Give all details. – Jabberwocky May 09 '17 at 14:08
  • Using Windows 10 but I'm running the program on an Ubuntu instance. I'm just using it as a code server of my own – MasterGL May 09 '17 at 14:10
  • @MasterGL try this small program and report if it works: `int main(void) { char line[10]; while (fgets(line, sizeof(line), stdin)) { puts(line); } return 0; }` – Jabberwocky May 09 '17 at 14:15
  • This one runs without an issue. It's printing every value I input to the program. – MasterGL May 09 '17 at 14:19
  • Hmmm.. weird. It compiles and runs without a problem. I'm trying it on both the Visual studio and gcc and it all works fine. But when I try it on gdb debugger, it tells me that there is an issue with fgets(). Same problem with the one above. – MasterGL May 09 '17 at 14:20
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/143792/discussion-between-michael-walz-and-mastergl). – Jabberwocky May 09 '17 at 14:21
0

using Valgrind I get

Access not within mapped region at address 0x0 at 0x4006D8: print_avg (main.c:16)

The problem is the instruction sum += p->value if p is NULL.

p is NULL because head is NULL because int get_nums(node * head) creates a copy of the pointer to head so when yo do head = curr ;, you're actually storing the value of the pointer into a copy so when you return to main the first head pointer is still NULL and you have a memory leak since you cannot free the memory you allocated (since the pointer is now lost).

here is the real working code you need

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

typedef struct _node {
  int value ;
  struct _node * next ;
 node ;

void print_avg(node ** head, int n)

   int sum = 0 , i = 0;
   node *p = *head ;
   //better check p value here to avoid segmentation fault
   for (i = 0 ; i < n && p!=NULL; i++) {
           sum += p->value ;
           p = (*head)->next ;
           free(*head);
           *head = p;

   }
   printf("%f\n", ((float)sum / (float)n)) ;


int get_nums(node ** head)

   int n = 0 ;
   char line[4]  ;

   while (fgets(line, sizeof(line), stdin)) {
           //strtok(line, "\n") ;

           node * curr ;
           curr = (node *) malloc(sizeof(node)) ;
           curr->value = strtol(line,NULL,10) ;
           curr->next = *head ;
           *head = curr ;

           n++ ;
   }
   return n ;



int main()

   int n ;
   node * head = NULL;
   //here we pass the address of head pointer so that the function will be able to set it
   n = get_nums(&head) ;
   //here we pass the address of head pointer so that the function will be able to free your list of pointers
   print_avg(&head, n) ;
   return 0 ;

More over n must start from 0 in your int get_nums(node ** head) function

Regards!

@Walz In this case you need to pass a pointer to a pointer because otherwise IF you free the nodes inside print function, head pointer from outside the function would not point to the right head of your list after print_avg function. For now let's say I have a pointer A which points to MY_LIST then I copy pointer A inside print_avg to handle MY_LIST, as I free the nodes inside MY_LIST and I return from print_avg ponter A is not changed! So it will point to the previous head (which has been freed) so if I try to access to it via pointer A a segmentation fault just around the corner.

You should always free allocated resources when you are sure you don't need them any more in your program. Since we are accessing the list, the most efficient way to free the list is freeing it node by node as you have used the value to calculate the avg BUT you can always free them later, maybe in another function.

Finally since your main ends there freeing resources is not so important here but it should be like an habit for you to free allocated resources before you loose the pointer to them. Imagine you are writing a multi threaded server and you loose even one byte per connection. Sooner or later you are going out of memory.

Regards!

@MasterGL I don't know if this could be your problem but if I ran the debugger in Eclipse and if I do "step into" when I get to fgets instruction I receive some errors too (maybe the debugger doesn't have fgets source code to show). I did with "Step over" and I only used "Step Into" to enter into my functions. It works well

Whitefield
  • 31
  • 6
  • Not sure if freeing the nodes in `print_avg` is a good idea. And why passing a pointer to a pointer to `print_avg`? – Jabberwocky May 09 '17 at 13:19
  • Getting this sort of error with your code Whitefield. Not sure if this code is solving the problem with fgets() issue. But thanks for the help! _IO_fgets (buf=0x7fffffffe330 "P\343\377\377\377\177", n=-136403616, fp=0x0) at iofgets.c:40 – MasterGL May 09 '17 at 14:06
  • Hi MasterGL I think that maybe you could have a problem with a library. I must say that I ran your original code and found a couple of programming issues (the worst is the memory leak as you allocate then set and then loose the pointer to a memory area) as I described, but I couldn’t reproduce your error as Valgrind (which I advice to you as a debugger) just found a segmentation error due to a missing check in your `for` loop and to a wrong initialization of `n`. Actually running it on debugger gives no errors and no memory leak. – Whitefield May 11 '17 at 11:45