`
clskkk2222
  • 浏览: 33854 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论
  • NeuronR: 引用因为用于向函数传递对象和从函数返回对象,该构造函数一般不应 ...
    复制构造函数

数组和指针

    博客分类:
  • C++
阅读更多

数组是由类型名、标识符和维数组成的复合数据类型

数组也是一种存储单一数据类型对象的容器,其中每个对象都没有单独的名字,而是通过它在数组中的位

置对它进行访问。
数组的长度是固定的,数组一经创建,就不允许添加新的元素。

Note:
数组的维数必须用值大于等于1的常量表达式定义
常量表达式只能包含整型字面值常量、枚举常量或者用常量表达式初始化的整型 const 对象。
非 const 变量以及要到运行阶段才知道其值的 const 变量都不能用于定义数组的维数。
(可能会引起不可预料的错误)

数组定义中的类型名可以是内置数据类型或类类型;
除引用之外,数组元素的类型还可以是任意的复合类型;
没有所有元素都是引用的数组.

如果没有显式提供元素初值,则数组元素会像普通变量一样初始化:
在函数体外定义的内置数组,其元素均初始化为 0。
在函数体内定义的内置数组,其元素无初始化。
不管数组在哪里定义,如果其元素为类类型,则自动调用该类的默认构造函数进行初始化;如果该类没有

默认构造函数,则必须为该数组的元素提供显式初始化。
显式初始化的数组不需要指定数组的维数值,编译器会根据列出的元素个数来确定数组的长度:

如果指定了数组维数,那么初始化列表提供的元素个数不能超过维数值。如果维数大于列出的元素初值个

数,则只初始化前面的数组元素;剩下的其他元素,若是内置类型则初始化为0,若是类类型则调用该类

的默认构造函数进行初始化

数组操作

数组下标从零开始,下标是数组元素到开始的偏移量.
数组中元素在内存中连续存放,低编号在低地址,高编号在高地址;

在用下标访问元素时,vector 使用 vector::size_type 作为下标的类型,而数组下标的正确类型则是

size_t

在使用数组时,也必须保证其下标值在正确范围之内,即数组在该下标位置应对应一个元素。

不允许数组直接复制和赋值
个数组不能用另外一个数组初始化,也不能将一个数组赋值给另一个数组

特殊的字符数组

字符数组既可以用一组由花括号括起来、逗号隔开的字符字面值进行初始化,也可以用一个字符串字面值

进行初始化。
字符串字面值包含一个额外的空字符(null)用于结束字符串。当使用字符串字面值来初始化创建的新数

组时,将在新数组中加入空字符

1.输入输出时字符数组名都处理成字符串,对字符变量的地址在输入输出时都会处理成字符串,只有字符

变量地址这样规定;
2.'\0'是字符串唯一合法的结束标志;
3.c++中字符串相比:
 (1)加头文件<string>,格式:变量名==“字符串”;相等为1,不等为0;==只比地址不比内

容;
 (2)加头文件<cstring>, 格式:strcmp(字串1,字串2);结果相等为0,不等结果随意;
4.以下操作需加 头文件<cstring>
 (1)strcpy(变量名,“字符串”):意为把字符串放入字符数组中,是覆盖
 (2)strcat(变量名,“字符串”):意为追加在字符数组后面,追加时需保证字符数组足够大

,以免越界;
 (3)strlen(数组名):计算字符串(不包含'\0')有多长;
5.char型数组输出:cout<< &a[2] << endl;表示从a[2]那个地址开始输出字符串;
6.输入字符串保存在数组中,并不要求输满规定的元素个数,空格或者回车判断输入结束;

字符串字面值的类型就是 const char 类型、以空字符 null 结束的数组
C++ 语言通过(const)char*类型的指针来操纵 C 风格字符串
永远不要忘记字符串结束符 null
调用者必须确保目标字符串具有足够的大小
传递给标准库函数 strcat 和 strcpy 的第一个实参数组必须具有足够大的空间存放新生成的字符串
使用 strn 函数处理C风格字符串

使用标准库函数 strncat 和 strncpy 的诀窍在于可以适当地控制复制字符的个数。特别是在复制和串连

字符串时,一定要时刻记住算上结束符 null.

Note:
对大部分的应用而言,使用标准库类型 string,除了增强安全性外,效率也提高了,因此应该尽量避免

使用 C 风格字符串。

创建动态数组
C++ 语言则使用 new 和 delete 表达式在自由存储区(或堆)中分配存储空间.

new 表达式返回指向新分配数组的第一个元素的指针

动态分配数组时,如果数组元素具有类类型,将使用该类的默认构造函数实现初始化;如果数组元素是内

置类型,则无初始化.

可使用跟在数组长度后面的一对空圆括号,对数组元素做值初始化

对于动态分配的数组,其元素只能初始化为元素类型的默认值,而不能像数组变量一样,用初始化列表为

数组元素提供各不相同的初值。

允许动态分配空数组

C++ 虽然不允许定义长度为 0 的数组变量,但明确指出,调用 new 动态创建长度为 0 的数组是合法的

C++ 语言为指针提供 delete [] 表达式释放指针所指向的数组空间

如果遗漏了空方括号对,这是一个编译器无法发现的错误,将导致程序在运行时出错。

混合使用标准库类 string 和 C 风格字符串

通常,由于 C 风格字符串与字符串字面值具有相同的数据类型,而且都是以空字符 null 结束,因此可

以把 C 风格字符串用在任何可以使用字符串字面值的地方:

可以使用 C 风格字符串对 string 对象进行初始化或赋值。
string 类型的加法操作需要两个操作数,可以使用 C 风格字符串作为其中的一个操作数,也允许将 C

风格字符串用作复合赋值操作的右操作数。

反之则不成立:在要求C风格字符串的地方不可直接使用标准库 string 类型对象。

string 类提供了一个名为 c_str 的成员函数,c_str 函数返回 C 风格字符串,其字面意思是:“返回

C 风格字符串的表示方法”,即返回指向字符数组首地址的指针,该数组存放了与 string 对象相同的内

容,并且以结束符 null 结束。
c_str 返回的指针指向 const char 类型的数组
 
使用数组初始化 vector 对象,必须指出用于初始化式的第一个元素以及数组最后一个元素的下一位置的

地址

多维数组
严格地说,C++ 中没有多维数组,通常所指的多维数组其实就是数组的数组

可以使用由花括号括起来的初始化式列表来初始化多维数组的元素。对于多维数组的每一行,可以再用花

括号指定其元素的初始化式

指针和多维数组
因为多维数组其实就是数组的数组,所以由多维数组转换而成的指针类型应是指向第一个内层数组的指针

用 typedef 简化指向多维数组的指针

#include <iostream>
#include <string>
#include <cstring>
#include <vector>
using namespace std;

int main()
{
    // int& ir[3]; error! declaration of `ir' as array of references 
    
    int ib[] = {0, 1, 2}; // an array of dimension 3
    
    const unsigned array_size = 5;
    // Equivalent to ia = {0, 1, 2, 0, 0}
    // ia[3] and ia[4] default initialized to 0
    int ia[array_size] = {0, 1, 2};
    for(size_t index=0; index!=array_size; ++index)
    {
         cout << ia[index] << " ";
    }
    cout << endl;
    
    // Equivalent to str_arr = {"hi", "bye", "", "", ""}
    // str_arr[2] through str_arr[4] default initialized to the empty string
    string str_arr[array_size] = {"hi", "bye"};
    for(size_t index=0; index!=array_size; ++index)
    {
         cout << str_arr[index] << endl;;
    }
    
    char ca1[] = {'C', '+', '+'};               // no null
    char ca2[] = {'C', '+', '+', '\0'};         // explicit null
    char ca3[] = "C++";                         // null terminator added automatically
    
    //const char ch3[6] = "Daniel";   error: Daniel has 7 elements
    
    cout << "ca1 : " << ca1 << endl; //maybe more than "c++" 
    cout << "ca2 : " << ca2 << endl;
    cout << "ca3 : " << ca3 << endl;
    cout << strlen(ca1) << endl;
    // int ia2[](ia);    error: cannot initialize one array with another
    // int ia3[array_size]; // ok: but elements are uninitialized!
    // ia3 = ia;           //  error:ISO C++ forbids assignment of arrays 
    
    char c1[] = "hello";

    cout << "cout << (int)c1 = " << (int)c1 << endl;
    cout << "cout << &c1[0] : " << &c1[0] << endl;
    cout << "cout << (int)&c1[0] = " << (int)&c1[0] << endl;
    cout << "cout << &c1[2] : " << &c1[2] << endl;
    cout << "cout << (int)&c1[2] = " << (int)&c1[2] << endl;
    
    memset(c1,0,sizeof(c1));
	cout << "after memset(c1,0,sizeof(c1)) ,c1 = " << c1 << endl;
	cout << "strlen(c1) = " << strlen(c1) << endl;
	
    const char *cp1 = "A string example";
    const char *cp2 = "A different string";
    int i = strcmp(cp1, cp2);    // i is positive
    cout << "strcmp(\"" << cp1 << "\",\"" << cp2 << "\") = " << i << endl;
    i = strcmp(cp2, cp1);        // i is negative
    cout << "strcmp(\"" << cp2 << "\",\"" << cp1 << "\") = " << i << endl;
    i = strcmp(cp1, cp1);        // i is zero
    cout << "strcmp(\"" << cp1 << "\",\"" << cp1 << "\") = " << i << endl;

    cout << "strlen(\"" << cp1 << "\") = " << strlen(cp1) << endl;
    cout << "strlen(\"" << cp2 << "\") = " << strlen(cp2) << endl;
    
    // Dangerous: What happens if we miscalculate the size of largeStr?
    char largeStr[16 + 18 + 2];         // will hold cp1 a space and cp2
    strcpy(largeStr, cp1);              // copies cp1 into largeStr
    strcat(largeStr, " ");              // adds a space at end of largeStr
    strcat(largeStr, cp2);              // concatenates cp2 to largeStr
    // prints A string example A different string
    cout << largeStr << endl;

    char largeStr2[16 + 18 + 2]; // to hold cp1 a space and cp2
    strncpy(largeStr2, cp1, 17); // size to copy includes the null
    strncat(largeStr2, " ", 2);  // pedantic, but a good habit
    strncat(largeStr2, cp2, 19); // adds at most 18 characters, plus a null
    cout << largeStr2 << endl;
    
    string *psa = new string[10]; // array of 10 empty strings
    int *pia = new int[10];       // array of 10 uninitialized ints
    for(size_t index=0; index != 10; ++index)
    {
         cout << pia[index] << endl;
    }
    delete [] psa;
    psa = 0;
    delete [] pia;
    pia = 0;

    //const int *pci_bad = new const int[100];  error: uninitialized const array
    const int *pci_ok = new const int[10]();// ok: value-initialized const array
    for(size_t index=0; index != 10; ++index)
    {
         cout << pci_ok[index] << endl;
    }
    delete [] pci_ok;
    pci_ok = 0;
    
    char *cp = new char[0]; // ok: but cp can't be dereferenced
    delete cp;
    cp = 0;
    
    string st = "OneNightInBeijing";
    const char *str = st.c_str(); // ok
    cout << str << endl;
    
    const size_t arr_size = 6;
    int int_arr[arr_size] = {0, 1, 2, 3, 4, 5};
    // ivec has 6 elements: each a copy of the corresponding element in int_arr
    vector<int> ivec(int_arr, int_arr + arr_size);
    for(vector<int>::iterator iter=ivec.begin(); iter!=ivec.end(); ++iter)
    {
         cout << *iter << endl;
    }
    
    int ima[3][4] = {     /*  3 elements, each element is an array of size 4 */
     {0, 1, 2, 3} ,   /*  initializers for row indexed by 0 */
     {4, 5, 6, 7} ,   /*  initializers for row indexed by 1 */
     {8, 9, 10, 11}   /*  initializers for row indexed by 2 */
    };
    for(size_t i=0; i!=3; ++i)
    {
      for(size_t j=0; j!=4; ++j)
      {
           cout << ima[i][j] << " ";
      }
      cout << endl;
    }
    cout << endl;
    int imb[][4] = {0,1,2,3,4,5,6,7,8,9,10,11}; //the same as ima
    for(size_t i=0; i!=3; ++i)
    {
      for(size_t j=0; j!=4; ++j)
      {
           cout << imb[i][j] << " ";
      }
      cout << endl;
    }
    cout << endl;
    // explicitly initialize only element 0 in each row
    int imc[3][4] = {{ 0 } , { 4 } , { 8 } };
    for(size_t i=0; i!=3; ++i)
    {
      for(size_t j=0; j!=4; ++j)
      {
           cout << imc[i][j] << " ";
      }
      cout << endl;
    }
    cout << endl;
    int imd[3][4] = {0 , 3, 6 , 9};
    for(size_t i=0; i!=3; ++i)
    {
      for(size_t j=0; j!=4; ++j)
      {
           cout << imd[i][j] << " ";
      }
      cout << endl;
    }
    cout << endl;
     
    int *imp1[4];   // array of pointers to int
    int (*imp2)[4]; // pointer to an array of 4 ints

    // array of size 3, each element is an array of ints of size 4
    int im[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};     
    
    typedef int int_array[4];
    int_array *itp = im;
    cout << itp[2][2] << endl;  //will print 11
    
    for (int_array *p = im; p != im + 3; ++p)
    {
        for (int *q = *p; q != *p + 4; ++q)
        {
          cout << *q << " ";
        }
        cout << endl;
    }
    cout << endl; 
    
    int (*mp)[4] = im; // ip points to an array of 4 ints
    cout << mp[1][0] << endl;   // will print 5
    mp = &im[1];       // ia[2] is an array of 4 ints
    cout << mp[1][0] << endl;   //will print 9
    
    return 0;   
}

 指针是指向某种类型对象的复合数据类型,用于指向对象,保存的是另一个对象的地址

每个指针都有一个与之关联的数据类型,该数据类型决定了指针所指向的对象的类型

C++ 语言使用 * 符号把一个标识符声明为指针

理解指针声明语句时,从右向左阅读

在定义指针变量时,可用空格将符号 * 与其后的标识符分隔开来

如果需要在一个声明语句中定义两个指针,必须在每个变量标识符前再加符号 * 声明:

指针可能的取值
一个有效的指针必然是以下三种状态之一:保存一个特定对象的地址;指向某个对象后面的另一对象;或

者是0值。若指针保存0值,表明它不指向任何对象。未初始化的指针是无效的,直到给该指针赋值后,才

可使用它。

避免使用未初始化的指针,很多运行时错误都源于使用了未初始化的指针。

如果可能的话,除非所指向的对象已经存在,否则不要先定义指针,这样可避免定义一个未初始化的指针

如果必须分开定义指针和其所指向的对象,则将指针初始化为 0。因为编译器可检测出 0 值的指针,程

序可判断该指针并未指向一个对象。

对指针进行初始化或赋值只能使用以下四种类型的值
1. 0 值常量表达式
2. 类型匹配的对象的地址
3. 另一对象末的下一地址
4. 同类型的另一个有效指针
   
初始化或赋值时必须保证类型匹配

C++ 提供了一种特殊的指针类型 void*,它可以保存任何类型对象的地址

void* 表明该指针与一地址值相关,但不清楚存储在此地址上的对象的类型。

void* 指针只支持几种有限的操作:
与另一个指针进行比较;
向函数传递 void* 指针或从函数返回 void* 指针;
给另一个 void* 指针赋值。

不允许使用 void* 指针操纵它所指向的对象。

指针操作
对指针进行解引用可访问它所指的对象,* 操作符(解引用操作符)将获取指针所指的对象

解引用操作符返回指定对象的左值

给指针直接赋值即可修改指针的值——不需要对指针进行解引用。

指针和引用的比较
1. 引用总是指向某个对象,定义引用时没有初始化是错误的
2. 给引用赋值修改的是该引用所关联的对象的值,而并不是使引用与另一个对象关联。引用一经初始化

,就始终指向同一个特定对象

指向指针的指针
指针占用内存空间存放其值,指针的存储地址可存放在指针中

使用指针访问数组元素

在表达式中使用数组名时,该名字会自动转换为指向数组第一个元素的指针

指针的算术操作
通常,在指针上加上(或减去)一个整型数值 n 等效于获得一个新指针,该新指针指向指针原来指向的

元素之后(或之前)的第 n 个元素。

指针的算术操作只有在原指针和计算出来的新指针都指向同一个数组的元素,或指向该数组存储空间的下

一单元时才是合法的。如果指针指向一对象,我们还可以在指针上加1从而获取指向相邻的下一个对象的

指针。

只要两个指针指向同一数组或有一个指向该数组末端的下一单元,C++ 还支持对这两个指针做减法操作

size_t 类型用于指明数组长度,它必须是一个正数;
ptrdiff_t 类型则应保证足以存放同一数组中两个指针之间的差距,它有可能是负数

允许在指针上加减 0,使指针保持不变
如果一指针具有 0 值(空指针),则在该指针上加 0 仍然是合法的,结果得到另一个值为 0 的指针
对两个空指针做减法操作,得到的结果仍是 0

解引用和指针算术操作之间的相互作用 

在指针上加一个整型数值,其结果仍然是指针。允许在这个结果上直接进行解引用操作,而不必先把它赋

给一个新指针
解引用操作符的优先级比加法操作符高

下标和指针
使用下标访问数组时,实际上是使用下标访问指针:

数组本质 <==> 指针 <==> 数组首地址

p[n] <==> *(p+n)
[]适用于所有的指针操作,本质上是指针的操作

数组名是常量,不需要初始化,不能再赋值

不管是什么类型的指针,它的大小都是4 byte(字节)

C++ 允许计算数组或对象的超出末端的地址,对此地址进行解引用操作读到的是垃圾数据

指针是数组的迭代器

指针和 const 限定符:指向 const 对象的指针和 const 指针

如果指针指向 const 对象,则不允许用指针来改变其所指的 const 值。为了保证这个特性,C++ 语言强

制要求指向 const 对象的指针也必须具有 const 特性,不能通过指向const对象的指针修改其所指对象

的值,但是该指针本身并不是 const。在定义时不需要对它进行初始化,如果需要的话,允许给 cptr 重

新赋值,使其指向另一个 const 对象。

不能使用 void* 指针保存 const 对象的地址,而必须使用 const void* 类型的指针保存 const 对象的

地址

允许把非 const 对象的地址赋给指向 const 对象的指针

不能使用指向 const 对象的指针修改基础对象,然而如果该指针指向的是一个非 const 对象,可用其他

方法修改其所指的对象。

不能保证指向 const 的指针所指对象的值一定不可修改,可以把指向 const 的指针理解为“自以为指向

const 的指针”。

在实际的程序中,指向 const 的指针常用作函数的形参。将形参定义为指向 const 的指针,以此确保传

递给函数的实际对象在函数中不因为形参而被修改。

const 指针——本身的值不能修改
与任何 const 量一样,const 指针也必须在定义时初始化。
const指针所指对象的值能否修改完全取决于该对象的类型。

任何企图给 const 指针赋值的行为(即使给 自己赋回同样的值)都会导致编译时的错误。

指向 const 对象的 const 指针
不能修改所指向对象的值,也不允许修改该指针的指向

#include <iostream>
#include <vector>
#include <string>
using namespace std;

int main()
{
    vector<int>   *pvec;      // pvec can point to a vector<int>
    int           *ip1, *ip2; // ip1 and ip2 can point to an int
    string        *ps;   // pstring can point to a string
    double        *dp;        // dp can point to a double
    
    cout << "sizeof(pvec) = " << sizeof(pvec) << endl;    // 4 
    cout << "sizeof(ip1) = " << sizeof(ip1) << endl;      // 4 
    cout << "sizeof(ps) = " << sizeof(ps) << endl; // 4
    cout << "sizeof(dp) = " << sizeof(dp) << endl;        // 4
          
    string* ps1, ps2;  // ps1 is a pointer to string,  ps2 is a string
    string* ps3, *ps4; // both ps1 and ps2 are pointers to string
    
    int ival = 1024;
    int *pi = 0;       // pi initialized to address no object
    int *pi2 = &ival;  // pi2 initialized to address of ival
    int *pi3;          // ok, but dangerous, pi3 is uninitialized
    pi = pi2;          // pi and pi2 address the same object, e.g. ival
    pi2 = 0;           // pi2 now addresses no object

    int zero = 0;
    const int c_ival = 0;
    
    //int *p = ival;   error: p initialized from int value of ival
    //pi = zero;       error: pi assigned int value of zero
    pi = c_ival;    // ok: c_ival is a const with compile-time value of 0
    pi = 0;         // ok: directly initialize to literal constant 0
    pi = NULL;      //ok: equivalent to int *pi = 0;
    
    double dval;
    double* pd = &dval;   // ok: initializer is address of a double
    double* pd2 = pd;     // ok: initializer is a pointer to double
    
    //int *pi2 = pd;    error: types of pi and pd differ
    //pi2 = &dval;      error: attempt to assign address of a double to int *

    int i = 1;
    void *pv = &i;
    cout << (int)pv << endl;
    //cout << *pv << endl;  error! void* is not a pointer-to-object type 
    
    string s("hello world");
    string *sp = &s;          // sp holds the address of s
    cout  << *sp << endl;     // prints hello world
    *sp = "goodbye";          // contents of s now changed
    cout  << *sp << endl;     // prints goodbye
    string s2 = "some value";
    sp = &s2;                 // sp now points to s2
    cout  << *sp << endl;     // prints some value
    
    pi = &ival; // pi points to an int
    int **ppi = π // ppi points to a pointer to int
    pi2 = *ppi; // ppi points to a pointer

    cout << "The value of ival\n"
         << "direct value: ival = " << ival << "\n"
         << "indirect value: *pi = " << *pi << "\n"
         << "doubly indirect value: **ppi = " << **ppi
         << endl;
    
    int ia[] = {0,2,4,6,8};
    int *ip = ia; // ip points to ia[0]
    
    cout << "ia = " << ia << endl;
    cout << "ip = " << ip << endl;
    ip = &ia[4];    // ip points to last element in ia
    cout << "ip = &ia[4], *ip = " << *ip << endl;
    
    ip = ia;
    int *ip3 = ip + 4;  // ok: ip2 points to ia[4], the last element in ia
    cout << "*ip3 = " << *ip3 << endl;
    
    ptrdiff_t n = ip3 - ip; // ok: distance between the pointers
    cout << "ip3 - ip = " << n << endl;
    
    cout << "ip + 0 = " << (ip + 0) << endl;  //ip unchanged
    cout << "ip - 0 = " << (ip - 0) << endl;  //ip unchanged
    
    int *np1 = 0;
    int *np2 = 0;
    cout << "np1 = " << np1 << endl;
    cout << "np2 = " << np2 << endl;
    cout << "np1 + 0 = " << (np1 + 0) << endl;
    cout << "np1 - np2 = " << (np1 - np2) << endl;
    cout << &np1 << endl;
    int *np3 = np1 + 0;
    cout << &(np3) << endl;   //another pointer whose value is 0
    
    int last = *(ia + 4); // ok: initializes last to 8, the value of ia[4]
    cout << "*(ia + 4) = " << last << endl;
    last = *ia + 4;      // assign last to ia[0] + 4 equal to (0+4)
    cout << "*ia + 4 = " << last << endl;
    
    int *p = &ia[2];     // ok: p points to the element indexed by 2
    cout << "p[1] = " << p[1] << endl;  // ok: p[1] equivalent to *(p + 1),
                                        //    p[1] is the same element as ia[3]
    cout << "p[-2] = " << p[-2] << endl;       // ok: p[-2] is the same element as ia[0]
    
    p = ia + 5;
    cout << "ia + 5 = " << *p << endl;
    
    const size_t arr_sz = 5;
    int int_arr[arr_sz] = { 0, 1, 2, 3, 4 };
    // pbegin points to first element, pend points just after the last
    for (int *pbegin = int_arr, *pend = int_arr + arr_sz; pbegin != pend; ++pbegin)
    {
      cout << *pbegin << ' '; // print the current element
    }
    cout << endl;
    
    const double *cptr;  // cptr may point to a double that is const
     
    const double pii = 3.14;
    //double *ptr = &pii;    error: ptr is a plain pointer
    cptr = &pii; // ok: cptr is a pointer to const
    
    const int universe = 42;
    const void *cpv = &universe; // ok: cpv is const
    //void *pv = &universe;      error: universe is const

    double d_val = 3.14; // d_val is a double; its value can be changed
    cptr = &d_val;       // ok: but can't change dval through cptr

    int errNumb = 0;
    int *const curErr = &errNumb; // curErr is a constant pointer
    //curErr = curErr;  error
    
    // pi_ptr is const and points to a const object
    const double *const pi_ptr = &pii;
    
    
    string ss = "snowing";
    typedef string *pstring;
    //const pstring cstr;  error !assignment of read-only variable `cstr' 
    const pstring cstr = &ss;  //ok
    cout << * cstr << endl;

    return 0;   
}

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics