2011年5月15日星期日

  读书日记--C++ 程序设计语言(2)

1.字符串文字量的类型是”适当个数的const字符的数组”

char* p = "char";

p[1] = ‘a’;

这样做在编译期不会发现错误,运行时报错。

2.

char* p1 = "char”;

char* p2 = "char”;

具有相同的地址空间;

p1 == p2

如果想修改,可以复制到数组里,

void f()
{
    char p[] = "char";
    p[1] = 'a';
}
//copy string to an array then you can change it.

如果是字符串数组,有不同的地址:

   1: void f()
   2: {   
   3:      char p1[] = "char";   
   4:      char p2[] = "char";   
   5:  if(p1 == p2)   
   6:  {       
   7:      printf("also equal\n");    
   8:   }
   9: }
  10: //p1 和p2 的地址不同。

3. 到数组的指针

   1: void f()
   2: {
   3:     char v[] = "abcdef";
   4:     char* p = v;//存在从数组到指针的隐式转换
   5:     int len = strlen(v);
   6:     int len_p =strlen(p);
   7:     //v = p;// 错误不存在 从指针到数组char[]的隐式转换
   8: }

数组参数被隐式的转换到指针,这也意味着对于被调用的函数而言,数组的大小就会被丢掉。这就要求被调函数需要以某种方式去确定数组的大小,以便完成各种有意义的操作。strlen(p) 以 0作为结束来确定字符串的大小。

4.两种遍历数组的方法

   1: //数组下标
   2: void fi(char v[])
   3: {
   4:     for (int i = 0; v[i] != '0'; i ++)
   5:     {
   6:         use(v[i]);
   7:     }
   8: }
   9: //指针形式
  10: void fp(char v[])
  11: {
  12:     for(char* p = v; *p != 0; p ++)
  13:     {
  14:         use(*p);
  15:     }
  16: }

两种方式没有好坏之分。

假设 p 是指向 T类型的指针如:则 p 和 p +1 之间的距离是 sizeof(T )

   1: void f()
   2: {
   3:     int vi[10];
   4:     short vs[10];
   5:     printf("0x%x, 0x%x\n", &vi[0], &vi[1]);// 两个指针直接的距离是 sizeof(vi[0]); 即sizeof(int)
   6:     printf("0x%x, 0x%x\n", &vs[0], &vs[1]);// sizeof(short)
   7:  
   8: }
   9: //0x12fe08, 0x12fe0c
  10: //0x12fdec, 0x12fdee

数组没有自描述性,因此如果要遍历一个数组,需要提供该数组的大小。

   1: void f(char v[], unsinged int size)
   2: {
   3:     ....
   4: }

5. 常量

6. 引用

一个引用就是某个的对象的另一个名字。引用的主要用途是为了描述函数的参数和函数的返回值,特别是为了运算符的重载。记法X&表示到X的引用。

对”普通”T&的初始式必须是一个类型T的左值。

对一个const T& 的初始式不必是一个左值,甚至可以不是类型T的;在这种情况下:

[1] 首先,如果需要将应用到T的隐式类型转换;

[2] 而后将结果存入一个类型T的临时变量。

[3] 最后,将此临时变量用作初始式的值。

   1: void f()
   2: {
   3:     //double& dr = 1.0;// 错误,要求是左值
   4:     const double& cdr =1;
   5: }

对于后一个初始化的解释:

   1: double temp = double(1);//首先建立一个具有正确值的临时变量
   2: const double& cdr = temp;//而后用这个临时变量作为cdr的初始式

一个比较好的引用使用为返回值的例子:

   1: #include <iostream>
   2: #include <vector>
   3: #include <string>
   4: using namespace std;
   5:  
   6: struct Pair{
   7:     string name;
   8:     double value;
   9: };
  10: vector<Pair> pairs;
  11: // Note return value is reference
  12: double& value(const string& s)
  13: {
  14:     for(int i = 0; i < pairs.size(); i ++)
  15:     {
  16:         if( s == pairs[i].name)return pairs[i].value;
  17:  
  18:     }
  19:     Pair p = {s, 0};
  20:     pairs.push_back(p);
  21:     return pairs[pairs.size() - 1].value;
  22: }
  23: void main(void) 
  24: {
  25:     string buf;
  26:     while(cin >> buf) value(buf) ++;
  27:  
  28:     for (vector<Pair>::const_iterator p = pairs.begin(); p != pairs.end(); p ++)
  29:     {
  30:         cout << p->name << ":" << p->value << endl;
  31:     }
  32:     system("pause");
  33: }

7. 指向void的指针

   sizeof(void)//错误

  sizeof(void*)//正确 4

一个指向任何对象类型的指针都可以赋值给类型为void*的变量,void*可以赋值给另一个void*,两个void* 可以比较是否想到,而且可以显示的将void*转换为另一个类型。

void* 的最重要用途是需要将函数传递一个指针,而又不能对对象的类型做任何假设。还有就是从函数返回一个无类型的对象。要使用这样的对象,必须通过显示的类型转换。

8.结构体

一个struct是任意类型元素的聚集。

注意加分号。

用于对数组的初始化列表形式记法也适用于结果类型变量的初始化。

结构类型对象的大小未必是其成员的大小之和,这是因为许多机器上要求将确定类型的对象分配在某种与机器的系统结构有关的边界上。在这类机器上,对象被称为具有对齐的性质,对齐会造成结构中出现空洞,你可以通过简单的从大到小排列成员,以取得最小的空间浪费,但是,最好还是按照可读性去排列他们,只在那些必须优化的地方按大小将他们排序。

两个结构总是不同的类型,即使他们有相同的成员。

没有评论:

发表评论