Thread: User enter text and save to text file (end enter text using -1)

  1. #1
    Registered User
    Join Date
    Feb 2013
    Location
    Sweden
    Posts
    171

    Question User enter text and save to text file (end enter text using -1)

    Hi! What I want to do is let the user enter some text until he/she enters -1. Then I want to print what the user wrote to a text file.

    Do I somehow overwrite the buffer? I get a text file with 0 kB. So it contains no text at all. How can I make it print all the text the user typed to the file?

    Code:
    #include <stdio.h>
    #include <string.h>
    #define SIZE 1000
    #define TRUE 1
    #define FALSE 0
    #define AMT_USERS 1
    
    
    typedef struct User {
    	char buffer[SIZE]; 
    	FILE* file;
    }User;
    
    
    
    
    void input(User *user);
    void printToFile(User *user);
    
    
    int main() {
    	User user[AMT_USERS];
    	
    	input(user);
    	
    	return 0;
    }
    
    
    void input(User *user) {
    	
    	int finished = FALSE;
    	
    	while (finished == FALSE) {
    		
    		fgets(user->buffer, SIZE, stdin); 
    		
    		if (strcmp(user->buffer, "-1\n") == 0) {
    			finished = TRUE;
    		}
    	}
    	
    	printToFile(user);
    }
    
    
    void printToFile(User *user) {
    	user->file = fopen("text.txt", "w");
    	
    	if (user->file == NULL) {
    		perror("Error");
    	} 
    	
    	while (fgets(user->buffer, SIZE, user->file) != NULL) {
    		fprintf(user->file, "%s", user->buffer);
    	}
    	
    	fclose(user->file);
    }

  2. #2
    Registered User
    Join Date
    Jun 2017
    Posts
    157
    I see 2 problems with your code:

    1. fgets(user->buffer, SIZE, stdin); will override previous value of user->buffer. Better read into a temporary buffer and if input != "-1\n" then add to user->buffer. Be careful not to write over the end from user->buffer.

    2. while (fgets(user->buffer, SIZE, user->file) != NULL) Why you do try to read from empty file that is open only for writing ???????
    Why don't you just write user->buffer to the file ?

  3. #3
    Registered User
    Join Date
    Feb 2013
    Location
    Sweden
    Posts
    171
    So I decided to try to do what I at least think you meant, if I'm not totally mistaken.

    1. So I created a temporary buffer (I hope) and then checks for as long as the input
    from the user is not -1. Add the characters to the users buffer (not sure if this step is correct though).
    I am aware that I'm still overwriting the buffer.


    This worked fine with only printing one sentence, of course, I never overwrite the buffer
    then.

    2. So I am trying to read in to file. That was not what I thought I were doing.
    How do you mean I can use user->buffer to the file?

    Code:
    #include <stdio.h>
    #include <string.h>
    #define SIZE 1000
    #define TRUE 1
    #define FALSE 0
    #define AMT_USERS 1
    
    
    typedef struct User {
        char buffer[SIZE]; 
        FILE* file;
    }User;
    
    
    
    
    void input(User *user);
    void printToFile(User *user);
    
    
    int main() {
        User user[AMT_USERS];
        
        input(user);
        
        return 0;
    }
    
    
    void input(User *user) {
        char buffer[SIZE];
        
        int finished = FALSE;
        
        while (finished == FALSE) {
            
            fgets(buffer, SIZE, stdin); 
            
            if (strcmp(buffer, "-1\n") == 0) {
                finished = TRUE;
            }
            
            if (strcmp(buffer, "-1\n") != 0) {        
                int i;
                for (i = 0; i < SIZE; i++) {
                    user->buffer[i] = buffer[i];
                }
            }
        }
                    
        printToFile(user);
    
    
    }
    
    
    void printToFile(User *user) {
        user->file = fopen("text.txt", "w");
        
        if (user->file == NULL) {
            perror("Error");
        } 
        
        //while (fgets(user->buffer, SIZE, user->file) != NULL) {
            fprintf(user->file, "%s", user->buffer);
        //}
        
        fclose(user->file);
    }

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    You have two general approaches:
    • Read in one step, then write in the next step. This requires you to allocate enough space to store everything that was read up to the termination input sequence, otherwise you cannot write out everything that was read.
    • Interleave reading and writing. This means that you read into the buffer, check that it isn't the termination input sequence, and if so, immediately write to the file.

    What you appear to be trying to do is the first approach, but with a buffer sized for the second approach. You have to pick one approach in its entirety.

    EDIT:
    Also, you have an array of User objects when it seems that you only want one User object, and then to pass a pointer to it when calling a function.

    Although it is not necessarily wrong, I wonder if storing FILE pointers in the User struct objects is a right approach. There typically are a limited number of open file handles permitted.
    Last edited by laserlight; 12-26-2017 at 08:33 AM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #5
    Registered User
    Join Date
    Jun 2017
    Posts
    157
    Try this code:
    Code:
    #include <stdio.h>
    #include <string.h>
    
    #define SIZE 1000
    #define TRUE 1
    #define FALSE 0
    #define AMT_USERS 1
    
    
    typedef struct User 
    {
      char buffer[SIZE];
      FILE* file;
    }User;
    
    void input(User *user);
    void printToFile(User *user);
    
    int main() 
    {
      User user[AMT_USERS] = {0};
    
      input(user);
    
      return 0;
    }
    
    
    void input(User *user) 
    {
      char buffer[SIZE] = {0};
    
      int finished = FALSE;
    
      while (finished == FALSE) 
      {
        fgets(buffer, SIZE, stdin);
        if (strcmp(buffer, "-1\n") == 0) 
          finished = TRUE;
        else
        {
          if (strlen(user->buffer) + strlen(buffer) < SIZE) /* check buffer overflow */
            strcat(user->buffer, buffer);
        }
        
      }
      printToFile(user);
    }
    
    
    void printToFile(User *user) 
    {
      user->file = fopen("text.txt", "w");
      if (user->file == NULL) 
      {
        perror("Error");
        return;
      }
      fprintf(user->file, "%s", user->buffer);
      fclose(user->file);
    }

  6. #6
    Registered User
    Join Date
    Feb 2013
    Location
    Sweden
    Posts
    171
    Quote Originally Posted by laserlight View Post
    EDIT:
    Also, you have an array of User objects when it seems that you only want one User object, and then to pass a pointer to it when calling a function.

    Although it is not necessarily wrong, I wonder if storing FILE pointers in the User struct objects is a right approach. There typically are a limited number of open file handles permitted.
    Actually, I do want an array because this only part of code to a more complicated program. That program let's the user choose how many users to create.

    And thanks for the replies and my code actually works now!

    Do we first check how many characters the buffer that is being
    filled has first and then adding the temporary buffer to see if
    we actually can add another string/word?

    Because if the buffer has more than 1000 characters the program
    will print data that the user never typed. I realized what happened
    when changing the size to 10 and typing more than 10 characters.
    But what is causing it a '\n' and '\0' character?

    And using string concatnation let us add information to the position
    were we ended the first string/word?
    Code:
          if (strlen(user->buffer) + strlen(buffer) < SIZE) /* check buffer overflow */
            strcat(user->buffer, buffer);
    Last edited by DecoratorFawn82; 12-26-2017 at 02:10 PM.

  7. #7
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Since your aim is to "make it print all the text the user typed to the file" up to the termination sequence, I'm afraid that OldGuy2's code example still doesn't work correctly. The approach used by OldGuy2 is a better variant of your flawed approach, i.e., there's a fixed size buffer to store the user input, and then after reading all the input, it is then written as the output. Because the buffer is fixed in size but the user input can be larger than what the buffer can store, it remains plausible that with long enough file content, you cannot "make it print all the text the user typed to the file". The improvement is that instead of just writing one line from the file as output, the code now concatenates as many lines as can fill the buffer, discarding the rest, and only then writes the output.

    Do you have to store all the text that is read from the user? If so, you should use a dynamic array. If not, then use the second approach I suggested, i.e., restructure your code to interleave reading and writing such that you can use a fixed size buffer to read a line (or part of a line; it would not matter) then immediately write it as output as long as it is not the termination sequence.

    Quote Originally Posted by DecoratorFawn82
    Because if the buffer has more than 1000 characters the program
    will print data that the user never typed. I realized what happened
    when changing the size to 10 and typing more than 10 characters.
    But what is causing it a '\n' and '\0' character?
    I think that's because of a bug in the loop: basically, you should check the return value of fgets. The code doesn't do that, but rather only terminates the loop if the termination sequence is found.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  8. #8
    Registered User
    Join Date
    Feb 2013
    Location
    Sweden
    Posts
    171
    I get what you mean laserlight but in my assignment it sais that I should create
    a buffer with a large size, but of course it doesn't print all text to the file if the
    user types more than 1000 characters.

    So I guess you mean, that I should use a dynamic array so that I don't need
    to have a fixed size of the buffer. That would make the user being able to enter
    as many characters as he/she wanted.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 5
    Last Post: 08-31-2011, 07:23 AM
  2. Replies: 3
    Last Post: 05-25-2011, 05:54 PM
  3. Replies: 4
    Last Post: 01-03-2006, 03:02 AM
  4. Automatically enter text in a dialog box
    By leojose in forum Windows Programming
    Replies: 6
    Last Post: 12-13-2005, 11:59 AM
  5. How do you save to a text file?
    By RolaCola in forum C++ Programming
    Replies: 15
    Last Post: 06-28-2005, 07:31 PM

Tags for this Thread