Solved

Copying from stdin to malloc() 'd structs

Posted on 2003-12-03
23
1,044 Views
Last Modified: 2010-04-15
Hi

I have defined a struct in my program

struct node {
      int nodetype; /*1 = question, 2 = object*/
        int nodenumber;
      char object[25];
      char question[25];
      struct node *YES_ptr;
      struct node *NO_ptr;
      };

and in my main() i have 2 pointers to structs, and I have malloc() each of them memory

struct node *node_1, *node_2;


      
      node_1 = (struct node*)malloc (sizeof(struct node));
      node_2 = (struct node*)malloc (sizeof(struct node));


I have then set up a buffer and 2 pointers to chars
      
        char buffer[255];
      char *new_object, *new_question;


I am then trying to copy into the structs input from the command line and store it in the appropriate parts of the structs.

        printf("Please Enter An Object \n");
      new_object = fgets(buffer, 255, stdin);
      printf("You have entered: %s\n", node_1->object);
      sscanf ( buffer, "%[^\n]s", node_1->object );
      
      printf("Please Enter A Question \n");            
      new_object = fgets(buffer, 255, stdin);      
      sscanf ( buffer, "%[^\n]s", node_1->question );            
      printf("You Question was: %s\n", node_1->question);


For some reason when I run the program it skips straight to the
      sscanf ( buffer, "%[^\n]s", node_1->question );            
part and doesnt let me input anything for the object.

Another question I have is what should I do with these structs after I have filled them,
Will they automatically stay in memory?
Do I have to give them names so I can refer to them later?
Do I need to free up the memory after I exit my prog?

Thanks

0
Comment
Question by:welsh_boy
  • 7
  • 6
  • 4
  • +4
23 Comments
 
LVL 45

Expert Comment

by:Kdo
ID: 9870487

Something else may be occurring before you get to this point.

Try "fflush (stdin);" immediately before the fgets();

Any memory assigned to your program belongs to your program.  When the program ends, all memory used by the program goes back to the operating system.  If you don't need the objects any more, you can free() them, but if the program is just going to end anyway it's easier and more efficient to let the system just take back the memory when the program ends.

You are responsible for keeping a pointer to all objects that you malloc().  Especially if you want to use it elsewhere in the program.

SomePointer = malloc (100);
SomePointer = malloc (200);

This is perfectly legal.  But the first 100 characters are "lost" to the program because you over-wrote SomePointer and now have no way to reference it.  The memory will come back when the program ends, but it's lost to the program.

If you didn't want the first 100 characters any longer, you should free() them before assigning a new buffer.  Or, if you want the same buffer to be a different size, realloc() will assign you another buffer AND copy what was in the original buffer to the new one.

SomePointer = malloc (100);
SomePointer = realloc (200);

The original 100 bytes have been given back to the system and a new 200 byte buffer has been assigned.  The first 100 bytes of the buffer have also been copied to the new buffer.


Hope this clears things up for you,
Kent
0
 

Author Comment

by:welsh_boy
ID: 9870596
Thanks that has cleared up some of the issues I had with memory allocation, but I have tried
fflush(stdin); in different parts of my code and it still skips the first fgets();

I get
 Please Enter An Object
You have entered:
Please Enter A Question

I dont get the chance to enter something for the object!!
0
 
LVL 45

Expert Comment

by:Kdo
ID: 9871842

That's really bizarre.  Can you post the entire code?

Kent
0
 
LVL 5

Assisted Solution

by:shajithchandran
shajithchandran earned 50 total points
ID: 9872105
I am sure u r using scanf before the first fgets(). If yes then replace those scanfs with fgets or place getch() just before first fgets().
The problem here is that the scanf doesn't read \n. So if there is a scanf before fgets when u enter some data and press enter, the last enter stays in the keyboard buffer and this is read by ur first fgets and hence it doesn't wait there.
And don't use fflush(). This is meant only to clear an output stream not input. It is a misconception.

Try not mixing fgets and scanf. Use only one type to read data.
Any way post ur code if this doesn't solve ur problem.

Bye
Shaj
0
 
LVL 24

Assisted Solution

by:fridom
fridom earned 50 total points
ID: 9872531
You code is broken. what should  

printf("Please Enter An Object \n");
new_object = fgets(buffer, 255, stdin);
printf("You have entered: %s\n", node_1->object);
 sscanf ( buffer, "%[^\n]s", node_1->object );
     

do? Where is node_1 filled?
What do you do with new_object?
You will have  a terrible time if the input in buffer is longer than 24.
I suggest you try out a simple program to understand how to use fgets and sscanf
I suggest following code (not tested)

static enum {BUF_SIZE = 255 };
char *srval = NULL;
char buf [BUF_SIZE];
printf("Give me a string "); fflush(stdout);
srval = fgets(buf, sizeof(buf), stdin);
if (! srval) { // error handling  };
printf("got %s", buf);


For the memory handling:
Some tips were given to you the simply base line is if you use a malloc somewhere there must be an matching free elsewhere. Getting that right is not trivial and you usage of C suggests that you are not all too familiar with it. You might consider using GC for your code.


Any tip recommanding using fflush(stdin) invokes undefined behaviour and should be omitted.

It would be very helpful to know what you really want to do and that you post code which one can use to compile. You should think about you problem and try to extract it from your code.

Your problem at the moment is getting input from the user. So solve that first after that you can solve the next one.

Regards
Friedrich









0
 
LVL 10

Assisted Solution

by:Sys_Prog
Sys_Prog earned 25 total points
ID: 9872681
Hi welsh_boy

To add,
1)   actually u do not need any local variables to get the char * data AND to read from stdin,
2)   u can use gets () instead of fgets()
3)   No need to use sscanf()


Y can directly get it in your structure components

Example

printf("Please Enter An Object \n");
gets(node_1->object);
printf("You have entered: %s\n", node_1->object);
     
printf("Please Enter A Question \n");          
gets(node_1->question );          
printf("You Question was: %s\n", node_1->question);

Also, u can also use scanf() instead of gets()

HTH
Amit
0
 
LVL 24

Expert Comment

by:fridom
ID: 9872832
Well I suggest to Amit to read a bit about C and see why using gets is a terrible idea.
Using scanf for interactive input is not an good idea either, but still better as using gets.

Friedrich
0
 

Author Comment

by:welsh_boy
ID: 9872924
ok guys thanks for all the help, will try out all the reccomendations
0
 

Author Comment

by:welsh_boy
ID: 9873087
       printf("Please Enter An Object \n");

      new_object = fgets(buffer, 255, stdin); //Read a string from the command line
      printf("You have entered: %s\n", node_1->object); //Print out the string
      sscanf ( buffer, "%[^\n]s", node_1->object );  //Store this string in node_1->object

      printf("Please Enter A Question \n");            
      new_question = fgets(buffer1, 255, stdin);      //Read a string from the command line
      sscanf ( buffer, "%[^\n]s", node_1->question );      //Store this in node_1->question
      printf("You Question was: %s\n", node_1->question);

At the moment the program skips the first sscanf and goes straight to asking for a question.
It stores the string passed to fgets() in node_1->question fine
0
 
LVL 8

Expert Comment

by:ssnkumar
ID: 9873794
If you post the complete code, then we can debug and see what is the problem!
0
 
LVL 45

Expert Comment

by:Kdo
ID: 9873933

Hey.  Wait a second... :)

Here's the first 4 lines that you posted:

       printf("Please Enter An Object \n");

     new_object = fgets(buffer, 255, stdin); //Read a string from the command line
     printf("You have entered: %s\n", node_1->object); //Print out the string
     sscanf ( buffer, "%[^\n]s", node_1->object );  //Store this string in node_1->object

If you'll notice, fgets() reads from stdin into an object called 'buffer'.  The following printf() echos back whatever is in node_1->object.  You don't set that value until the sscanf() in the next line!

Try swapping the printf() and sscanf() lines.


Kent
0
What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

 

Expert Comment

by:jayesh_j_patel
ID: 9874050
Hi,
I tried this code in visual c++. It works fine. What I found is you are printing value of node_1->object before fetting initialized. My question is which compiler you are using?
Jayesh
0
 

Author Comment

by:welsh_boy
ID: 9874542
My whole code is  as follows.

I have hard coded one node (A dog)
When you play the game it asks you are you thinking of a Dog
If the answer is no then it creates a new node and enters the new object, then it creates another new node to enter a question to distinguish between the new object and the original Dog.

#include <stdio.h>

struct node {
      int nodetype; /*1 = question, 2 = object*/
        int nodenumber;
      char object[25];
      char question[25];
      struct node *YES_ptr;
      struct node *NO_ptr;
      };

int main() {
 
      struct node *node_1,  *current_node, *node_2;
      
      /* HARD CODE AN OBJECT NODE */
      struct node dog;
      dog.nodetype = 2;
        dog.nodenumber = 0;
        dog.YES_ptr = NULL;
        dog.NO_ptr = NULL;
        strcpy(dog.object, "Dog");

 
      char buffer[255], buffer1[255];
      char *new_object1;
      
      node_1 = (struct node*)malloc (sizeof(struct node));
      node_2 = (struct node*)malloc (sizeof(struct node));      

      char    user_input;
      char *new_object, *new_question;
      
      current_node= &dog; //Set the current node to Dog

//Outer loop for game
      while( 1) {
//Inner loop for  questions
        while (1 ){
          if (current_node->nodetype == 2) { //Object Node
      printf("Are you thinking of a %s?",current_node->object);
            scanf("  %c", &user_input );
            user_input = toupper( user_input );
            if(user_input == 'Y'){
            printf("I got it right\n");
            break; //Break out of the loop
            }

            if(user_input == 'N'){
            printf("You beat me\n");
            printf("What where you thinking?\n ");

//Enter new object and question into a new node
      
      printf("Please Enter An Object \n");
      new_object = fgets(buffer, 255, stdin);
      sscanf("You have entered: %s\n", new_object);
            
      printf ( buffer, "%[^\n]s", node_1->object );
      
      sscanf("Please Enter A Question \n");            
      new_question = fgets(buffer, 255, stdin);      
      printf ( buffer, "%[^\n]s", node_2->question );
            

      printf("Object You entered into struct is: %s \n", node_1->object);
      printf("Question You entered into struct is: %s \n", node_2->question);
      
      
                break; //Break out of loop
}

            else  printf("\007Error: Invalid choice\n");}
      }

          printf("Another Go?\n");         
  /*Get Response From User */
      scanf("  %c", &user_input );
      user_input = toupper( user_input );
 
  /*If answer is No user wins, get new details*/
      if(user_input == 'N'){
        printf("Thanks for playing\n");
        
        break;
        }      
      }}
0
 
LVL 45

Expert Comment

by:Kdo
ID: 9874591
Hi welsh_boy,

Please read my previous response.  I think that nailed it.

Kent
0
 
LVL 45

Accepted Solution

by:
Kdo earned 75 total points
ID: 9874658

Ok, ok.   I got lazy with that last post.  :)

Here's the "4 lines" in question:


       printf("Please Enter An Object \n");

     new_object = fgets(buffer, 255, stdin); //Read a string from the command line
     printf("You have entered: %s\n", node_1->object); //Print out the string
     sscanf ( buffer, "%[^\n]s", node_1->object );  //Store this string in node_1->object

Change them to be:

       printf("Please Enter An Object \n");

     new_object = fgets(buffer, 255, stdin);                   //Read a string from the command line
     sscanf ( buffer, "%[^\n]s", node_1->object );         //Store this string in node_1->object
     printf("You have entered: %s\n", node_1->object); //Print out the string

or:

       printf("Please Enter An Object \n");

     new_object = fgets(buffer, 255, stdin);            //Read a string from the command line
     printf("You have entered: %s", buffer;             //Print out the string
     sscanf ( buffer, "%[^\n]s", node_1->object );  //Store this string in node_1->object


Kent
0
 

Author Comment

by:welsh_boy
ID: 9874715
Hi Kent

I have tried replacing it with your code but I t still ignores the Object part and skips straight to the question.

I am using gcc to compile
0
 
LVL 45

Expert Comment

by:Kdo
ID: 9874799

Ok.  New theory.  :)  In this block of code:

//Enter new object and question into a new node
     
         printf("Please Enter An Object \n");
         new_object = fgets(buffer, 255, stdin);
>       sscanf("You have entered: %s\n", new_object);
         
         printf ( buffer, "%[^\n]s", node_1->object );
     
>>     sscanf("Please Enter A Question \n");          
         new_question = fgets(buffer, 255, stdin);    
         printf ( buffer, "%[^\n]s", node_2->question );

The line marked with '>' is still printing the wrong item.  'new_object' should be 'buffer'.
The line marked with '>>' should read:  printf ("Please Enter A Question \n");


Kent

0
 
LVL 45

Expert Comment

by:Kdo
ID: 9875512
Hi welsh_boy,

I finally compiled and ran your program.  It seems that we've been looking in the wrong place.  (Where we've been looking needs help, but it's not the cause of your problem!)

Earlier in the program is this code:

//Inner loop for  questions
       while (1 ){
         if (current_node->nodetype == 2) { //Object Node
     printf("Are you thinking of a %s?",current_node->object);
          scanf("  %c", &user_input );
          user_input = toupper( user_input );
          if(user_input == 'Y'){
          printf("I got it right\n");
          break; //Break out of the loop
          }

The  line 'scanf( %c", &user_input);' is causing the problem.

On your system, you press Y or N and then hit enter.  The scanf () extracts the letter but leaves the carriage return on the stdin stream!  When your code later executes the lines:

         printf("Please Enter An Object \n");
         new_object = fgets(buffer, 255, stdin);

the carraige return that is in the stdin buffer is read, and the input terminates with a null string.

You'll need to peel the carriage return off when you scanf() in the upper block or flush the buffer before reading anything else.


Glad that we finally found the problem,   :)
Kent

0
 
LVL 24

Expert Comment

by:fridom
ID: 9875656
Kent is right with his answer. You might change to either getchar or another fgets.
The problem was that the OP send code which does not show the problem.

Friedrich
0
 
LVL 5

Expert Comment

by:shajithchandran
ID: 9879867
Yes scanf is causing the problem. I told this in my first post.
I hope u read that.
0
 

Author Comment

by:welsh_boy
ID: 9881561
Im still having problems, i have tried putting fflush(stdin); at many locations with no luck

It still uses the /n charator for the next scanf
!!
0
 
LVL 8

Assisted Solution

by:ssnkumar
ssnkumar earned 50 total points
ID: 9881734
I have changed the program a bit.
I have introduced a fgetc() before one of the fgets().....(also, I have changed the indentation to suit my taste:-)) )!
I am sure it will work fine now......Here is the code:

#include <stdio.h>

struct node
{
     int nodetype; /*1 = question, 2 = object*/
     int nodenumber;
     char object[25];
     char question[25];
     struct node *YES_ptr;
     struct node *NO_ptr;
};

int main()
{
     struct node *node_1,  *current_node, *node_2;
     char  buffer[255], buffer1[255];
     char *new_object1;
     char  user_input;
     char *new_object, *new_question;
     
     /* HARD CODE AN OBJECT NODE */
     struct node dog;

     dog.nodetype = 2;
     dog.nodenumber = 0;
     dog.YES_ptr = NULL;
     dog.NO_ptr = NULL;
     strcpy(dog.object, "Dog");
     
     node_1 = (struct node*)malloc (sizeof(struct node));
     node_2 = (struct node*)malloc (sizeof(struct node));    
     new_object = (char *)malloc (sizeof(char *));    

     current_node= &dog; //Set the current node to Dog

//Outer loop for game
     while (1)
     {
//Inner loop for  questions
       while (1)
       {
         if (current_node->nodetype == 2)
       { //Object Node
            printf("Are you thinking of a %s?",current_node->object);
            scanf("%c", &user_input );
            user_input = toupper( user_input );
            if(user_input == 'Y')
          {
               printf("I got it right\n");
               break; //Break out of the loop
            }

            if(user_input == 'N')
          {
               printf("You beat me\n");
               printf("What where you thinking?\n ");

//Enter new object and question into a new node
     
               printf("Please Enter An Object \n");
             fgetc(stdin);
               new_object = fgets(buffer, 255, stdin);
               printf("You have entered: %s\n", new_object);
         
               printf ( buffer, "%[^\n]s", node_1->object );
     
               printf("Please Enter A Question \n");          
               new_question = fgets(buffer, 255, stdin);    
               printf ( buffer, "%[^\n]s", node_2->question );
         
               printf("Object You entered into struct is: %s \n", node_1->object);
               printf("Question You entered into struct is: %s \n", node_2->question);
     
               break; //Break out of loop
           }
           else  printf("\007Error: Invalid choice\n");
      }
     }

     printf("Another Go?\n");        
  /*Get Response From User */
     scanf("  %c", &user_input );
     user_input = toupper( user_input );
 
  /*If answer is No user wins, get new details*/
     if(user_input == 'N')
     {
       printf("Thanks for playing\n");
       break;
     }      
  }
}
0
 
LVL 24

Expert Comment

by:fridom
ID: 9882330
you get advice which was better suited. What you do is a hack, not a solution.

Regards
Friedrich
0

Featured Post

Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

Join & Write a Comment

Have you thought about creating an iPhone application (app), but didn't even know where to get started? Here's how: ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ Important pre-programming comments: I’ve never tri…
This tutorial is posted by Aaron Wojnowski, administrator at SDKExpert.net.  To view more iPhone tutorials, visit www.sdkexpert.net. This is a very simple tutorial on finding the user's current location easily. In this tutorial, you will learn ho…
The goal of this video is to provide viewers with basic examples to understand how to use strings and some functions related to them in the C programming language.
Video by: Grant
The goal of this video is to provide viewers with basic examples to understand and use for-loops in the C programming language.

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now