2010/11/03

2010/11/3

关键字:C风格字符串

 

C风格字符串(C-style character string)

以空字符null结束的字符数组.

char c1[] = {'C', '+', '+'};    //不是C风格字符串

char c2[] = "C++";              //

 

C风格字符串标准库

必须包含头文件#include<cstring>

cstringstring.hC++版本,string.hC语言提供的标准库.

注意这些标准库函数不会检测起字符串参数.使用这些函数是不安全的,强烈建议不要使用.

使用这些函数有下面限制:

1.      参数不能为空

2.      传入的字符串必须以null结尾

3.      一些函数会修改传入的字符串,必须确保被修改的字符串足够大以容纳本函数新生产的字符串.

 

C风格字符串标准库

strlen(s)

返从s开始直到null的长度,不包括null

strcmp(s1, s2)

比较两个字符串s1s2是否相同,s1s2相等,返回0,s1大于s2,返回正数,s1小于s2,则返回负数.

strcat(s1, s2)

将字符串s2接到s1后面,返回s1.

strcpy(s1, s2)

s2复制给s1,并返回s1

strncat(s1, s2, n)

将字符串s2的前n个字符接到s1后面,返回s1.

strncpy(s1, s2, n)

s2n个字符复制给s1,并返回s1

C风格字符串也可以关系操作符比较,但实际上比较的是地址,比较地址是无意义的:

char c1[] = {'C', '+', '+'};    //不是C风格字符串

    char c2[] = "C++";              //

    char *p1 = &(c1[1]);

    bool b = (c1) > (c2);           //实际比较的是地址

    b = (c1) > (p1);                //实际比较的是地址

也就是说C风格字符串需要比较时必须用strcmp函数.

使用strcatstrcpy等标准库函数时,调用者必须确保目标字符串具有足够的大小.

char cp1[] = {'1', '2', '3'};   //错误,C风格字符串

    char cp2[] = "12345";

    char largeStr[3+1+5];           //错误,目标字符串要多一个结尾用以保存null

    strcpy(largeStr, cp1);          //错误,C风格字符串不能使用strcpy

    strcat(largeStr, " ");          //largeStr可能已经溢出

    strcat(largeStr, cp2);          //largeStr可能已经溢出

修改后

char cp1[] = {'1', '2', '3', 0};

    char cp2[] = "12345";

    char largeStr[3+1+5+1];

    strcpy(largeStr, cp1);

    strcat(largeStr, " ");

    strcat(largeStr, cp2);

不过最好还是使用strn系列函数,明确指定复制、连接的字符个数

char cp1[] = {'1', '2', '3', 0};

    char cp2[] = "12345";

    char largeStr[3+1+5+1];

    strncpy(largeStr, cp1, 4);

    strncat(largeStr, " ", 2);

    strncat(largeStr, cp2, 6);

最简便安全的方法是使用string

    string cp1 = "123";

    string cp2 = "12345";

    string largeStr = cp1;

    largeStr += " ";

    largeStr += cp2;

对于大部分程序,使用string不仅增强安全性,而且效率也有提高,因此尽量避免使用C风格字符串.

 

动态数组

创建和销毁分别用new name[]delete[] name.

动态创建的数据如果需要初始化,只能初始化为元素的默认值,即内置类型只能初始化为0,而类类型只能调用输入参数为void的构造函数或默认构造函数.而不可以使用初始化列表.

class A

{

public:

    A(){a = 1;}

private:

    int a;

};

 

int main()

{

    int *p = new int[10];           //未初始化

    int *p1 = new int[10]();        //初始化为默认值0

    string *pstr = new string[10];  //初始化为空字符串

    A *pa1 = new A[10]();           //调用输入参数为void的构造函数,a1

    A *pa2 = new A[10];             //调用A的输入参数为void的构造函数,a1,A没有默认构造函数

    B *pb1 = new B[10]();           //调用输入参数为void的构造函数,即调用B的默认构造函数,b未初始化

    B *pb2 = new B[10];             //调用B的输入参数为void的构造函数即默认构造函数,b未初始化

 

    return 0;

}

如果类未声明输入参数为void的构造函数,则编译器会自动生成默认构造函数,默认构造函数形如A(){},只分配地址,不初始化变量.

stringC风格字符串

有几点需要注意:

string str = "1243";

    str = str + "1243";             //错误

    str = "1243" + str;             //错误

    str += "1234";                  //正确,这里的+=string类的重载操作符并不等同于str = str + "1234"

 

    char *p = str.c_str();          //错误

    const char *p = str.c_str();    //正确,str.c_str()返回的是string内部数组首地址,不允许被修改

    str += "12";

    const char *p2 = p;             //虽然语法上没问题,但实际可能是错误的,因为p保存的是str之前的内存,str+="12"之后该地址可能无效了,应该将字符串copy到其他内存中

vector和数组

唯一需要知道的是可以用数组初始化vector.

int array[4] = {1,2,3};             //array[3]会被初始化为

    vector<int> vec(array, array+4);    //初始化方法为vector(begin, end),end为哨兵迭代器,vec中会包含从array开始到array+3的所有元素

 

指针与多维数组

C++中的多维数组实际是数组的数组.

理解下面的代码即可:

int array[3][4];

    int (*p1)[4] = array;       //从内向外理解即可.p1是指针,指向int [4]的指针.p1是指向包含个整型元素的数组的指针

    int *p2[4];                 //从内向外理解即可.p2是数组,数组中包含个int *元素.等同于int* p[4];

    p1 = &(array[2]);           //array实际是内层数组的首地址,&array[2]是外层数组的第个元素的首地址

 

可以用typedef简化理解

typedef int intarray4[4];

    for (intarray4 *p=array; p!=array+3; ++p)

    {

        for (int *q=*p; q!=(*p)+4; ++q)

        {

            cout << *q << endl;

        }

    }

intarray4是一种类型,int[4]类型.p就是int[4]数组类型的指针.

p解引用得到int[4]类型的数组中的第一个元素的值,q指针依次遍历指向4个元素.

你可能感兴趣的:(2010/11/03)