C++ strings: [] vs. *

后端 未结 6 1187
走了就别回头了
走了就别回头了 2020-12-02 09:22

Been thinking, what\'s the difference between declaring a variable with [] or * ? The way I see it:

char *str = new char[100];
char str2[] = \"Hi world!\";
<         


        
相关标签:
6条回答
  • 2020-12-02 09:29

    Let's look into it (for the following, note char const and const char are the same in C++):

    String literals and char *

    "hello" is an array of 6 const characters: char const[6]. As every array, it can convert implicitly to a pointer to its first element: char const * s = "hello"; For compatibility with C code, C++ allows one other conversion, which would be otherwise ill-formed: char * s = "hello"; it removes the const!. This is an exception, to allow that C-ish code to compile, but it is deprecated to make a char * point to a string literal. So what do we have for char * s = "foo"; ?

    "foo" -> array-to-pointer -> char const* -> qualification-conversion -> char *. A string literal is read-only, and won't be allocated on the stack. You can freely make a pointer point to them, and return that one from a function, without crashing :).

    Initialization of an array using a String literal

    Now, what is char s[] = "hello"; ? It's a whole other thing. That will create an array of characters, and fill it with the String "hello". The literal isn't pointed to. Instead it is copied to the character-array. And the array is created on the stack. You cannot validly return a pointer to it from a function.

    Array Parameter types.

    How can you make your function accept an array as parameter? You just declare your parameter to be an array:

    void accept_array(char foo[]); 
    

    but you omit the size. Actually, any size would do it, as it is just ignored: The Standard says that parameters declared in that way will be transformed to be the same as

    void accept_array(char * foo);
    

    Excursion: Multi Dimensional Arrays

    Substitute char by any type, including arrays itself:

    void accept_array(char foo[][10]);
    

    accepts a two-dimensional array, whose last dimension has size 10. The first element of a multi-dimensional array is its first sub-array of the next dimension! Now, let's transform it. It will be a pointer to its first element again. So, actually it will accept a pointer to an array of 10 chars: (remove the [] in head, and then just make a pointer to the type you see in your head then):

    void accept_array(char (*foo)[10]);
    

    As arrays implicitly convert to a pointer to their first element, you can just pass an two-dimensional array in it (whose last dimension size is 10), and it will work. Indeed, that's the case for any n-dimensional array, including the special-case of n = 1;

    Conclusion

    void upperCaseString(char *_str) {}; 
    

    and

    void upperCaseString(char _str[]) {};
    

    are the same, as the first is just a pointer to char. But note if you want to pass a String-literal to that (say it doesn't change its argument), then you should change the parameter to char const* _str so you don't do deprecated things.

    0 讨论(0)
  • 2020-12-02 09:29

    The first option dynamically allocates 100 bytes.

    The second option statically allocates 10 bytes (9 for the string + nul character).

    Your third example shouldn't work - you're trying to statically-fill a dynamic item.

    As to the upperCaseString() question, once the C-string has been allocated and defined, you can iterate through it either by array indexing or by pointer notation, because an array is really just a convenient way to wrap pointer arithmetic in C.


    (That's the simple answer - I expect someone else will have the authoritative, complicated answer out of the spec :))

    0 讨论(0)
  • 2020-12-02 09:33

    Okay, I had left two negative comments. That's not really useful; I've removed them.

    • The following code initializes a char pointer, pointing to the start of a dynamically allocated memory portion (in the heap.)
    
    char *str = new char[100];
    

    This block can be freed using delete [].

    • The following code creates a char array in the stack, initialized to the value specified by a string literal.
    
    char [] str2 = "Hi world!";
    

    This array can be modified without problems, which is nice. So

    
    str2[0] = 'N';
    cout << str2;
    

    should print Ni world! to the standard output, making certain knights feel very uncomfortable.

    • The following code creates a char pointer in the stack, pointing to a string literal... The pointer can be reassigned without problems, but the pointed block cannot be modified (this is undefined behavior; it segfaults under Linux, for example.)
    
    char *str = "Hi all";
    str[0] = 'N'; // ERROR!
    
    • The following two declarations
    
    void upperCaseString(char *_str) {};
    void upperCaseString(char [] _str) {};
    

    look the same to me, and in your case (you want to uppercase a string in place) it really doesn't matters.

    However, all this begs the question: why are you using char * to express strings in C++?

    0 讨论(0)
  • 2020-12-02 09:41

    Please also take a look at the http://c-faq.com/aryptr/aryptr2.html The C-FAQ might prove to be an interesting read in itself.

    0 讨论(0)
  • 2020-12-02 09:43

    The three different declarations let the pointer point to different memory segments:

    char* str = new char[100];
    

    lets str point to the heap.

    char str2[] = "Hi world!";
    

    puts the string on the stack.

    char* str3 = "Hi world!";
    

    points to the data segment.

    The two declarations

    void upperCaseString(char *_str) {};
    void upperCaseString(char _str[]) {};
    

    are equal, the compiler complains about the function already having a body when you try to declare them in the same scope.

    0 讨论(0)
  • 2020-12-02 09:44

    As a supplement to the answers already given, you should read through the C FAQ regarding arrays vs. pointers. Yes it's a C FAQ and not a C++ FAQ, but there's little substantial difference between the two languages in this area.

    Also, as a side note, avoid naming your variables with a leading underscore. That's reserved for symbols defined by the compiler and standard library.

    0 讨论(0)
提交回复
热议问题