1. Welcome to the new MacRumors forums. See our announcement and read our FAQ

Strcpy isn't working -- :(

Discussion in 'Mac Programming' started by bobber205, Mar 15, 2007.

  1. macrumors 68020

    bobber205

    #1
    This is legal at school in Visual Studio.

    Code:
      if (which >= 1 && which <= numEntries) {
                    which = which -1;
                    cout << "New First Name: ";
                    cin >> temp;
                    strcpy(firstnames[index[which]], temp);
                    cout << endl;
    
                    cout << "New Last Name: ";
                    cin >> temp;
                    strcpy(lastnames[index[which]], temp);
                    cout << endl;
    
                    cout << "New Phone Number: ";
                    cin >> temp;
                    strcpy(phonenumbers[index[which]], temp);
                    cout << endl;
    
                    cout << "New Birthday: ";
                    cin >> temp;
                    strcpy(birthdays[index[which]], temp);
                    cout << endl;
    
                    
                
    }
                else cout << "INVALID Number." << endl;
                
    
    But in Xcode I'm getting a

    Code:
     invalid types 'char (*)[50][char* ()(const char*, int)]' for array subscript
    
    Any ideas why? What function should I use?

    What's a good reference for what C++ functions I can and can't use in Xcode's compiler?
     
  2. macrumors 65816

    MarkCollette

    #2
    1. Exactly what datatypes are: which, index, firstnames, lastnames, phonenumbers, birthdays?

    2. What aren't you using structures or classes, instead of these parallel arrays?

    3. Why are you using strcpy(), instead of strncpy()?

    4. Why are you (I think) using char arrays, instead of string objects?
     
  3. macrumors 68020

    bobber205

    #3
    EDIT:

    The index array was not passed to that function.

    [SOLVED]

    Sorry. :(
     
  4. macrumors 6502

    #4
    Im guessing he's just just doing some basic data structure course in C at school, so he would be required to learn the basics of arrays first, before moving into structs. Clearly its not Objective-C or C++, so classes are out of the question :)
     
  5. macrumors 65816

    MarkCollette

    #5
    Yeah, you're probably right. Except it is C++, since he's using cin and cout :)
     
  6. macrumors G5

    gnasher729

    #6
    Never, ever use strncpy. It doesn't do what you think it does.

    When you copy into a buffer that is big enough, both strcpy and strncpy work fine. strcpy is better, because strncpy will _always_ fill the rest of the buffer with zeroes, which is painfully slow if you have a generously nice big buffer. If the buffer is not big enough, strcpy overwrites memory which will crash. strncpy doesn't overwrite memory, but it copies a string without the trailing '\0'. So if you try to use the result, _anything_ can happen. The result is, your program is likely to crash, but not where the bug is. Instead things will go wrong some time later.
     
  7. macrumors 65816

    #7
    This is a good point. I do rather wish that strncpy would return a pointer to the terminating \0 like stpcpy() does. It could return NULL if there isn't a terminating \0. I guess they wanted consistency with strcpy().
     
  8. macrumors 65816

    MarkCollette

    #8
    I didn't know that strncpy() padded with extra zeros if possible. But I do know that the simply workaround for potentially not adding the zero byte is to simply always have one extra slot at the end, and just put a '\0' in there, forcing termination.
     
  9. macrumors demi-god

    szark

    #9
    strncpy does exactly what I expect it to - allow me to copy a smaller string into the middle of a larger string without automatically truncating it. :)
     
  10. macrumors 65816

    Flynnstone

    #10
    Could this be part of the reason that Windows software seems to be prone to buffer overrun problems?
     
  11. macrumors 68000

    savar

    #11
    Strange advice... most security experts would say exactly the opposite. Copying data without doing bounds checking is dangerous, especially if that data was supplied by a user. Your program might not crash; it might smash the stack and then execute harmful shell code.
     
  12. macrumors 65816

    MarkCollette

    #12
    I think the piont of that bad advice was that it's better for a situation to fail fast, at development time, then limp on into production.
     
  13. macrumors member

    #13
    If writing outside a buffer was guaranteed to crash your app, yes. But it is not. Check your bounds and use strncpy:)

    Wittegijt.
     
  14. macrumors 65816

    MarkCollette

    #14
    True, but you can typically turn on array bounds checking when developing.
     
  15. macrumors G5

    gnasher729

    #15
    Security experts will tell you that strncpy lulls you into a false sense of security. You think you are secure but you are not. Now in reality you either make sure that the destination buffer is big enough before you call strcpy (in which case strncpy is pointless), or you write a function yourself that will do something sensible, unlike what strncpy does, if there is not enough space.

    Lets say dst has space for ten chars. If you just call

    strncpy (dst, src, 10);
    len = strlen (dst);

    strncpy won't overwrite anything, but len can be greater than 10, or the call to strlen can even crash, so strncpy doesn't gain anything. Any use of strncpy in some code makes me very, very worried.
     
  16. macrumors G5

    gnasher729

    #16
    Good idea. What compiler switch do I use for that in XCode?
     
  17. macrumors G5

    gnasher729

    #17
    It can be worse.

    Say you have a struct

    typedef struct { char c [12]; int n; } mystruct;

    and call strncpy (c, "this is a very very long string", 12);

    On a PowerPC, the next byte in memory following the array c is the most significant byte of n. As long as 0 <= n <= 16000000 or so, the most significant byte of n is a zero, so there is a zero byte following the array c and c will behave as if it contained a valid string of 12 characters plus a trailing zero.

    Compile your code for an Intel Macintosh. The next byte in memory following array c is now the least significant byte of n. If n has a value from 1 to 255, c doesn't behave like a string of 12 characters anymore. This is a great opportunity for a bug in your program that only happens in an Intel version, and is an absolute nightmare to find.

    For example:

    mystruct s;
    strncpy (s.c, "This is a very very long string", sizeof (s.c));
    for (s.n = 1; s.n <= 255; ++s.n)
    if (strchr (s.c, s.n) != NULL)
    printf ("s.c contains the character %c\n". s.n);

    On a PowerPC, it will print that s.c contains the letters T, h, i, s, space, a, v and e. On an Intel Mac, it will print that s.c contains _all_ 255 letters which is strange because strlen (s.c) will return 12 after the loop is finished.
     
  18. macrumors 6502a

    #18

    strncpy isn't useless. Like szark said, you can use it to copy one string into a portion of another string, ie strncpy( dst, src, strlen( src ) )

    In your above code if dst plays the role of a C string, ie is null terminated and is 10 characters long including the null character, then doing:-

    strncpy( dst, src, 10 )

    is a silly thing to do and it's the programmers fault and not strncpy() when the null character is overwritten.

    b e n
     
  19. macrumors 65816

    MarkCollette

    #19
    Not if you actually do what I said to do in this post.

    Code:
    typedef struct { char c [13]; int n; } mystruct; 
    
    strncpy (mystruct.c, "this is a very very long string", 12);
    mystruct.c[12] = '\0';
    
     
  20. macrumors 68020

    pilotError

    #20
    If your really worried about buffer overflows, and your string is null terminated, you can just use sizeof()

    strncpy(mystruct.c, "this is a very very long string", sizeof(mystruct.c) - 1);

    I though the GNU compilers deprecated a bunch of the original string copy functions and provided alternatives to avoid the whole buffer overflow thing.

    I did a quick man check and didn't see them.

    I also see a mac specific strlcpy in the man pages.
     
  21. macrumors 68030

    Catfish_Man

    #21
    Or we could just STOP USING C FOR GENERAL APPLICATION PROGRAMMING and save ourselves multiple huge classes of bugs, as well as speeding up development. It's a system programming language, folks. It's not suited for string processing. :mad:
     
  22. macrumors G5

    gnasher729

    #22
    You didn't think this through, did you?

    If mystruct.c has n bytes, then the first n-1 bytes will be filled with data from the string, the last byte has its previous, probably unspecified value. So the behavior now depends on whatever was at that memory location earlier, which is generally unpredictable and may for example depend on which compiler optimisations you have turned on. This can give you another debugging nightmare: The possibility that a bug only turns up in a release version and doesn't happen in your debugging version.
     
  23. macrumors G5

    gnasher729

    #23
    That was the point of my first post: Don't use strncpy. Yes, it is not its fault that it is ugly and useless, just don't use it.
     
  24. macrumors 6502a

    #24
    I think the whole point was, that with mystruct.c[12] = '\0'; (as MarkCollete suggested) then strncpy(mystruct.c, "this is a very very long string", sizeof(mystruct.c) - 1); is fine.

    Just my opinion but your examples for not using strncpy look like example of bad progamming technique/errors/bugs. You might as well say strcpy is a security problem because somebody might do this:-

    Code:
    char* fish = malloc( 20 ) ;
    …
    …
    strcpy( fish, "a very long message that will spill over fish" ) ;
    
    Anyway, not everybody uses strncpy to copy 'whole' C strings, and not all strings are null terminated.

    b e n

    EDIT: Also in some secure situations (though I admit I've never had to do this myself), it's important to overwrite the previous contents of strings so as not to leave keys etc in memory.
     
  25. macrumors 68020

    pilotError

    #25
    My point was if you wanted to avoid the buffer overflows, use the sizeof. I think he's capable of null terminating the string.

    Then again, None of us should be programming in C, its a systems programming language you know! :p

    Good quote from the Red Hat man pages:

     

Share This Page