C++ 数组和指针学习笔记(3)

八、指针和const限定符

指向const对象的指针

const double *cptr;    // cptr may point to a double that is const

const限定了cptr指针所指向的对象类型,而并非cptr本身。也就是说,cptr本身并不是const。

允许通过给cptr赋值,使其指向一个const对象,但不能通过cptr修改其所指向的对象的值。

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

const int universe = 42;
  const void *cpv = &universe;    // ok: cpv is const
  void *pv = &universe;        // error: universe is const

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

九、const指针

C++语言还提供了const指针——本身的值不能修改:

 int errNumb = 0;
  int *const curErr = &errNumb;    // curErr is a constant pointer
  curErr = curErr;            // error: curErr is a constant pointer

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

假设给出以下语句:

  typedef string *pstring;
  const pstring cstr;

请问cstr变量是什么类型:

 const string *pstring;    // wrong interpretation of const pstring cstr
  string *const cstr;        // equivalent to const pstring cstr,等价于这句话

C风格字符串

C风格字符串的标准库函数(要使用这些标准库函数,必须包含相应的C头文件:cstring)

strlen(s)       strcmp(s1, s2)      strcat(s1, s2) strcpy(s1, s2)    strncat(s1, s2, n)    strncpy(s1, s2, n)

注意:这些标准库函数不会检查其字符串参数

永远不要忘记字符串结束符null,调用者必须确保目标字符串具有足够的大小

如果必须使用C风格字符串,则使用标准库函数strncat和strncpy比strcat和strcpy函数更安全

  char largeStr[16 + 18 + 2];    // to hold cp1 a space and cp2
  strncpy(largeStr, cp1, 17);    // size to copy includes the null
  strncat(largeStr, " ", 2);   // pedantic, but a good habit
  strncat(largeStr, cp2, 19);    // adds at most 18 characters, plus a null

对大部分的应用而言,使用标准库类型string,除了增强安全性外,效率也提高了,因此应该尽量避免使用C风格字符串。
 
创建动态数组
 
动态数组的定义

 int *pia = new int[10];  // array of 10 uninitialized ints

new表达式返回指向新分配数组的第一个元素的指针
 
初始化动态分配的数组
 
可使用跟在数组长度后面的一对空圆括号,对数组元素做值初始化:

int *pia2 = new int[10]();  // array of 10 uninitialized ints

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

 // error: uninitialized const array
  const int *pci_bad = new const int[100];
  // ok: value-initialized const array
  const string *pci_ok = new const int[100]();

允许动态分配空数组

  char arr[0];              // error: cannot define zero-length array
  char *cp = new char[0];    // ok: but cp can't be dereferenced

用new动态创建长度为0的数组时,new返回有效的非零指针。该指针与new返回的其他指针不同,不能进行解引用操作,因为它毕竟没有指向任何元素。而允许的操作包括:比较运算,因此该指针能在循环中使用;在该指针上加(减)0;或者减去本身,得0值。
 
动态空间的释放
 
动态分配的内存最后必须进行释放,否则,内存最终将会逐渐耗尽。
 
使用数组初始化vector对象

 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> ivcec(int_arr, int_arr + arr_size);

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

#include <stdio.h> 
main() 
{ 
 static  int  a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}}; /* 定义一个3行4列的二维数组 */
 int  *p; 
 printf ("%d %d/n",a,*a); 
 printf ("%d %d/n",a[0],*(a+0)); 
 printf ("%d %d/n",&a[0],&a[0][0]); 
 printf ("%d %d/n",a[0][0],*(*(a+0)+0)); 
 for  (p=a[0];p<a[0]+12;p++) /* 把a[0]的地址赋予指针变量p,条件判断p<a[0]+12表示的是小于最后一个元素的地址; */
 { 
  if ((p-a[0])%4==0) /* 利用整数指针变量p减去当前地址判断出是不是已经显示出了四个值,换行回车 */
  { 
   printf ("/n"); 
  } 
  printf ("%4d",*p); /* 打印出元素的值 */
 } 
 printf ("/n"); 
} 
 
/* 
第 5行中的a和*a打印出来的值,就会让人弄不明白我们知道数组传递的地址那么a表示这个数组的其实地址为什么*a却不是实际值呢?原因是在多维数组中 a+0表示的是第0行的首地址,a+1表示是第一行的首地址,那么*a其实就是*(a+0),那么第一个元素其实是a[0][0]
而*(a+0) 仅仅是把一个3行4列的二维数组拆为了三个一维数组,*(a+0)显然表示的不是物理位置也就不可能得到第一个元素的值了,它仅仅是一个内存地址也就是第 0行的启始地址,再看8行中的*(*(a+0)+0),它表示的则是第0行第0列个元素的值也就是a[0][0],再次强调*(a+0)表示的是数组第一行的首地址,也就是第二行的*(a+1),而元素值要得到显然就是*(*(a+0)+0)了如果是第0行第1个也就是*(*(a+0)+1)。
*/

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/c27ac77ebd68c3300507a901ad95700a.html