简体   繁体   中英

C++ pointer to char arithmetic

If I add 1 to a pointer, the actual value added will be the size of the type that the pointer points to right? For example:

int* num[5];
cout << *num << ", " << *(num + 2) << endl; 

This will print the value stored at num[1] and at num[2], so num + 2 is actually num + 2*sizeof(int) if I'm not wrong.

Now, if I initialize an array of pointers to char to string literals, like this one:

char* ch[5] = 
{
     "Hi",
     "There",
     "I,m a string literal"
};

This can be done because a string literal like "hi" represents the address of its first character, in this case 'h'. Now my question is how can I write something like:

cout << *(ch + 2);

and get "I,ma string literal" as the output? Since the pointer points to char, shouldn't adding 2 to the pointer actually be (ch + 2*sizeof(char)) ? giving me the output 'There' ?

Does it have something to do with cout? Does cout search the memory of the pointed to values to see if it finds '\\0's recognizing the contents of the pointed to values as strings and then modifying pointer arithmetic? But then adding 1 to a pointer to char pointing to strings would mean adding different number of bytes (instead of the size of a char) everytime, since a string can be any size. Or am I totally wrong? I'm sorry I am new to C++, and programming in gerenal.

The array isn't storing char s, it's storing char * s. Hence saying ch + 2 will be equivalent to ch + 2*sizeof(char *) . You then dereference that, which is pointing to "I'm a string literal" .

Your initial example shows the confusion:

int* num[5];
cout << *num << ", " << *(num + 2) << endl; 

This is an array of pointers-to-int. Hence, *(num + 2) will be *(num + 2*sizeof(int *)) , not 2*sizeof(int) . Let's demonstrate this with a small program:

#include <iostream>

int main()
{
    int *num[3];
    int x, y, z;
    x = 1;
    y = 2;
    z = 3;

    num[0] = &x;
    num[1] = &y;
    num[2] = &z;

    std::cout << *(num + 2) << "\n";
}

This will print out a memory address (like 0x22ff28 ) because it is holding pointers, not values.

In C and C++, arrays and pointers are very similar (many books claim they are exactly the same. This is not -quite- true, but it is true in a lot of situations).

Your first example should be int num[5] . Then *(num + 2) (which is equivalent to num[2] ) will be equivalent to *(num + 2*sizeof(int) . Hopefully this clears up your confusion somewhat.

"If I add 1 to a pointer, the actual value added will be the size of the type that the pointer points to right?"

There's no guarantee in the C++ Standard that a pointer is the number of the byte of some memory where the pointer points to. If you add an integer n to a pointer, the result is a pointer to the n th next element in that array:

int iarr[10];
int* pi = iarr;  // pi points to iarr[0]
int* pi2 = pi+2; // pi2 points to iarr[2]

What you get when you look at, eg int repr = (int)pi; is not defined by the C++ Standard.

What will happen on the most popular platforms/implementations, is that

(int)pi2 == ((int)pi) + 2*sizeof(int)

When you have arrays of pointers, the exact same thing happens:

int* piarr[10];
int** ppi = piarr;     // ppi points to iarr[0]
int** ppi2 = piarr+2;  // ppi2 points to iarr[2]

Note that the type of piarr is array of 10 pointer to int , therefore the elements of that array have the type pointer to int . A pointer to an element of that array consequently has the type pointer to pointer to int .


char* ch[5] is an array of 5 pointers to char .

"Hello" etc. are (narrow) string literals. A (narrow) string literal is an array of n const char , where n is the length of the string plus 1 (for the terminating \\0 character). Arrays can be implicitly converted to pointers to the first element of the array, this is what happens here:

char* ch[5] = 
{
     "Hi",
     "There",
     "I,m a string literal"
};

The array ch contains three pointer to char . As those have been obtained by converting arrays to pointers, each of them points to the first element of an array of char : The pointer ch[0] (the first element of the array ch ) points to the first element of the array "Hi", ch[1] points to the first element of "There" and so on.

Note there's also a conversion involved from const char to char , which is deprecated and should be avoided. The better form would be:

char const* ch[5] = 
{
     "Hi",
     "There",
     "I,m a string literal"
};

The expression *(ch + 2) is interpreted as follows:

  • ch names that array (see above)
  • ch + 2 implicitly converts ch from array of 3 pointers to char to pointer to pointer to char , a pointer pointing to the first element of the array ch . The type of this expression therefore is pointer to pointer to char .
  • ch + 2 makes the pointer from the last step now point to the second next element; it pointed to the first element of ch , so it now points to the third element of the array ch .
  • *(ch + 2) finally, the * dereferences the pointer and "fetches" the object pointed to. The pointer created by ch + 2 points to the 3rd element of the array ch , therefore, this expression resolves into the third element of the array ch . The type of the expression now is pointer to char .

The result of the expression is passed to std::cout::operator<< . As the type of the expression is pointer to char , cout will print that string: the third element of the array ch .

Does it have something to do with cout?

No:

const char* cstrings[5] = 
{
    "Hi",
    "There",
    "I,m a string literal"
};

const char** x = cstrings + 2;
cout << *x << endl;

. .

But what can be confusing is that the << operator works differently when given a pointer to a cstring--instead of outputting the address, it outputs the string. Here is an example:

int x = 10;
int* pint = &x;

const char* pstr = "hello";

cout << pint << endl << pstr << endl;

--output:--
0x7fff5fbff85c  //hexidecimal string representation of an integer
hello

Since the pointer points to char,

1) The literal strings are stored in your array as pointers. That's why the type of the array is pointer.

2) Pointers are adresses in memory, which are just integers.

3) So your array of pointers is really an array of integers.

In C, a character is represented by the datatype char . It can hold any ASCII character and it ranges from 0 to 255. Moreover it uses a single byte of size.

A string, however, is represented by char* , which technically is an array of chars . There's a difference. A char is not the same as a char* . The former stores a single character, and the latter stores a memory direction which corresponds to the offset of the string.

Now, in your example, ch is not a char* but a char** . This is, it is an array of an array of chars , or better said, an array of strings. If we dereference ch once, as in *ch , we will get the first string: Hi . If we dereference it twice, as in **ch , we will get the first character of the first string: H . So, we can start working with pointer arithmetics!

cout << *(ch + 2) will output I,ma string literal

cout << **(ch + 1) will output T (first character of second string)

cout << *(*ch + 1) will output i (second character of first string)

Keep on working with these examples to understand better how characters and strings are output! It's all about pointer arithmetics!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM