Thread: strange behaviour

  1. #1
    Registered User
    Join Date
    Jul 2012
    Location
    Australia
    Posts
    242

    strange behaviour

    Hi all.

    If "test.txt" contains "Hello world", and this is copied into "temp.txt", then why does puts(word) result in "hhhhh"? Why not "Hello"? Thanks in advance.

    Code:
    // spellcheck.c - checks spelling of a text file against a dictionary file
    // 5 functions: copyfile(), getword(), spellcheck(), options(), editfile()
    
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    #define BUFFERSIZE 4096
    #define FILENAME_LENGTH 40
    #define STRING_LENGTH 300 // length of string read by fgets() from file
    #define WORD_LENGTH 40
    
    void copyfile (FILE *file, FILE *tempfile);
    void getword(FILE *tempfile);
    void spellcheck (char *word);
    void options();
    void edit_file();
    
    int main(void)
    {
        FILE *file, *dictionary, *tempfile;
        char word_to_check[WORD_LENGTH];
    
        file = fopen("test.txt", "r");
        tempfile = fopen("temp.txt", "w");
        copyfile(file, tempfile);
        tempfile = fopen("temp.txt", "r");
        getword(tempfile);
        //dictionary = fopen("dictionary.txt", "r");
    
        //spellcheck(word_to_check);
    
        return 0;
    }
    
    // copy original file to tempfile for reading so that original file can be opened for writing(editing)
    void copyfile(FILE *file, FILE *tempfile)
    {
        size_t c;
        char buffer[BUFFERSIZE];
    
        while((c = fread(buffer, 1, BUFFERSIZE, file)) > 0)
        {
            fwrite(buffer, 1, c, tempfile);
        }
        fclose(file);
        fclose(tempfile);
    }
    
    void getword(FILE *tempfile)
    {
        char word[WORD_LENGTH];
        int ch;
        static int x1 = 0, x2 = 0; // location of space or punctuation
        int ctr = 0;
    
        while((ch = fgetc(tempfile)) != EOF)
        {
            if((ch != ' ') && (ch != '.') && (ch != '-') && (ch != '!') && (ch != '(') && (ch != ')') && (ch != ':') && (ch != ';') && (ch != '\n'))
            {
                word[ctr] = 'ch';
                ctr++;
                continue;
            }
            else
            {
                word[ctr] = '\0'; // if ch is space or punctuation, add terminator to create string
                puts(word);
                exit (1);
            }
        }
    }
    
    //void spellcheck (char *word)
    //{
    //
    //}
    IDE: Code::Blocks | Compiler Suite for Windows: TDM-GCC (MingW, gdb)

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    > word[ctr] = 'ch';
    Because this is a wide character constant, and the LSB of it is just 'h'

    Perhaps you meant
    word[ctr] = ch;

    > exit (1);
    This is a bit aggressive having just read one word, what about the rest of the file?

    > fclose(file);
    > fclose(tempfile);
    There is nothing wrong per se, but it might be an idea to open and close the files in the same function.
    Leaked file handles (caused by confusion over who opens/closes the file) are pretty serious, since there are so few file handles to begin with.
    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.

  3. #3
    Registered User
    Join Date
    May 2010
    Posts
    4,632
    You are trying to assign word[ctr] the value 'ch', this is the problem line.
    Code:
                word[ctr] = 'ch';
    How many characters can a char constant hold? Answer a char can only hold one character. You probably meant:
    Code:
                word[ctr] = ch;
    Jim

  4. #4
    Registered User
    Join Date
    Sep 2012
    Posts
    357
    line 61
    Code:
            word[ctr] = 'ch';
    You putting a constant (a multi-character literal even) into the word object.

    Try upping your compiler warnings ... and change that line to
    Code:
            word[ctr] = ch;

  5. #5
    Registered User
    Join Date
    Jul 2012
    Location
    Australia
    Posts
    242
    Thanks for the replies. Such a simple mistake, but I still couldn't figure it out after 2 hours.

    Maybe I'll ask here next time if I can't solve something within an hour.
    IDE: Code::Blocks | Compiler Suite for Windows: TDM-GCC (MingW, gdb)

  6. #6
    Registered User
    Join Date
    Sep 2012
    Posts
    357
    Quote Originally Posted by cfanatic View Post
    Such a simple mistake, but I still couldn't figure it out after 2 hours.
    The compiler can help you catch some (most) simple mistakes.
    Just enable all the warnings you can and mind the warnings.

    For specifics about enabling the warnings, tell us what is your compiler. Maybe one of us uses the same compiler and can tell you how to do it.

  7. #7
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    You're using gcc, so you should be able to enable these options.
    Code:
    $ gcc -std=c99 foo.c
    foo.c: In function ‘getword’:
    foo.c:61:25: warning: multi-character character constant [-Wmultichar]
    foo.c:61:13: warning: overflow in implicit constant conversion [-Woverflow]
    
    $ gcc -Wall -std=c99 foo.c
    foo.c: In function ‘main’:
    foo.c:22:10: warning: unused variable ‘word_to_check’ [-Wunused-variable]
    foo.c:21:18: warning: unused variable ‘dictionary’ [-Wunused-variable]
    foo.c: In function ‘getword’:
    foo.c:61:25: warning: multi-character character constant [-Wmultichar]
    foo.c:61:13: warning: overflow in implicit constant conversion [-Woverflow]
    foo.c:54:24: warning: unused variable ‘x2’ [-Wunused-variable]
    foo.c:54:16: warning: unused variable ‘x1’ [-Wunused-variable]
    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.

  8. #8
    Registered User
    Join Date
    Jul 2012
    Location
    Australia
    Posts
    242
    Well, the code is starting to take shape, but I am getting the below errors.

    I declared the struct in getword(), and want to pass the struct back to main. How do I create a pointer to the struct in main, and assign the returned struct to it? I tried to do this in line 22, but the struct is local to getword(). Thanks.

    Code:
    main.c||In function ‘main’:|
    main.c|30|error: request for member ‘word’ in something not a structure or union|
    main.c|31|error: request for member ‘word’ in something not a structure or union|
    main.c|34|warning: comparison between pointer and integer [enabled by default]|
    main.c|22|warning: variable ‘word_to_check’ set but not used [-Wunused-but-set-variable]|
    main.c|21|warning: variable ‘dictionary’ set but not used [-Wunused-but-set-variable]|
    main.c||In function ‘getword’:|
    main.c|79|warning: return from incompatible pointer type [enabled by default]|
    main.c|79|warning: function returns address of local variable [enabled by default]|
    main.c|82|warning: return makes pointer from integer without a cast [enabled by default]|
    main.c|64|warning: unused variable ‘x2’ [-Wunused-variable]|
    main.c|64|warning: variable ‘x1’ set but not used [-Wunused-but-set-variable]|
    ||=== Build finished: 2 errors, 8 warnings ===|
    Code:
    // spellcheck.c - checks spelling of a text file against a dictionary file
    // 5 functions: copyfile(), getword(), spellcheck(), options(), editfile()
    
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    #define BUFFERSIZE 4096
    #define FILENAME_LENGTH 40
    #define STRING_LENGTH 300 // length of string read by fgets() from file
    #define WORD_LENGTH 40
    
    void copyfile (FILE *file, FILE *tempfile);
    struct word *getword(FILE *tempfile);
    void spellcheck (struct word *word_to_check);
    void options();
     void editfile();
    
    int main(void)
    {
        FILE *file, *dictionary, *tempfile;
        struct word *word_to_check;
    
        copyfile(file, tempfile);
        tempfile = fopen("temp.txt", "r");
        dictionary = fopen("dictionary.txt", "r");
    
        do {
            word_to_check = getword(tempfile);
            printf("%s", word_to_check.word);
            spellcheck(word_to_check.word);
        //option();
        //edit();
        } while (getword(tempfile) != 1);
    
        return 0;
    }
    
    // copy original file to tempfile for reading so that original file can be opened for writing(editing)
    void copyfile(FILE *file, FILE *tempfile)
    {
        size_t c;
        char buffer[BUFFERSIZE];
    
        file = fopen("test.txt", "r");
        tempfile = fopen("temp.txt", "w");
    
        while((c = fread(buffer, 1, BUFFERSIZE, file)) > 0)
        {
            fwrite(buffer, 1, c, tempfile);
        }
        fclose(file);
        fclose(tempfile);
    }
    
    struct word *getword(FILE *tempfile)
    {
        struct word {
        char word[WORD_LENGTH];
        int x;
        } word;
    
        int ch;
        static int x1 = 0, x2 = 0; // location of space or punctuation
        int ctr = 0;
    
        while((ch = fgetc(tempfile)) != EOF)
        {
            if((ch != ' ') && (ch != '.') && (ch != '-') && (ch != '!') && (ch != '(') && (ch != ')') && (ch != ':') && (ch != ';') && (ch != '\n'))
            {
                word.word[ctr] = ch;
                ctr++;
                x1 = ctr;
                continue;
            }
            else
            {
                word.word[ctr] = '\0'; // if ch is space or punctuation, add terminator to create string
                return &word; // return pointer to main()
            }
        }
        return (word.x = 1); // flag that EOF has been reached
    }
    
    void spellcheck (struct word *word_to_check)
    {
    
    }
    IDE: Code::Blocks | Compiler Suite for Windows: TDM-GCC (MingW, gdb)

  9. #9
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Lines 58 to 61 need to be moved to around line 12
    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.

  10. #10
    Registered User
    Join Date
    Jul 2012
    Location
    Australia
    Posts
    242
    Make the struct global? That would make things so easy. But people keep telling to stop using globals(including structs).

    Oh well, if you say so.
    IDE: Code::Blocks | Compiler Suite for Windows: TDM-GCC (MingW, gdb)

  11. #11
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    It's global variables (of any type) which people say to avoid.

    A struct declaration is like a function prototype. It has to be declared in a place visible to everything that uses it.

    So towards the beginning of the file
    Code:
    // a struct called word, containing members called word and x
        struct word {
        char word[WORD_LENGTH];
        int x;
        };
    And in your function
    Code:
    struct word word;  // create an instance of 'struct word' called 'word'
    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.

  12. #12
    SAMARAS std10093's Avatar
    Join Date
    Jan 2011
    Location
    Nice, France
    Posts
    2,694
    Quote Originally Posted by cfanatic View Post
    But people keep telling to stop using globals(including structs).

    Oh well, if you say so.
    I also suggest you to declare the struct above main function.Do not declare variables above the main

  13. #13
    Registered User
    Join Date
    May 2012
    Posts
    1,066
    Quote Originally Posted by cfanatic View Post
    Code:
    main.c||In function ‘main’:|
    main.c|30|error: request for member ‘word’ in something not a structure or union|
    main.c|31|error: request for member ‘word’ in something not a structure or union|
    main.c|34|warning: comparison between pointer and integer [enabled by default]|
    The reason for the errors in line 30 and 31 is that "word_to_check" is a pointer to struct word.
    Code:
     printf("%s", word_to_check.word);
    spellcheck(word_to_check.word);
    Here you want to access a struct member but since word_to_check is a pointer you have to dereference it first:
    Code:
    (*word_to_check).word
    or use the syntax shortcut
    Code:
    word_to_check->word
    In line 34 getword() returns a pointer to struct word but you want to compare it to an interger. The problems lies probably in your wrong belief that line 82 works:
    Code:
    return (word.x = 1); // flag that EOF has been reached
    But that line is wrong because you have defined the function to return a pointer and here you try to return an int.
    If you want to return some kind of error message to the caller you have to use a pointer. Usually that's done with a null-pointer.

    Bye, Andreas

  14. #14
    SAMARAS std10093's Avatar
    Join Date
    Jan 2011
    Location
    Nice, France
    Posts
    2,694
    Looking again at the post i show that cfanatic does not write void when the function has no parameters at all.(e.g. line 16 at post #1)

    I am bit of confused here.What should we do?Use void or not?

  15. #15
    Registered User
    Join Date
    Jul 2012
    Location
    Australia
    Posts
    242
    Quote Originally Posted by AndiPersti View Post
    But that line is wrong because you have defined the function to return a pointer and here you try to return an int.
    If you want to return some kind of error message to the caller you have to use a pointer. Usually that's done with a null-pointer.
    That's great. My only reason for using a struct is so that I could return an int to signify EOF. If I can just return a null pointer, then time to get rid of the struct altogether.
    IDE: Code::Blocks | Compiler Suite for Windows: TDM-GCC (MingW, gdb)

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. strange behaviour
    By cfanatic in forum C Programming
    Replies: 2
    Last Post: 07-16-2012, 06:41 AM
  2. strange behaviour
    By cfanatic in forum C Programming
    Replies: 9
    Last Post: 07-13-2012, 10:41 PM
  3. Strange behaviour of GCC
    By BlackOps in forum C Programming
    Replies: 14
    Last Post: 07-29-2009, 06:44 PM
  4. strange behaviour.......
    By surdy in forum C Programming
    Replies: 2
    Last Post: 05-01-2004, 11:50 AM
  5. Strange behaviour
    By PrivatePanic in forum Windows Programming
    Replies: 11
    Last Post: 07-23-2002, 12:54 AM