BE —— C++

2018-09-30  本文已影响0人  不知道的是

Storage classes

#include <iostream>

using namespace std;

int x;

int main()
{
    int y; // automatic storage

    cout << "The value of x is " << x << endl; // 0

    cout << "The value of y is " << y << endl; // undetermined value -- 4354366

    {
        int y;
        cout << "The value of x is " << x << endl; // 0
        cout << "The value of y ( inner ) is " << y << endl; // undetermined value -- 7208852
    }

    return 0;
}
#include <iostream>

namespace foo
{
    int x;
}

int main()
{
    std::cout << foo::x; // 0
    
    return 0;
}

http://www.cplusplus.com/doc/tutorial/namespaces/

Multidimensional arrays

Multidimensional arrays are not limited to two indices (i.e., two dimensions). They can contain as many indices as needed. Although be careful: the amount of memory needed for an array increases exponentially with each dimension. For example:

char century [100][365][24][60][60];

declares an array with an element of type char for each second in a century. This amounts to more than 3 billion char! So this declaration would consume more than **3 gigabytes of memory!

http://www.cplusplus.com/doc/tutorial/arrays/

pointer

// my first pointer
#include <iostream>
using namespace std;

int main ()
{
  int firstvalue, secondvalue;
  int * mypointer;
  cout << mypointer << endl; // 0x42719e

  mypointer = &firstvalue; // 将变量 firstvalue 的内存地址赋值给指针 mypointer
  cout << mypointer << endl; // 0x42719e
  *mypointer = 10; // 修改变量 firstvalue 的值
  cout << "mypointer " << mypointer << endl;
  mypointer = &secondvalue; // 将变量 secondvalue 的内存地址赋值给 mypointer
  cout << "mypointer " << mypointer << endl;
  *mypointer = 20; // 修改变量 secondvalue 的值
  cout << "firstvalue is " << firstvalue << '\n';
  cout << "secondvalue is " << secondvalue << '\n';
  return 0;
}
// more pointers
#include <iostream>
using namespace std;

int main ()
{
  int firstvalue = 5, secondvalue = 15;
  int * p1, * p2;

  cout << "int * p1; " << p1 << endl; // int * p1; 0x4273fe
  cout << "int * p2; " << p2 << endl; // int * p2; 0x6eff94

  p1 = &firstvalue;  // p1 = address of firstvalue
  cout << "p1 = &firstvalue; " << p1 << endl; // p1 = &firstvalue; 0x6efef0

  p2 = &secondvalue; // p2 = address of secondvalue
  cout << "p2 = &secondvalue; " << p2 << endl; // p2 = &secondvalue; 0x6efeec

  *p1 = 10;          // value pointed to by p1 = 10
  cout << "*p1 = 10; " << *p1 << endl; // *p1 = 10; 10

  *p2 = *p1;
  cout << "*p2 = *p1; " << *p2 << endl; // *p2 = *p1; 10
  cout << "firstvalue is " << firstvalue << endl; // firstvalue is 10
  cout << "secondvalue is " << secondvalue << endl; // secondvalue is 10

  p1 = p2;           // p1 = p2 (value of pointer is copied)
  cout << "p1 " << p1 << endl; // p1 0x6efeec
  cout << "p2 " << p2 << endl; // p2 0x6efeec

  bool bResult = p1 == p2 ? 1 : 0;
  cout << "p1 == p2 -> " << bResult << endl; // p1 == p2 -> 1

  *p1 = 20;          // value pointed to by p1 = 20
  cout << "*p1 = 20; " << *p1 << endl; // *p1 = 20; 20

  cout << "firstvalue is " << firstvalue << '\n'; // 10
  cout << "secondvalue is " << secondvalue << '\n'; // 20
  return 0;
}

http://www.cplusplus.com/doc/tutorial/pointers/

Pointers and arrays

Pointers and arrays support the same set of operations, with the same meaning for both. The main difference being that pointers can be assigned new addresses, while arrays cannot.

In the chapter about arrays, brackets ([]) were explained as specifying the index of an element of the array. Well, in fact these brackets are a dereferencing operator known as offset operator. They dereference the variable they follow just as * does, but they also add the number between brackets to the address being dereferenced. For example:
( 在关于数组的章节中,括号([])被解释为指定数组元素的索引。 实际上,这些括号是一个称为偏移运算符的解除引用运算符。 它们取消引用它们所遵循的变量,就像 * 一样,但它们也将括号之间的数字添加到被解除引用的地址。 )

a[5] = 0; // a [offset of 5] = 0
*(a+5) = 0; // pointed to by (a+5) = 0  

These two expressions are equivalent and valid, not only if a is a pointer, but also if a is an array. Remember that if an array, its name can be used just like a pointer to its first element.

#include <iostream>

using namespace std;

int main()
{
    int price [5] {100, 1};

    int id;

    int * myPointer;

    // Remember that if an array, its name can be used just like a pointer to its first element.

    cout << "price: " << price << endl; // 0x6dfee4

    cout << "&price: " << &price << endl; // 0x6dfee4

    cout << "*price: " << *price << endl; // 100 ( the first element of array price )

    cout << "myPointer: " << myPointer << endl; // 0x42725e

    cout << "id: " << id << endl; // 1968163360 ( automatic storage / undetermined value )

    cout << "&id: " << &id << endl; // 0x6dfee0

    id = 1;

    int * ptID = &id;

    cout << "*ptID: " << *ptID << endl; // 1

    /*
     * error: invalid conversion from 'int' to 'int*' [-fpermissive]
     *
     * myPointer = id; ( myPointer -> pointer type ) ( id -> int type )
     * cout << myPointer << endl;
     * https://stackoverflow.com/questions/42875580/invalid-type-argument-of-unary-have-int-error-in-c
     */

    myPointer = &id;

    cout << "myPointer: " << myPointer << endl; // 0x6dfee0

    cout << "*myPointer: " << *myPointer << endl; // 1

    myPointer = price;

    cout << "myPointer: " << myPointer << endl; // 0x6dfee4

    cout << "*myPointer: " << *myPointer << endl; // 100

    /*
     * error: lvalue required as increment operand
     *
     * cout << "++price: " << ++price << endl;
     * cout << "price++: " << price++ << endl;
     */

    return 0;
}
#include <iostream>

using namespace std;

int main()
{
    int myArray [5];

    cout << myArray << endl; // 0x6dfeec ( 7208684 )

    cout << myArray[0] << endl; // 1968139194

    cout << &myArray[0] << endl; // 0x6dfeec ( 7208684 )

    cout << &myArray[1] << endl; // 0x6dfef0 ( 7208688 )

    cout << &myArray[2] << endl; // 0x6dfef4 ( 7208692 )

    cout << &myArray[3] << endl; // 0x6dfef8 ( 7208696 )

    cout << &myArray[4] << endl; // 0x6dfefc ( 7208700 )

    return 0;
}
#include <iostream>

using namespace std;

int main()
{
    int myArray [5] {0, 1, 2, 3, 4};

    int * myPointer;

    myPointer = myArray;

    cout << "myPointer: " << myPointer << endl; // 0x6dfee0

    bool bRes = myPointer == myArray ? true : false;

    cout << "bRes: " << bRes << endl; // 1

    *myPointer = 10;

    cout << "++myPointer: " << ++myPointer << endl; // 0x6dfee4

    cout << "myPointer: " << myPointer << endl; // 0x6dfee4

    *myPointer = 20;

    cout << "++myPointer: " << ++myPointer << endl; // 0x6dfee8

    cout << "myPointer: " << myPointer << endl; // 0x6dfee8

    *myPointer = 30;

    cout << "++myPointer: " << ++myPointer << endl; // 0x6dfeec

    cout << "myPointer: " << myPointer << endl; // 0x6dfeec

    *myPointer = 40;

    cout << "++myPointer: " << ++myPointer << endl; // 0x6dfef0

    cout << "myPointer: " << myPointer << endl; // 0x6dfef0

    *myPointer = 50;

    cout << sizeof(myPointer) << endl; // 4 bytes

    cout << sizeof(1) << endl; // 4 bytes ( 0000 0000 0000 0000 0000 0000 0000 0001 )

    cout << myPointer << endl; // 0x6dfef0 ( address of myArray[4] )

    for (int i = 0; i < 5; i++)
    {
        cout << "myArray[" << i << "]: " << myArray[i] << endl;
        /*
         * myArray[0]: 10
         * myArray[1]: 20
         * myArray[2]: 30
         * myArray[3]: 40
         * myArray[4]: 50
         */
    }

    return 0;
}
#include <iostream>

using namespace std;

int main()
{
    int myArray [5] {0, 1, 2, 3, 4};
    int * myPointer;
    myPointer = myArray;

    cout << myPointer << endl; // 0x6dfee8

    cout << myPointer[3] << endl; // 3

    *(myPointer + 3) = 30;

    cout << myPointer[3] << endl; // 30

    cout << &myPointer[3] << endl; // 0x6dfef4

    return 0;
}
#include <iostream>

using namespace std;

int main()
{
    int myArray [5] {0, 1, 2, 3, 4};

    int * myPointer;

    // Pointers and arrays support the same set of operations, with the same meaning for both.

    *(myArray + 4) = 40; // equal to ( myArray[4] = 40 )

    cout << "myArray[4]: " << myArray[4] << endl;

    return 0;
}

Pointer initialization

#include <iostream>

using namespace std;

int main()
{
    int myVar;

    int * myPointer = &myVar;

    cout << &myVar << endl; // 0x6dfef8

    cout << myPointer << endl; // 0x6dfef8

    int * myPointer2;

    *myPointer2 = &myVar; // error: invalid conversion from 'int*' to 'int' [-fpermissive]

    return 0;
}

Pointers can be initialized either to the address of a variable (such as in the case above), or to the value of another pointer (or array):

#include <iostream>

using namespace std;

int main()
{
    /*
     * Pointers can be initialized either to the
     * address of a variable (such as in the case above),
     * or to the value of another pointer (or array):
     */

    int age;
    int * myPointer1 = &age;

    int * myPointer2 = myPointer1; // ( myPointer pointer type )

    int * myPointer3 = myPointer2;

    cout << "&age: " << &age << endl; // 0x6dfef0

    cout << "myPointer1: " << myPointer1 << endl; // 0x6dfef0

    cout << "myPointer2: " << myPointer2 << endl; // 0x6dfef0

    cout << "myPointer3: " << myPointer3 << endl; // 0x6dfef0

    return 0;
}

Pointer arithmetics

Regarding the increment ( ++ ) and decrement ( -- ) operators, they both can be used as either prefix or suffix of an expression, with a slight difference in behavior: as a prefix, the increment happens before the expression is evaluated, and as a suffix, the increment happens after the expression is evaluated. This also applies to expressions incrementing and decrementing pointers, which can become part of more complicated expressions that also include dereference operators ( * ).

Remembering operator precedence rules, we can recall that postfix operators, such as increment and decrement, have higher precedence than prefix operators, such as the dereference operator ( * ).
( 记住运算符优先级规则,我们可以回想一下,后缀运算符(如递增和递减)的优先级高于前缀运算符,例如解除引用运算符 ( * ) )

#include <iostream>

using namespace std;

int main()
{
    int myArray [5] {0, 10, 20, 30, 40};

    int * myPointer;

    myPointer = myArray;

    cout << "myPointer: " << myPointer << endl; // 0x6dfee8

    cout << "myArray: " << myArray << endl; // 0x6dfee8

    // same as *(p++): increment pointer, and dereference unincremented address
    *myPointer++;

    cout << "myPointer: " << myPointer << endl; // 0x6dfeec

    cout << "*myPointer: " << *myPointer << endl; // 10

    // same as *(++p): increment pointer, and dereference incremented address
    *++myPointer;

    cout << "myPointer: " << myPointer << endl; // 0x6dfef0

    cout << "*myPointer: " << *myPointer << endl; // 20

    // same as ++(*p): dereference pointer, and increment the value it points to
    ++*myPointer;

    cout << "myPointer: " << myPointer << endl; // 0x6dfef0

    cout << "*myPointer: " << *myPointer << endl; // 21

    // dereference pointer, and post-increment the value it points to
    (*myPointer)++;

    cout << "myPointer: " << myPointer << endl; // 0x6dfef0

    cout << "*myPointer: " << *myPointer << endl; // 22

    return 0;
}

To conduct arithmetical operations on pointers is a little different than to conduct them on regular integer types. To begin with, only addition and subtraction operations are allowed; the others make no sense in the world of pointers. But both addition and subtraction have a slightly different behavior with pointers, according to the size of the data type to which they point.

When fundamental data types were introduced, we saw that types have different sizes. For example: char always has a size of 1 byte, short is generally larger than that, and int and long are even larger; the exact size of these being dependent on the system. For example, let's imagine that in a given system, char takes 1 byte, short takes 2 bytes, and long takes 4.

#include <iostream>

int main()
{
    short * myshort; // short 2 bytes

    std::cout << myshort << std::endl; // 0x4270ae ( 4354222 )

    myshort++;

    std::cout << myshort << std::endl; // 0x4270b0 ( 4354224 )

    return 0;
}

0x4270ae -> 0x4270af ( One byte apart not a bit ? )

Pointers and const

Pointers can be used to access a variable by its address, and this access may include modifying the value pointed. But it is also possible to declare pointers that can access the pointed value to read it, but not to modify it. For this, it is enough with qualifying the type pointed to by the pointer as const. For example:

int x;
int y = 10;
const int * p = &y;
x = *p; // ok: reading p
*p = x; // error: modifying p, which is const-qualified 

Here p points to a variable, but points to it in a const-qualified manner, meaning that it can read the value pointed, but it cannot modify it. Note also, that the expression &y is of type int, but this is assigned to a pointer of type const int. This is allowed: a pointer to non-const can be implicitly converted to a pointer to const. But not the other way around! As a safety feature, pointers to const are not implicitly convertible to pointers to non-const.

#include <iostream>

using namespace std;

int main()
{
    int price = 20;
    const int * myPointer;

    myPointer = &price;

    cout << *myPointer << endl;

    *myPointer = 30; // error: assignment of read-only location '* myPointer'

    return 0;
}

As a safety feature, pointers to const are not implicitly convertible to pointers to non-const.

#include <iostream>

using namespace std;

int main()
{
    const int apples = 20;
    int oranges;

    const int * myptr;

    int * myptr2;

    myptr = &apples;

    // *myptr = 30; // error: assignment of read-only location '* myptr'

    oranges = *myptr; // oranges = 20

    oranges = 30;

    cout << oranges << endl; // 30

    cout << myptr << endl; // 0x6dfef4

    myptr2 = myptr; // error: invalid conversion from 'const int*' to 'int*' [-fpermissive] ( ☆☆☆☆☆ )

    cout << myptr2 << endl; // will not execute

    return 0;
}
// pointers as arguments:
#include <iostream>
using namespace std;

void increment_all (int* start, int* stop)
{
  int * current = start;
  while (current != stop) {
    ++(*current);  // increment value pointed
    ++current;     // increment pointer
  }
}

void print_all (const int* start, const int* stop)
{
  const int * current = start;
  while (current != stop) {
    cout << *current << '\n';
    // ++(*current); // error: increment of read-only location '* current'
    ++current;     // increment pointer
  }
}

int main ()
{
  int numbers[] = {10,20,30};

  cout << numbers << endl; // 0x6dfef4 ( 7208692 )

  cout << numbers + 3 << endl; // 0x6dff00 ( 7208704 )

  increment_all (numbers, numbers + 3);
  print_all (numbers, numbers + 3);

  return 0;
}

Note that print_all uses pointers that point to constant elements. These pointers point to constant content they cannot modify, but they are not constant themselves: i.e., the pointers can still be incremented or assigned different addresses, although they cannot modify the content they point to.

#include <iostream>

using namespace std;

int main()
{
    int age = 20;
    const int * myptr;

    myptr = &age;

    cout << myptr << endl; // 0x6dfef8

    // the pointers can still be incremented
    ++myptr;

    cout << myptr << endl; // 0x6dfefc

    const int * myptr2;

    myptr2 = myptr;

    cout << myptr2 << endl; // 0x6dfef8

    // *myptr2 = 30; // error: assignment of read-only location '* myptr2'

    int price = 200;

    // the pointers can still be assigned different addresses
    myptr = &price;

    cout << myptr << endl; // 0x6dfef0

    return 0;
}

And this is where a second dimension to constness is added to pointers: Pointers can also be themselves const. And this is specified by appending const to the pointed type (after the asterisk):

#include <iostream>

using namespace std;

int main()
{
    int x1;
    int x2;
    int x3;
    int x4;
          int *       p1 = &x1;  // non-const pointer to non-const int
    const int *       p2 = &x2;  // non-const pointer to const int
          int * const p3 = &x3;  // const pointer to non-const int
    const int * const p4 = &x4;  // const pointer to const int

    cout << "p1: " << p1 << endl; // p1: 0x6dfeec

    *p1 = 10;

    cout << "x1: " << x1 << endl; // x1: 10

    cout << "p2: " << p2 << endl; // p2: 0x6dfee8

    // *p2 = 20; // error: assignment of read-only location '* p2'

    p2 = p1;

    cout << "p2: " << p2 << endl; // p2: 0x6dfeec

    cout << "p3: " << p3 << endl; // p3: 0x6dfee4

    // p3 = &x1; // error: assignment of read-only variable 'p3'

    *p3 = 30;

    cout << "*p3: " << *p3 << endl; // *p3: 30

    cout << "p4: " << p4 << endl; // p4: 0x6dfee0

    // *p4 = 40; // error: assignment of read-only location '*(const int*)p4'

    return 0;
}

To add a little bit more confusion to the syntax of const with pointers, the const qualifier can either precede or follow the pointed type, with the exact same meaning:

const int * p2a = &x;  //      non-const pointer to const int
int const * p2b = &x;  // also non-const pointer to const int
上一篇下一篇

猜你喜欢

热点阅读