Thread: Weird string problem

  1. #1
    Registered User
    Join Date
    Oct 2005
    Posts
    43

    Weird string problem

    Hi,

    I have been programming in C for about 6 months now and thought I had got pretty used to it but I came across a weird problem which I don't really understand. I wrote a small program to illustrate my problem (really just a cutdown version of a larger application I am writing).

    I am using Windows XP Professional with Dev-C++ and GCC.

    Here are two almost identical programs:

    Code:
    #include <time.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    int main()
    {
     char People[][9] = {
      "adam",
      "bridget",
      "celia",
      "claire",
      "eric",
      "faye",
      "fiona",
      "holly",
      "isobel",
      "katie",
      "matthew",
     };
     int ps, pe;
     char fs[7] = "hello ";
     char fe[7] = "hello ";
    
     srand((unsigned) time(NULL));
     ps = rand() % 11;
     pe = rand() % 11;
    
     strcat(fs, People[ps]);
     strcat(fs, " is here");
     printf("%s", fs); getchar();
    
     strcat(fe, People[pe]);
     strcat(fe, " is here");
     printf("%s", fe); getchar();
    
     return 0;
    }
    Code:
    #include <time.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    int main()
    {
     char People[][9] = {
      "adam",
      "bridget",
      "celia",
      "claire",
      "eric",
      "faye",
      "fiona",
      "holly",
      "isobel",
      "katie",
      "matthew",
     };
     int ps, pe;
     char fs[8] = "\\hello ";
     char fe[8] = "\\hello ";
    
     srand((unsigned) time(NULL));
     ps = rand() % 11;
     pe = rand() % 11;
    
     strcat(fs, People[ps]);
     strcat(fs, " is here");
     printf("%s", fs); getchar();
    
     strcat(fe, People[pe]);
     strcat(fe, " is here");
     printf("%s", fe); getchar();
    
     return 0;
    }
    They are written in C for a console application.

    Now the only difference is that there is an escaped backslash in the strings in the second version (I have also updated the lengths of the strings in the initialisers). The first version compiles and runs fine, displaying two strings such as "hello matthew is here" and "hello adam is here". However the second version displays one of the strings e.g. "\hello eric is here", then it crashes.

    I do not understand this error at all.

    Please help!

  2. #2
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,218
    Code:
    char fs[8] = "\\hello ";
    ...
     strcat(fs, People[ps]);
     strcat(fs, " is here");
    You're only allocating 8 bytes for your fs array, which is just fine for holding the string you're initializing it to. But then you're using strcat() to append another string to the end of fs. This appended string is going outside the bounds of the array and is mangling memory. Try making fs able to hold at least 30 chars and see what happens.

    The problem actually exists in both programs you posted. You're just getting lucky (some might say unlucky, because a bug that doesn't readily present itself is harder to find) in the first one that the memory mangling isn't so bad that it crashes the program.

    At any rate, your fs and fe arrays need to be big enough to hold the "hello" string plus the longest string in your People array plus the "is here" string plus the string terminator character.
    Last edited by itsme86; 08-04-2006 at 04:31 PM.
    If you understand what you're doing, you're not learning anything.

  3. #3
    Registered User
    Join Date
    Oct 2005
    Posts
    43
    Thanks, that's very helpful.

    Presumably it would be possible to write a "safe" strcat, which creates a new pointer, mallocs it to the correct size (sum of the strlens, plus one) then strcpys the old string in there, runs the existing strcat function and frees the old pointer.

    But I guess the existing strcat doesn't have this functionality because it would be very time-consuming (but more memory-efficient, because you wouldn't have to declare arrays to be larger than they need to be).

  4. #4
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    >Presumably it would be possible to write a "safe" strcat, which creates a new pointer,
    >mallocs it to the correct size (sum of the strlens, plus one) then strcpys the old string in
    >there, runs the existing strcat function and frees the old pointer.
    That doesn't sound very safe. What if the old pointer is an array? Freeing memory that was never malloc'd is not a good idea at all. It also puts the onus of freeing the memory in the new string to the caller, which has been proven repeatedly to be a mistake since callers tend to forget such things. That idea, while logically sound, has too many restrictions, it seems.

    A "safe" strcat would be something more like this:
    Code:
    char *safe_strcat ( char *dst, const char *src, size_t n )
    {
      size_t len = strlen ( dst );
    
      while ( *src != '\0' && len < n - 1 )
        dst[len++] = *src++;
    
      dst[len] = '\0';
    
      return dst;
    }
    My best code is written with the delete key.

  5. #5
    Registered User
    Join Date
    Mar 2006
    Posts
    725
    safe_strcat() is known by many names. In string.h you will find it called strncat.
    Code:
    #include <stdio.h>
    
    void J(char*a){int f,i=0,c='1';for(;a[i]!='0';++i)if(i==81){
    puts(a);return;}for(;c<='9';++c){for(f=0;f<9;++f)if(a[i-i%27+i%9
    /3*3+f/3*9+f%3]==c||a[i%9+f*9]==c||a[i-i%9+f]==c)goto e;a[i]=c;J(a);a[i]
    ='0';e:;}}int main(int c,char**v){int t=0;if(c>1){for(;v[1][
    t];++t);if(t==81){J(v[1]);return 0;}}puts("sudoku [0-9]{81}");return 1;}

  6. #6
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,218
    Except strncat() will only copy the string terminator into the destination string if it's within the first n chars of src. That's always a big gotcha that gets strncat() beginners.
    If you understand what you're doing, you're not learning anything.

  7. #7
    ex-DECcie
    Join Date
    Dec 2005
    Posts
    125

    Maybe try strlcat...

    Quote Originally Posted by itsme86
    Except strncat() will only copy the string terminator into the destination string if it's within the first n chars of src. That's always a big gotcha that gets strncat() beginners.
    I believe the variants of BSD Unix have a "safe" strcat called strlcat (and there is a companion strlcpy) both of which are guaranteed to truncate AND null terminate instead of overflowing.

    You can probably find source code around on the web.....

    I know it doesn't come by default in the Red Hat variants of Linux.
    Mr. Blonde: You ever listen to K-Billy's "Super Sounds of the Seventies" weekend? It's my personal favorite.

  8. #8
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Which isn't realy safe, if you don't want your data truncated. Though to be fair, you did put safe in quotes.


    Quzah.
    Hope is the first step on the road to disappointment.

  9. #9
    ex-DECcie
    Join Date
    Dec 2005
    Posts
    125
    To paraphrase Forrest Gump, "safe is as safe does"

    Seriously, I agree with you. If you're in a situation where your data might be truncated anyway, then it is safer to have it null terminated I'd guess. And if you do examine the return value, you can tell that it has been truncated.

    But, it's not for every situation....
    Mr. Blonde: You ever listen to K-Billy's "Super Sounds of the Seventies" weekend? It's my personal favorite.

  10. #10
    Registered User Micko's Avatar
    Join Date
    Nov 2003
    Posts
    715

    OT: Forrest Gump

    Quote Originally Posted by fgw_three
    To paraphrase Forrest Gump, "safe is as safe does"
    What Forrest Gump used to say?
    "Dumb is..."
    This is off topic, but I need to know....
    Cheers
    Gotta love the "please fix this for me, but I'm not going to tell you which functions we're allowed to use" posts.
    It's like teaching people to walk by first breaking their legs - muppet teachers! - Salem

  11. #11
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,218
    Stupid is as stupid does.
    If you understand what you're doing, you're not learning anything.

  12. #12
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    "Life is like a truncated-not-terminated 'string'..."


    Quzah.
    Hope is the first step on the road to disappointment.

  13. #13
    {Jaxom,Imriel,Liam}'s Dad Kennedy's Avatar
    Join Date
    Aug 2006
    Location
    Alabama
    Posts
    1,065
    If you really get desperate, you could use the Windows StringCchCopy which supposedly doesn't allow you to copy past the end of the allocated memory location, but I agree with the others about writing your own and malloc'ing the space.

    Andy

  14. #14
    Registered User
    Join Date
    Aug 2006
    Posts
    12
    Maybe at first stage you simply should allocate enough space for destination strings?

    Code:
    char fs[64] = "\\hello ";
    char fe[64] = "\\hello ";
    I hope it helps.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. C++ string problem
    By gatewalker in forum C++ Programming
    Replies: 6
    Last Post: 06-07-2009, 10:40 PM
  2. We Got _DEBUG Errors
    By Tonto in forum Windows Programming
    Replies: 5
    Last Post: 12-22-2006, 05:45 PM
  3. Replies: 5
    Last Post: 11-07-2005, 11:34 PM
  4. Program using classes - keeps crashing
    By webren in forum C++ Programming
    Replies: 4
    Last Post: 09-16-2005, 03:58 PM
  5. Classes inheretance problem...
    By NANO in forum C++ Programming
    Replies: 12
    Last Post: 12-09-2002, 03:23 PM