c++中数组、字符串和指针

数组

1.数组大小必须是整形常数、const值或常量表达式,所有的值都是在编译时已知的;但使用new时,可以是变量;

 

2.不能将一个数组直接赋值给另一个数组,数组名是常量(是指针常量);

 

3.初始化字符数组时,如果使用双引号直接将字符串常量初始化给数组,则字符串常量中最多由初始化数组时规定的长度-1个字符,留一个字符位置给末尾的空字符 '\0';

注意:string对象不使用空字符来标记字符串末尾。

char a[5] = "abcd";

 将一个字符串赋值给字符数组,常用的方法是用strcpy()函数。

4.如果初始化字符数组时,使用字符串常量直接赋值的方法,且字符串常量中有'\0',则输出该字符数组时,到'\0'处就输出结束,因为'\0'是空字符。

    char a[10] = "abc\0def";
    cout<<a<<endl;
    char* b = "ab\0cd";
    cout<<b<<endl;
    string c = "ab\0cd";
    cout<<c<<endl;

输出:

但是,如果是用户输入初始化,且输入时有'\0',则输出时,输入的'\0'并不会作为空字符

    char a[10] ;
    cin>>a;
    cout<<a<<endl;
    char* b = new char[10];
    cin>>b;
    cout<<b<<endl;
    delete [] b;
    string c ;
    cin>>c;
    cout<<c<<endl;
    return 0;

如果使用花括号一个个赋值字符,即这种方式:

    char d[4] = {'a','b','c'};
    cout<<d<<endl;
    char e[4] = {'a','b','c','d'};
    cout<<e<<endl;

输出:

这是因为,采用上述初始化方式,系统会自动将在数组范围内没有初始化的字符都赋值为'\0',但显然字符数组e已经被人为的赋值满了,所有就一直输出,知道遇到第一个'\0'才输出停止。(参考https://blog.csdn.net/qq_41076797/article/details/105493998

 

5.对于字符数组使用strlen(),则其计算第一个'\0'之前的长度(不包含空字符'\0');对字符数组使用sizeof(),其计算整个数组的长度(单位为字节)(c++ pp page64)

    char a[10]  = "abcde";
    cout<<strlen(a)<<endl;
    cout<<sizeof(a)<<endl;
    cout<<a<<endl;

 

6.cin使用空白(空格、制表符和换行符)来确定字符串结束的位置;cin.getline()使用换行符来确定字符串结束位置。因此如果想输入一整行(包含空格),则使用cin.getline()函数;
cin.getline()提取一整行输入,知道到达换行符,随后getline()丢弃换行符,而get()将换行符保留在输入队列中(即作为下次输入的第一个字符);
使用方法:

cin.getline(a,20);其中a为字符数组名,参数为20,则其最多读取19个字符;get()用法类似。

有关使用cin后紧接着使用cin.getline()不能输入的问题,见https://www.cnblogs.com/San-Francisco/p/15872715.html

string类对象的getline()函数的使用前面不加cin:

string s;
getline(cin,s);

 c++ pp page(65)

 

7.不能将一个字符数组(或数组)直接赋值给另一个字符数组(或数组),因为数组名为常数。但可以将一个string类对象直接赋值给另一个string类对象。

 

8.字符数组间,如果想将一个字符数组赋值到另一个字符数组,不能直接使用等于号=赋值,而要使用strcpy();

    char* a = new char[6];
    a = "abcde";
    char* b = new char[6];
    b = a;
    strcpy(b,a);
    cout<<a<<endl;
    delete [] a;

注意,上图创建了两个动态变量a和b,分别指向两个内存。现在若将a指针指向的内存中的内容"abcde"复制到b指针指向的内存中去,不能使用b = a;因为这代表将b指针指向a指针指向的内存;这样不但没有达到我们的目的,还永远失去了初始时b指针指向的内存;应使用strcpy(a,b);(c++ pp page 70,93)

 

8.1.在cout和多数c++表达式中,char数组名char指针以及用双引号引起的字符串常量都被解释为字符串第一个字符的地址。

这就说明,对数组名 a 使用 *,得到数组的第一个元素,*(a+1)得到数组的第二个元素;

对 char* 指针 a 使用*,得到字符串第一个元素,*(a+1)得到字符串第二个元素;

直接对字符串"abcd"使用 *,得到字符'a';(注意,字符串 “abcd” 是 const char * 类型

    int a[5] = {1,2,3,4,5};
    cout<<*a<<endl;
    cout<<*(a+1)<<endl;
    char* b = "abcde";
    cout<<*b<<endl;
    cout<<*(b+1)<<endl;
    cout<<*("qwer")<<endl;
    cout<<*(("qwer")+1)<<endl;

输出为:

但是注意:

char* b = "abcde";

这样写不太好,这就相当于

int* a = &1;

这样,a是一个指针,但它指向哪里并不确定。见c++ pp page 84

 

8.2.关于字符指针不能直接输入的问题

考虑下面代码:

    char* a;
    cin>>a;
    cout<<a<<endl;

a是一个字符指针,但其指向哪里并不知道,因为该指针并没有被初始化。因此该指针并未被初始化为一个确定的、适当的地址。直接输入是错误的。就如同下面的代码一样:

    int* a;
    *a = 3;
    cout<<a<<endl;

上面的指针a也没有被初始化为一个确定的地址。

但是这样使用字符指针是可以的:

    char* a;
    a = "abcd";
    cout<<a<<endl;

因为字符串常量”abcd“被解释为一个地址;这样使用表示a指向 "abcd" 这个地址中存放的字符串。

最好的写法应该是这样:

    char* a;
    char b[20] = "abcd";
    a = b;
    cout<<a<<endl;

参考c++ pp page 84

 

8.3关于const char * a的赋值问题

#include <iostream>
using namespace std;
int main()
{
    const char * a;
    a = "abc";
    a = "def";
}

上述代码是可行的;

a是一个const char * 类型的指针,不能通过该指针修改其指向的内容的值,但是可以将该指针指向别的地址。而字符串常量“abc”代表了字符串“abc”的第一个字符的地址,字符串常量“def”代表了字符串“def”的第一个字符的地址。

 

9.OOP(面向对象编程)是在运行阶段(而不是编译阶段)进行决策。

在一般情况下,我们声明一个数组时,程序在被编译时就会为它分配内存空间。不管程序最终是否使用数组,数组使用占用内存。在程序编译时给数组分配内存叫做静态联编。

使用new时,是在运行阶段,如果需要数组,则创建它,并选择数组长度。这被称为动态联编。(c++pp page86)

 

10.

1)c++中创建指针时,计算机会分配用来存储地址的内存(即指针变量的内存),但不会分配用来存储指针所指向的数组的内存。

2)使用new运算符时,计算机会分配用来存储指针所指向的变量的内存。该过程是:new将先找到一个长度正确的内存块,并返回给指针该内存块的地址。(c++pp page 84)

 

11.对数组使用sizeof,得到整个数组的长度(前面已经提到);对指针使用sizeof,得到的是指针的长度,即使指针指向的是一个数组。(c++pp page90)

 

12.对于一个数组arr,如果出现了arr[i],则程序将其转换为*(arr+i);这是因为数组名即为数组第一个元素的地址(注意不是指向第一个元素,而是数组名就是数组第一个元素的地址,数组名是一个地址而不是一个指针变量)。但是,指针变量的+1和地址的+1其实是相同的,因为指针变量中存储的就是地址。

 

13.如果个cout提供一个指针,它将打印地址:

    int a = 4;
    int *b = &a;
    cout<<b<<endl;

但如果指针的类型是char*类型,则cout将显示指针指向的字符串:

    char a[5] = "abcd";
    char* b = a;//a是数组第一个元素的地址,所以这里不需要取地址符&
    cout<<b<<endl;

若要输出该数组第一个字符的地址,应使用

    cout<<(int*)a<<endl;

(c++pp page93)

 

14.指针数组、指向指针的指针(c++pp page98)

 

15.字符串比较

若word是char数组名,word == "mate"并不能判定word中存储的字符串是否为“mate”。因为数组名是数组第一个元素的地址,而字符串常量也是字符串的起始地址,因此该判断不是判断两个字符串是否相同,而是判断它们是否存储在相同的地址上。

若要判断字符串是否相同,应使用strcmp()函数,该函数接受两个字符串地址作为参数,这意味着参数可以是指针、字符串常量或字符数组名。

但是string类对象可以使用 == 来判断两个变量的字符串是否相同,因为类函数重载了这些运算符。(c++pp page 118)

 

posted @ 2022-02-12 17:56  SanFranciscoo  阅读(334)  评论(0编辑  收藏  举报