《C和C++代码精粹》——2.9 字符串数组

2.9 字符串数组

C和C++代码精粹
有两种方式来描述C风格的字符串数组:(1)指针数组;(2)二维数组。程序清单2.13中的程序说明了第一种方式。内存分布如下:

程序清单2.13 用指向字符的指针数组来实现字符串

// array6.cpp:粗糙的数组
#include <iostream>
#include <cstring>
using namespace std;  

main()
{
    char*  strings[] = {"now","is","the","time"};
    size_t n = sizeof strings / sizeof strings[0];  

    //从粗糙的数组打印
    for (int i = 0; i < n; ++i)
        cout << "String " << i  <<" == \"" << strings[i]
             << "\",\tsize == " << sizeof strings[i]
             << ",\tlength == " << strlen(strings[i])
             << endl;
}  

//输出:
String 0 == "now",   size == 4,   length == 3
String 1 == "is",    size == 4,   length == 2
String 2 == "the",   size == 4,   length == 3
String 3 == "time",  size == 4,   length == 4

由于字符串可以有不同的长度,所以这一类型的数组有时被称为粗糙的(ragged)数组。这一方式仅使用了容纳数据所需的内存数量,再加上指向每个字符串的指针。运行时系统传递给main函数的命令行参数数组argv是一个粗糙的数组。

粗糙的数组方式的一个不利之处是,在大多数环境中,需要动态地为每个字符串分配内存(参见第20章)。如果你不介意浪费一小部分空间,而且如果你也知道会遇到的最长的字符串的长度,就可以使用一个固定大小的区域来存储二维字符数组(每行一个字符串)。程序清单2.14中数组的内存区域分布如下:

程序清单2.14 作为二维字符数组中的行来实现字符串

// array7.cpp: 在二维字符数组中存储字符串
#include <iostream>
#include <cstring>
using namespace std;  

main()
{
    char array[][5] = {"now","is","the","time"};
    size_t n = sizeof array / sizeof array[0];  

    for (int i = 0; i < n; ++i)
        cout << "array[" << i << "] == \"" << array[i]
             << "\",\tsize == " << sizeof array[i]
             << ",\tlength == " << strlen(array[i])
             << endl;
}  

//输出:
array[0] == "now",   size == 5,   length == 3
array[1] == "is",    size == 5,   length == 2
array[2] == "the",   size == 5,   length == 3
array[3] == "time",  size == 5,   length == 4

正如这个程序所表明的,如果多维数组的第一维能从它的初始化中推断出来,那么就不必具体指出多维数组的第一维。

在程序设计语言中C++在某种程度上是独一无二的,因为在使用数组时仅可以使用其部分下标。就像程序清单2.14中的程序所使用的那样,表达式array[i]是指向第i行的指针。对于一个定义为int a2[4]的数组,a[i]代表的是什么呢?而ai又是什么呢?请继续读下一节。

本文仅用于学习和交流目的,不代表异步社区观点。非商业转载请注明作译者、出处,并保留本文的原始链接。

时间: 2024-09-28 15:04:17

《C和C++代码精粹》——2.9 字符串数组的相关文章

《C和C++代码精粹》——2.8 数组作为参数

2.8 数组作为参数 C和C++代码精粹当你把数组作为参数传递给一个函数,正如所预期的那样,是传递了指向数组第一个元素的指针.因此,可以在调用的函数中永久地改变数组元素的值.在程序清单2.12的函数f中,地址&a[0]按值传递给指针b,因此表达式b[i]就和表达式a[i]完全是一样的了.不可能按值传一个完整的内置数组. 即使用数组符号定义了参数b,即: int b[] 它同下面这种写法是完全一样的. int *b 程序清单2.12 说明作为参数的数组实际上是指针 // array5.cpp: 数

《C和C++代码精粹》——2.7 指针和一维数组

2.7 指针和一维数组 C和C++代码精粹 在程序清单2.7中,会注意到在传递数组 s 时并没有使用它的地址,这是因为C和C++在大多数表达式中把数组名转换成指向它第一个元素的指针.自1984年以来,我已经向成百上千的学生讲授了C和C++,我注意到了指针和数组,特别是指针和多维数组之间的关系造成很多迷惑. 这样说似乎很奇怪,但是C++确实不支持数组,至少C++不像支持第一类数据类型如整型或者甚至结构体那样支持数组.考虑以下的语句: int i=1,j; int a[4]={0,1,2,3},b[

《C和C++代码精粹》——1.10 操纵器

1.10 操纵器 C和C++代码精粹 当标识符 endl出现在一个输出流中时,一个换行字符就被插入并且流被刷新.标识符endl是操纵器的一个例子,即为了副效应而插入到流的一个对象.在〈iostream〉中被声明的系统预定义的操纵器列于表 1.3中.程序清单1.11里的程序在功能上与程序清单1.10的程序等价,但它是用操纵器来代替显式调用setf函数.操纵器经常可以使代码更为高效. 表1.3 简单的操纵器(〈iostream〉) 程序清单1.11 用操纵器改变数据基数 // base2.cpp:

《C和C++代码精粹》——2.12 指向函数的指针

2.12 指向函数的指针 C和C++代码精粹 一个指针可以指向函数也可以指向存储的对象.下面的语句声明fp是一个指向返回值为整型(int)的函数的指针: int(*fp)( ); *ftp的圆括号是必需的,没有它的语句 int *fp( ); 将fp声明为一个返回指向整型(int)指针的函数.这就是将星号与类型声明紧密相连的方式成为逐渐受人们欢迎的方式的原因之一. int fp(); //方式说明fp()返回一个指向整型的指针(int ) 当然,这种方式建议你通常应该每条语句只声明一个实体,否则

《C和C++代码精粹》导读

前言 C和C++代码精粹 本书适合于那些C和C++的职业程序员.假如你已熟悉这两种语言的语法和基本结构,这本书能够为你创建有效的.实用的程序提供实践性的指导.每一个代码范例或程序范例均标明行之有效的用法和技术,这些用法和技术对C/C++这两种重要编程语言的性能发挥起着重要的作用. 对于那些希望在工作中加强自身技术和提高效率的人来说,本书可以算是一本经验之谈.尽管目前人们对面向对象模式的推崇到了白热状态(本书也包括这方面的丰富内容),可是我没有理由不对C++的基础-C表示尊崇.我发现太多的程序开发

《C和C++代码精粹》——1.8 标准流

1.8 标准流 C和C++代码精粹C++中有4个预定义的流:cin(标准输入),cout(标准输出),cerr(标准错误),clog(标准错误).除了cerr外其余都是全缓冲流.就像stderr一样,cerr的行为好象是非缓冲的,但事实上它是单元缓冲的,也就是说它在处理完每一个对象而不是每一个字节后会自动清除缓冲.例如,带有单元缓冲的语句: cerr<<"hello":缓冲处理5个字符,然后清除缓冲区.一个非缓冲处理的流会立即发送每个字符到它的最终目的地. 程序清单1.5

《C和C++代码精粹》——2.15 小结

2.15 小结 C和C++代码精粹C和C++仅仅与那些使用它们的人一样危险.指针是地址.可以将任何一个指针赋值成void*.注意区分一个const指针和一个指向const的指针.p±n = =(char)p±n sizeof (*p).p-q = = ±n .*(a+i) = = a [i].除非在sizeof和&的上下文中,否则一个数组名即是指向它第一个元素的指针.没有多维数组,只有数组的数组.仅是指针的存在并不要求它所引用的类型的实现的有效性(这是一个不完全类型).如果理解了这些概念,你就正

《C和C++代码精粹》——1.4 函数原型

1.4 函数原型 C和C++代码精粹在C++中,函数原型不是可选的.事实上,在ANSI C委员会采用原型机制以前,它是为C++发明的.在你第一次使用函数前必须声明或定义每个函数,编译器将检查每个函数调用时正确的参数数目和参数类型.此外,在其应用时将执行自动转换.下列程序揭示一个在C中不使用原型时出现的普通错误. /* convert1.c */ #include <stdio.h> main( { dprint(123); dprint(123.0); return 0; } dprint(d

《C和C++代码精粹》——1.7 类型安全I/O

1.7 类型安全I/O C和C++代码精粹当然每个C程序员都曾经使用过printf的错误格式描述符号.对printf来说没有办法检查所传递的数据项是否与字符串格式匹配. 程序清单1.4 一个说明引用调用的交换函数 // swap.cpp #include <stdio.h> void swap(int &, int &); main() { int i = 1, j = 2; swap(i,j); printf("i == %d, j == %d\n", i