Thread: Extra characters in string

  1. #1
    Registered User Tigers!'s Avatar
    Join Date
    Jun 2009
    Location
    Melbourne, Australia
    Posts
    49

    Extra characters in string

    Gudday all
    Been fiddling around with parsing strings in a file into their path and file name components and finding that my ability to handle them is not as great as I thought. The basic problem is that a string that I wish to contain a file name of 13 characters (incl. the '\0') appears to be a lot longer that that when printed out.

    I have a file called moveTiff.dat which contains lines of the form \TestingTiffMoves\AU\PICKLIST\xxxxxxxx.TIF where the path is \TestingTiffMoves\AU\PICKLIST\ and this will be consistent for all lines in the file. The file is to be moved to another location. My idea was to use extract the path and file information and then use rename() to move the files as appropriate.

    I can extract the path seemingly alright but the file name has me stumped.
    Code:
    #include <stdio.h>
    #include <string.h>
    #include <io.h>
    
    int main(int argc, char *argv[])
    {
     char dest[30] = {0}; //destination path of files to be moved
     char tiff_file[13] = {0};  //TIFF files that will be moved
     char move_tiff[13] = "moveTIFF.dat";  //file with list of TIFF files to be moved
     char tiffLine[43];   //name and path of TIFF file
     FILE *inputFile, *errorFile, *indexFile, *tiffFile;
    
     if ( (access(move_tiff, F_OK)) != -1 ) {
    	printf("moveTIFF.dat found and can be opened\n");
    	tiffFile = fopen(move_tiff, "r");  // open data file "moveTIFF.dat" for reading only
    	while (fgets(tiffLine, 43, tiffFile)!=NULL) { //loop for reading a line up of "moveTIFF.dat" to end of file
    	  printf("%s\n", tiffLine);
    	  strncpy(dest, tiffLine, 30);
    	  printf("%i\n", strlen(tiffLine));
    	  strncpy(tiff_file, tiffLine + (strlen(tiffLine)-12), 12);
    	  printf("%s   %s\n", dest, tiff_file);
    	}
      }
     fclose(tiffFile);
     return 0;
    }
    When I run the code generated i get an output shown in the attachment.
    I can find the file moveTIFF.dat and open it. The lines in the file can be printed out (I have only shown the output for a run on a single line but the result is the same for all lines).
    The length of the line, 42 chars without the '\0' seems to be correct . I can print out the path seemingly ok but the file name is wrong. It is the extra lines (4 of them) and the other characters (the single '1' and the group of 3 characters) that puzzle me.
    The extra lines and characters appears in all lines of the file when run. I thought that I had made sure that only the characters I require were being extracted but somewhere it went blah.

    I am sure the problem is obvious but I cannot see the wood for the trees at present. Hopefully someone can spot what I cannot.

  2. #2
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    First of all, don't write code that relies on hard-coded magic numbers. All of those values should be calculated by the program. Otherwise you're just creating a maintainance nightmare for yourself and anyone else who has to use the code.

    >> tiffLine + (strlen(tiffLine)-12)

    Think about it. Let's say strlen(tiffLine) == 15. That would put you at the 3rd element to start copying at.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  3. #3
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    strncpy() doesn't automatically add a \0
    So it you don't add one, it can seem like data overrun.
    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.

  4. #4
    Registered User Tigers!'s Avatar
    Join Date
    Jun 2009
    Location
    Melbourne, Australia
    Posts
    49
    Quote Originally Posted by Sebastiani View Post
    First of all, don't write code that relies on hard-coded magic numbers. All of those values should be calculated by the program. Otherwise you're just creating a maintainance nightmare for yourself and anyone else who has to use the code.

    >> tiffLine + (strlen(tiffLine)-12)

    Think about it. Let's say strlen(tiffLine) == 15. That would put you at the 3rd element to start copying at.
    What's the best way to avoid hard-coded magic numbers e.g. how would they be defined and coded?

  5. #5
    Webhead Spidey's Avatar
    Join Date
    Jul 2009
    Posts
    285
    Store them in variables(the original ones) and then have your program calculate the rest.
    Spidey out!

  6. #6
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    I didn't compile this, but the general idea is something like:

    Code:
    // a 'safe' strncpy
    char* sstrncpy(char* dst, const char* src, size_t len)
    {
        if (!len--)
            return NULL;
        strncpy(dst, src, len);
        dst[len] = 0;    
        return dst;
    }
    
    int main(int argc, char *argv[])
    {
        const size_t size = 64;
        char* end_of_path = NULL;
        char dest[size+1] = {0}; //destination path of files to be moved
        char tiff_file[size+1] = {0};  //TIFF files that will be moved
        char move_tiff[size+1] = "moveTIFF.dat";  //file with list of TIFF files to be moved
        char tiffLine[size+1];   //name and path of TIFF file
        FILE *inputFile, *errorFile, *indexFile, *tiffFile;
        if ( (access(move_tiff, F_OK)) != -1 ) {
            printf("%s found and can be opened\n", move_tiff);
            tiffFile = fopen(move_tiff, "r");  // open data file "moveTIFF.dat" for reading only
            if (tiffFile != NULL) { 
                while (fgets(tiffLine, size, tiffFile)!=NULL) { //loop for reading a line up of "moveTIFF.dat" to end of file
                    printf("Line: %s\n", tiffLine);
                    sstrncpy(dest, tiffLine, size);
                    if (
                        (end_of_path = strrchr(dest, '\\')) != NULL 
                        || 
                        (end_of_path = strrchr(dest, '/')) != NULL
                    ) {    
                        ++end_of_path;
                        sstrncpy(tiff_file, end_of_path, size);
                        *end_of_path = 0;
                        printf("Path:%s\nFile: %s\n", dest, tiff_file);
                    }    
                }
                fclose(tiffFile);
            }    
        }    
        return 0;
    }
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  7. #7
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    if (!len--) return NULL;

    So if len is 1 then len-- is zero, but results in 1... Postfix is not what you want here, but you could use a sequence point as a fix instead.
    Last edited by whiteflags; 07-28-2009 at 04:32 AM.

  8. #8
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    >> So if len is 1 then len-- is zero, but results in 1... Postfix is not what you want here, but you could use a sequence point as a fix instead.

    The check was merely to ensure that len is not zero upon entering the function (which it does correctly).
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  9. #9
    Registered User Tigers!'s Avatar
    Join Date
    Jun 2009
    Location
    Melbourne, Australia
    Posts
    49
    Sebastiani
    Your code works fine. Thank you. I have to determine exactly how it works.
    See the attachment for the output.

    The difference between yours and mine does not seem to be that much to me but obvious it is.

  10. #10
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    >> Your code works fine. Thank you. I have to determine exactly how it works.
    See the attachment for the output.

    The one thing I noticed though is there's a trailing newline in the output. Just use strrchr(tiffLine, '\n') to get a pointer to the newline and set it to zero (check that it isn't NULL though, of course) before you copy the data to the other variables.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  11. #11
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    And just one more thing. So the whole point of automating things is so that your program can grow without having to account for any hard-coded settings. In your original post you stated that the filename will always be 13 characters long. So then if the program encounters a 14 character word, it won't work. And so then you have to go through all of the code and change all of that around including the 12's that are sprinkled around the function and whatnot. Quite a hassle! The way that the example I posted is set up, you'd only have to change the value 64 in a single place if the size of the filename for some reason requires more space. It's just more manageable that way.
    Last edited by Sebastiani; 07-28-2009 at 11:50 PM.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Help with hw problem: counting characters in a string
    By pinkfloyd4ever in forum C++ Programming
    Replies: 11
    Last Post: 11-04-2007, 11:18 PM
  2. Compile Error that i dont understand
    By bobthebullet990 in forum C++ Programming
    Replies: 5
    Last Post: 05-05-2006, 09:19 AM
  3. Reading characters from a string?
    By ladysniper in forum C++ Programming
    Replies: 6
    Last Post: 04-08-2006, 11:45 PM
  4. Linked List Help
    By CJ7Mudrover in forum C Programming
    Replies: 9
    Last Post: 03-10-2004, 10:33 PM
  5. string handling
    By lessrain in forum C Programming
    Replies: 3
    Last Post: 04-24-2002, 07:36 PM