Thread: Fun with strings. Some learning code.

  1. #1
    Registered User
    Join Date
    Sep 2017
    Posts
    93

    Fun with strings. Some learning code.

    I'm just posting some code that I came up with.

    I usually have a hard time learning things unless I do them myself after reading up on the concepts of the functions needed for certain applications.

    Figured I could post the code that I came up with to learn from.

    This is what I came up with:
    Code:
    #include <stdio.h>
    #include <stdint.h>
    #include <string.h>
    
    #define BUFFER 1024
    
    void PressEnter(void);
    
    int main()
    {
        char CharacterInput[BUFFER], ConvertedToString[BUFFER];
        uint16_t ProgramCounter;
    
        printf("Enter a string:\n");
        fgets(CharacterInput, sizeof(CharacterInput), stdin);
    
        printf("Printing directly from \"CharacterInput\":\n");
        printf("%s", CharacterInput);
        
        PressEnter();
    
        printf("Printing from for loop:\n");
        for(ProgramCounter = 0; ProgramCounter < strlen(CharacterInput); ProgramCounter++)
        {
            printf("%c\n", CharacterInput[ProgramCounter]);
            if(CharacterInput[ProgramCounter] == '\n' || CharacterInput[ProgramCounter] == EOF)
                break;
        }
        
        PressEnter();
    
        printf("\"CharacterInput\" is %lu bytes long\n", strlen(CharacterInput));
        printf("There are %d characters\n", ProgramCounter);
        printf("Remember, \"CharacterInput\" should be one byte longer than the number of characters due to the NULL terminator\n");
        
        PressEnter();
        
        printf("This is now copying \"CharacterInput\" to \"*ConvertedToString\"\n");
        strncpy(ConvertedToString, CharacterInput, sizeof(ConvertedToString));
        printf("%s", ConvertedToString);
        
        PressEnter();
        
        printf("Clearing \"CharacterInput\". Let's see if we saved the original content to \"ConvertedToString\":\n");
        memset(CharacterInput, 0x00, sizeof(CharacterInput));
        
        printf("Contents of \"CharacterInput\":\n");
        printf("%s\n", CharacterInput);
        printf("Contents of \"*ConvertedString\":\n");
        printf("%s\n", ConvertedToString);
        
        PressEnter();
        
        return 0;
    }
    
    void PressEnter()
    {
        printf("Press enter to continue: ");
        while(getchar() != '\n' && getchar() != EOF);
    }

  2. #2
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    Very nice, but this doesn't do what you might think it does.

    Code:
    void PressEnter()
    {
        printf("Press enter to continue: ");
        while(getchar() != '\n' && getchar() != EOF);
    }
    Your loop will call getchar() twice. This isn't really ideal, because you end up typing more than you planned in numerous circumstances; sending EOF instead of pressing enter is one of them. Store getchar()'s return value instead. If remembering to put the assignment in parentheses is awkward, you can use a do-while loop.

    Code:
    int ch;
    do
       ch = getchar();
    while (ch != '\n' && ch != EOF);
    Code:
            if(CharacterInput[ProgramCounter] == '\n' || CharacterInput[ProgramCounter] == EOF)
    
                break;
    You don't really need to check for these characters all the time, and I would delete these lines in this listing. I think when you first saw this, it was an attempt at detecting items left over in the input buffer to remove. You're not trying to remove anything in the buffer now, and tbh strlen() knows where the end of the string is.

    Code:
     for (i = 0, len = strlen(str); i < len; i++) ...
    Prefer this. strlen() will be called every iteration otherwise just to calculate a non-changing amount.
    Last edited by whiteflags; 10-23-2017 at 12:46 AM.

  3. #3
    Registered User
    Join Date
    Sep 2014
    Posts
    364
    Additional what whiteflags says.
    Code:
    if(CharacterInput[ProgramCounter] == '\n' || CharacterInput[ProgramCounter] == EOF)
        break;
    CharacterInput is a array of chars. EOF is an integer and can never be in a char.
    If you want to search for the end of the string, then you should search the terminator '\0'.


    The string terminator '\0' will interpreted as false.
    You can also write:
    Code:
    for ( ProgramCounter = 0 ; CharacterInput[ProgramCounter] ; ProgramCounter++) …
    Other have classes, we are class

  4. #4
    Registered User
    Join Date
    Jun 2017
    Posts
    157
    EOF is an integer and can never be in a char.
    Of course it can. EOF is defined as -1 and the range for a char is -128..127

  5. #5
    Programming Wraith GReaper's Avatar
    Join Date
    Apr 2009
    Location
    Greece
    Posts
    2,738
    Quote Originally Posted by OldGuy2 View Post
    EOF is defined as -1 and the range for a char is -128..127
    That is implementation-defined behavior, so we prefer to handle it as if it could be something different.
    Devoted my life to programming...

  6. #6
    Registered User
    Join Date
    Sep 2014
    Posts
    364
    As GReaper says, it's implementation-defined.

    Anyway, EOF is defined as a int and is larger then a char.
    If you assign EOF to a char, it will be stipped down to 8 bit.
    Now, it represent the char with the value -1 (or if unsigned 255) and this is a valid code for a character.
    Where should the program knows if you mean the character or the EOF?
    It can be that the OP (or anybody else) has a string with this character in the middle of the string.
    The loop can end in the middle ("no, i dont mean EOF! i want the character!") or keep running ("no, i dont mean this character! it is EOF!").
    From where should the program knows what you mean?

    Its simple! EOF can be returned from functions that read input streams.
    A char can never be represent EOF! A character array is NOT a stream!
    If you look for the end of string in a char array, then look out for '\0' (string terminator).

    PS: If a character array has no '\0' in it, then it contains no string (only characters)!
    Don't use any of the str...-functions! The most str...-functions relate on the terminator!
    If you build up a string be yourself, don't forget to set '\0'! And no, EOF isn't a terminator.
    Otherwise the result can be worst!
    Last edited by WoodSTokk; 10-23-2017 at 07:20 AM.
    Other have classes, we are class

  7. #7
    Registered User
    Join Date
    May 2010
    Posts
    4,632
    And don't forget that a char can be either an unsigned char or a signed char depending on implementation. So if your char happens to be unsigned you can't use a char to test for EOF since EOF is some implementation defined negative value.

    Jim

  8. #8
    Registered User
    Join Date
    Sep 2017
    Posts
    93
    Here's the updated code with your suggestions.

    Code:
    //
    //  main.c
    //  String Parsing
    //
    //  Created by Joshua Ernzen on 10/22/17.
    //  Copyright © 2017 Joshua Ernzen. All rights reserved.
    //
    
    #include <stdio.h>
    #include <stdint.h>
    #include <string.h>
    
    #define BUFFER 1024
    
    void PressEnter(void);
    
    int main()
    {
        char CharacterInput[BUFFER], ConvertedToString[BUFFER];
        uint16_t ProgramCounter, StringLength;
    
        printf("Enter a string:\n");
        fgets(CharacterInput, sizeof(CharacterInput), stdin);
    
        printf("Printing directly from \"CharacterInput\":\n");
        printf("%s", CharacterInput);
        
        PressEnter();
    
        StringLength = strlen(CharacterInput);
        printf("Printing from for loop:\n");
        for(ProgramCounter = 0; ProgramCounter < StringLength; ProgramCounter++)
        {
            printf("%c\n", CharacterInput[ProgramCounter]);
            if(CharacterInput[ProgramCounter] == '\n' || CharacterInput[ProgramCounter] == '\0')
                break;
        }
        
        PressEnter();
    
        printf("\"CharacterInput\" is %lu bytes long\n", strlen(CharacterInput));
        printf("There are %d characters\n", ProgramCounter);
        printf("Remember, \"CharacterInput\" should be one byte longer than the number of characters due to the NULL terminator\n");
        
        PressEnter();
        
        printf("This is now copying \"CharacterInput\" to \"*ConvertedToString\"\n");
        strncpy(ConvertedToString, CharacterInput, sizeof(ConvertedToString));
        printf("%s", ConvertedToString);
        
        PressEnter();
        
        printf("Clearing \"CharacterInput\". Let's see if we saved the original content to \"ConvertedToString\":\n");
        memset(CharacterInput, 0x00, sizeof(CharacterInput));
        
        printf("Contents of \"CharacterInput\":\n");
        printf("%s\n", CharacterInput);
        printf("Contents of \"*ConvertedString\":\n");
        printf("%s\n", ConvertedToString);
        
        PressEnter();
        
        return 0;
    }
    
    void PressEnter()
    {
        int8_t EnterBuffer;
        printf("Press enter to continue: ");
        
        do
            EnterBuffer = getchar();
        while(EnterBuffer != '\n' && EnterBuffer != EOF);
        
        return;
    }
    I was also thinking about removing "ConvertedToString[BUFFER]" to malloc. I've never played with malloc before so I would think this would be a good attempt for it.

  9. #9
    Registered User
    Join Date
    Sep 2014
    Posts
    364
    Quote Originally Posted by ImageJPEG View Post
    Code:
    void PressEnter()
    {
        int8_t EnterBuffer;
        printf("Press enter to continue: ");
    
        do
            EnterBuffer = getchar();
        while(EnterBuffer != '\n' && EnterBuffer != EOF);
    
        return;
    }
    Same problem here. int_8 has the same size as char. EOF will not fit in there.
    Here is a solution with int (and a little bit shorter):
    Code:
    void PressEnter(void)
    {
        int EnterBuffer;
        printf("Press enter to continue: ");
    
        while ((EnterBuffer = getchar()) != '\n' && EnterBuffer != EOF );
    }
    Other have classes, we are class

  10. #10
    Registered User
    Join Date
    Sep 2017
    Posts
    93
    I fixed the issue with int and EOF.

    I've now played around with malloc.

    Here's the snippet of that code:

    Code:
        AllocatedString = (char *)malloc(sizeof(AllocatedString));
        
        if(AllocatedString == NULL)
        {
            printf("ERROR: No memory!\n");
            return 1;
        }
        
        strcpy(AllocatedString, ConvertedToString);
        printf("Here is a malloc string:\n");
        printf("%s\n", AllocatedString);
        
        free(AllocatedString);

  11. #11
    Registered User
    Join Date
    Sep 2014
    Posts
    364
    Quote Originally Posted by ImageJPEG View Post
    I fixed the issue with int and EOF.

    I've now played around with malloc.

    Here's the snippet of that code:

    Code:
    AllocatedString = (char *)malloc(sizeof(AllocatedString));
    I asume that AllocatedString is declared as char pointer like:
    Code:
    char *AllocatedString = NULL;
    Now, whats the size of AllocatedString?
    Secondly, don't cast the returned value of malloc.
    The compiler will check your code, but a cast can suppress warnings and/or errors.

    The code should look like this:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main (void) {
    
        char ConvertedToString = "This is a test string!\n";
        char *AllocatedString = NULL;
    
        AllocatedString = malloc(strlen(ConvertedToString) + 1); // +1 for the terminator (\0)
        if(AllocatedString == NULL)
        {
            fprintf(stderr, "ERROR: No memory!\n");
            return 1;
        }
        strcpy(AllocatedString, ConvertedToString);
        printf("Here is a malloc string:\n");
        printf("%s\n", AllocatedString);
        free(AllocatedString);
        return 0;
    }
    PS: fprintf works like printf, except that you give the output stream. printf outputs only on stdout.
    fprintf can output on stdout, but also on stderr or a opened file.
    Its a good practice to write error messages to stderr, because if you pipe the output to another program,
    the receiving program expect valid output, not errors.
    A pipe connect only stdout with stdin of the reciever, stdout goes normaly to the terminal.
    Last edited by WoodSTokk; 10-24-2017 at 09:07 PM.
    Other have classes, we are class

  12. #12
    Registered User
    Join Date
    Sep 2017
    Posts
    93
    Thanks for the tip!

    I will admit, malloc seemed a bit more intimating than it actually is. At least for something this simple.

  13. #13
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,787
    Quote Originally Posted by WoodSTokk View Post

    The code should look like this:
    Code:
        char ConvertedToString = "This is a test string!\n";
    Maybe turn on compiler warnings...

  14. #14
    Registered User
    Join Date
    Sep 2014
    Posts
    364
    Quote Originally Posted by Hodor View Post
    Maybe turn on compiler warnings...
    Ops, sorry, should be
    Code:
    char ConvertedToString[] = "This is a test string!\n";
    Other have classes, we are class

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Learning c++, need help on this code snipit
    By FreddyJ in forum C++ Programming
    Replies: 3
    Last Post: 05-22-2015, 09:54 AM
  2. learning to use arrays and C-strings together
    By jackson6612 in forum C++ Programming
    Replies: 13
    Last Post: 06-11-2011, 04:55 PM
  3. learning c from old k&r code
    By cmay in forum C Programming
    Replies: 13
    Last Post: 06-10-2009, 03:56 AM
  4. Am I learning out-dated code?
    By JustinAllard in forum C++ Programming
    Replies: 9
    Last Post: 11-30-2005, 05:05 AM
  5. learning to code
    By Unregistered in forum C Programming
    Replies: 2
    Last Post: 10-30-2001, 08:49 AM

Tags for this Thread