Thread: Help getchar() problem

  1. #1
    Registered User
    Join Date
    Nov 2009
    Location
    Italy
    Posts
    65

    Question Help getchar() problem

    Hi, I'm doing this exercise that should print a list containing the differences between two integers x and y, here the code:

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    struct node {
    	int diff;
    	struct node* next;
    };
    typedef struct node Node;
    
    void Push(Node** headRef, int data)
    {
    	Node* newNode = malloc(sizeof(Node));	
    	newNode->diff = data;
    	newNode->next = *headRef;
    	*headRef = newNode;	
    }
    void printList(Node** headRef)
    {
    	Node* current = *headRef;
    	while(current!=NULL) {
    		printf("%d\n", current->diff);
    		current = current->next;
    	}
    }
    int main()
    {
    	int x, y, diff;
    	Node* head = NULL;
    	Node* tail;
    	
    	
    	scanf("%d%d", &x, &y);
    	diff = y-x;
    	Push(&head, diff);
    	tail = head;
    
    	while(getchar()!=EOF) {        // <---- getchar() function..
    		scanf("%d%d", &x, &y);
    		diff = y-x;
    		Push(&(tail->next), diff);
    		tail = tail->next;
    	}
    	printList(&head);
    	
    	return 0;
    }
    The problem is that if I want to break the loop I have to enter the EOF character (ctrl+d) 2 times while it should be entered only once, and the last element of the list gets printed twice, I think there are some issues with the getchar() function but I can't figure out what.. any help? thanks

  2. #2
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Yes, there are some complications with both getchar() and scanf() that you haven't addressed. Read this, it'll take you 10 minutes:

    STDIN pitfalls
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  3. #3
    Registered User
    Join Date
    Nov 2009
    Location
    Italy
    Posts
    65
    Thanks, i read that and I came up with this:

    Code:
    int main()
    {
    	int x, y;
    	int diff;
    	Node* head = NULL;
    	Node* tail;
    	
    	
    	scanf("%d%d", &x, &y);
    	diff = y-x;
    	Push(&head, diff);
    	tail = head;
    	
    	
    	while(getchar()!=EOF) {
    		scanf("%d%d", &x, &y);
    		
                    while(getchar()!='\n');   
    
                    diff = y-x;
    		Push(&(tail->next), diff);
    		tail = tail->next;
    		
    	//	while(getchar()!='\n');     // .......
    	}
    	printList(&head);
    	
    	return 0;
    }
    I used the getchar()!='\n' to gobble all the characters left in the input buffer, but still a problem remains, in fact it works fine if I enter a single line while it doesn't work within the while(getchar()!=EOF) loop, I put getchar()!='\n' at the bottom of it so that at any iteration it should "free" the input buffer but it prints the second number(y) twice, I also tried to put it right after the scanf function which i think is a better idea since the result if fine except for the fact the instead of the difference between the 2 numbers it prints the second number , so i monitored the x and y values at any iteration and found out that the x doesn't get any value, for example if I enter x=10 and y=14 the output is 14 since it does 14-0 because x is always 0 instead of the value I assigned to it(i.e 10).. any help would be appreciate.. thanks!!
    Last edited by rob90; 01-28-2010 at 09:37 AM.

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Code:
    char buff[BUFSIZ];
    while ( fgets( buff, BUFSIZ, stdin ) != NULL ) {
        if ( sscanf( buff, "%d%d", &x, &y) == 2 ) {
            diff = y-x;
            Push(&(tail->next), diff);
            tail = tail->next;
        } else {
            // huh, that wasn't two numbers
        }
    }
    If you want sanity, use fgets() for ALL input.
    Then use whatever you like for parsing the buffer once it is in memory.

    scanf() is barely usable even when the user can be trusted to type everything perfectly. If they don't, then error recovery is simply a PITA.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by Salem View Post
    scanf() is barely usable even when the user can be trusted to type everything perfectly. If they don't, then error recovery is simply a PITA.
    That isn't scanf, it's sscanf(). The OP is using fgets for the input then validating and extracting it with sscanf(), which is a wise strategy.

    [edit]sorry, I thought you took that from the previous post
    Last edited by MK27; 01-28-2010 at 10:18 AM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  6. #6
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by rob90 View Post
    I put getchar()!='\n' at the bottom of it so that at any iteration it should "free" the input buffer but it prints the second number(y) twice,
    That won't clean the input buffer. It will explicitly do what you asked for -- leave a newline in the buffer.

    You should try what Salem is recommending, there is another example at the bottom of the link I posted earlier. The "gobbling getchar" (while...!=\n) is a sort of lazy/mediocre approach that will work in some situations, but the fgets()/sscanf() approach is bulletproof.
    Last edited by MK27; 01-28-2010 at 10:20 AM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  7. #7
    Registered User
    Join Date
    Nov 2009
    Location
    Italy
    Posts
    65
    Thanks guys, I followed the suggestion of Salem and it seems to run fine now:

    Code:
    int main()
    {
    	int x, y;
    	int diff;
    	Node* head = NULL;
    	Node* tail;
    	char* str = malloc(sizeof(char)*BUFSIZE);
    	
    	
    	scanf("%d%d", &x, &y);
    	diff = y-x;
    	Push(&head, diff);
    	tail = head;
    
    	while(getchar()!='\n');
    	
    	while(fgets(str, BUFSIZE, stdin) != NULL) {
    		sscanf(str, "%d%d", &x, &y);
    		diff = y-x;
    		Push(&(tail->next), diff);
    		tail = tail->next;
    	}
    		
    	printList(&head);
    	free(str);
    	
    	return 0;
    }

  8. #8
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Look, you do almost the exact same thing twice:
    Code:
    	scanf("%d%d", &x, &y);
    	diff = y-x;
    	Push(&head, diff);
    	tail = head;
    
    	while(getchar()!='\n');
    	
    	while(fgets(str, BUFSIZE, stdin) != NULL) {
    		sscanf(str, "%d%d", &x, &y);
    		diff = y-x;
    		Push(&(tail->next), diff);
    		tail = tail->next;
    	}
    The whole point of having functions is that you don't have to duplicate code. There are endless reasons to NOT DUPLICATE CODE FOR NO REASON, and absolute none for doing it.

    Thus, you write a function to get two number and return diff. This is the example at the end of the page I posted:
    Code:
    int getNumber (int *num) {
    	char buffer[1024];
    	fgets(buffer,1024,stdin);
    	return sscanf(buffer, "%d", num);
    }
    Do you see how incredibly simple it would be to modify that to return that "diff" value? That's what functions are for!
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Laptop Problem
    By Boomba in forum Tech Board
    Replies: 1
    Last Post: 03-07-2006, 06:24 PM
  2. getchar() problem
    By jlharrison in forum C Programming
    Replies: 6
    Last Post: 01-25-2006, 02:49 PM
  3. problem with parser code
    By ssharish2005 in forum C Programming
    Replies: 2
    Last Post: 12-02-2005, 07:38 AM
  4. Replies: 5
    Last Post: 11-07-2005, 11:34 PM