数组和指针的特殊关系可以扩展到C-风格字符串。请看下面的代码:
- char flower[10] = "rose";
- cout << flower << "s are red\n";
数组名是第一个元素的地址,因此cout语句中的flower是包含字符r的char元素的地址。cout对象认为char的地址是字符串的地址,因此它打印该地址处的字符,然后继续打印后面的字符,直到遇到空字符为止。总之,如果给cout提供一个字符的地址,则它将从该字符开始打印,直到遇到空字符为止。
前面的cout语句中最后一部分的情况如何呢?如果flower是字符串第一个字符的地址,则表达式“s are red\n”是什么呢?为了与cout对字符串输出的处理保持一致,这个用引号括起来的字符串也应当是一个地址。在C++中,用引号括起来的字符串像数组名一样,也是第一个元素的地址。上述代码不会将整个字符串发送给cout,而只是发送该字符串的地址。这意味着对于数组中的字符串、用引号括起额字符串常量以及指针所描述的字符串,处理的方式是一样的,都将传递它们的地址。与逐个传递字符串中的所有字符相比,这样的工作量确实要少。
注意:在cout和多数C++表达式中,char数组名、char指针以及用引号括起来的字符串常量都被解释为字符串第一个字符的地址。
- //4.20演示了如何使用不同形式的字符串
- #include
- #include
//declare strlen()、strcpy() - using namespace std;
-
- int main()
- {
- char animal[20] = "bear"; //char数组
- const char *bird = "wren"; //指向char的指针变量,将“wren”的地址赋给了指针bird
- char *ps; //指向char的指针变量,未被初始化,不指向任何字符串(这通常是个坏主义)
- //创建未初始化的指针有点像签发空头支票:无法控制它将被如何使用
-
- //对于cout来说,使用数组名animal和指针bird是一样的。它们都是字符串的地址
- cout << animal << " and " << bird << endl << endl;
-
- //试图将信息读入ps指向的位置将更糟。由于ps没有被初始化,因此并不知道信息将被存储在哪里,这甚至可能改写内存中的信息。
- //要避免这种问题很容易——只要使用足够大的char数组来接收输入即可。请不要使用字符串常量或未被初始化的指针来接收输入。
- cout << "Enter a kind of animal: ";
- cin >> animal;
- ps = animal; //复制地址,两个指针将指向相同的内存单元和字符串
- cout << ps << "!\n\n";
- //一般来说,如果给cout提供一个指针,它将打印地址。但如果指针的类型为char*,则cout将显示指向的字符串,如上一行代码。
- //如果要显示字符串的地址,则必须将这种指针强制转换为另一种指针类型,如int*。如下面的代码。
- cout << "Before using strcpy():\n"; //strcpy()将字符串从一个位置复制到另一个位置
- cout << animal << " at " << (int *)animal << endl;
- cout << ps << " at " << (int *)ps << endl << endl;
-
- ps = new char[strlen(animal) + 1]; //get new storage,strlen返回字符串的长度,即确定字符串的长度,并将它+1来获得包含空字符时该字符串的长度
- strcpy(ps, animal);
- cout << "After using strcpy():\n"; //strcpy()将字符串从一个位置复制到另一个位置
- cout << animal << " at " << (int *)animal << endl;
- cout << ps << " at " << (int *)ps << endl << endl;
- delete[] ps;
-
- system("pause");
- return 0;
- }