C++ Primer(第四版)答案之第四章

4.1

(a) 数组大小用变量定义,非法

(b) 数组大小用函数返回值定义,非法

(c) 数组大小用整型表达式定义,合法

(d) 用字符串字面值初始化字符数组,数组大小不够。字符串字面值还有末尾的'\0'。

 

4.2

函数外定义,sa都是空字符串,ia都是0。

函数内定义,sa2都是空字符串,ia2都是未定义值。

 

4.3

(a) 是对的。

(b) 是错误的,vector不能用初始化列表来初始化,也不能用普通数组来初始化。

(c) 是错的。不能用一个数组直接初始化另一个数组(用一个数组整体赋值给另一个数组)

(d) 是错误的,不能用一个vector去初始化一个数组。

 

4.4

int a[10] = {1,2,3};  // 初始化一部分元素
int a[] = {1,2,3}; // 初始化全部元素

 

4.5

使用数组的缺点:

  • 更容易溢出,也就是下标越界。
  • 缺少一些方便的函数,比如size, empty等
  • 不能动态添加数组元素

 

4.6

当ix=10的时候,下标越界,下标从0开始,到size-1.

size_t ix=1,这个错误,应该是 ix=0;

ix<=array_size,这个错误,应该是 ix<array_size

 

4.7

#include <iostream>
#include <vector>
#include <bitset>

using namespace std;

int main() {
    int a[] = {1, 2, 3};
    size_t size = sizeof(a) / sizeof(a[0]);

    int b[size];
    for(size_t i=0; i<size; i++)
        b[i] = a[i];
    for (size_t i=0; i<size; i++)
        printf("%d\t", b[i]);
    printf("\n");

    vector<int> c;
    for(size_t i=0; i<size; i++)
        c.push_back(a[i]);
    vector<int> d(c);
    for(vector<int>::const_iterator iter=d.begin(); iter!=d.end(); iter++)
        cout << *iter << endl;

    return 0;
}

 

4.8

#include <iostream>
#include <vector>
#include <bitset>

using namespace std;

bool isEqual(int a[], int asz, int b[], int bsz) {
    if(asz!=bsz)
        return false;

    for(size_t i=0; i<asz; i++)
        if(a[i] != b[i])
            return false;

    return true;
}

bool isEqual2(vector<int> &a, vector<int>& b) {
    if(a.size()!=b.size())
        return false;

    for(vector<int>::size_type i=0; i<a.size(); i++)
        if(a[i] != b[i])
            return false;

    return true;
}

int main() {
    int a[] = {1,2,3};
    int b[] = {2,3,4};
    int c[] = {1,2,3};
    printf("%s\n", isEqual(a, 3, b, 3)?"is equal": "not equal");
    printf("%s\n", isEqual(a, 3, c, 3)?"is equal": "not equal");
    printf("%s\n", isEqual(b, 3, c, 3)?"is equal": "not equal");

    vector<int> aa, bb, cc;
    aa.push_back(1);
    aa.push_back(2);
    aa.push_back(3);
    bb.push_back(2);
    bb.push_back(3);
    bb.push_back(4);
    cc.push_back(1);
    cc.push_back(2);
    cc.push_back(3);
    printf("%s\n", isEqual2(aa, bb)?"is equal": "not equal");
    printf("%s\n", isEqual2(aa, cc)?"is equal": "not equal");
    printf("%s\n", isEqual2(bb, cc)?"is equal": "not equal");

    return 0;
}

 

4.9

#include <iostream>
#include <vector>
#include <bitset>

using namespace std;

int main() {
    int a[10];
    for(size_t i=0; i<10; i++)
        a[i] = i;

    return 0;
}

 

4.10

将*号和标识符连在一起,适合于一次定义多个指针。看到标识符前面有个*号,就可以认为是指针,指向的元素类型就是*号前面的类型。

*号和类型连在一起,容易认为是一种数据类型,会在定义多个变量的时候,造成混乱。

 

4.11

(a) 合法的,定义了一个指针,但是没有初始化,是个野指针。

(b) 合法

(c) 非法,指针类型和初始化使用的变量类型不一致

(d) 合法,又是野指针

(e) 合法,标准的定义空指针

(f) 合法,同上

 

4.12

不能检查是否指向了一个有效的对象。指针只是对象的地址,也就是一片内存的地址,至于这片内存上的对象是不是存活,什么状态,都不清楚。

 

4.13

void*指针,可以指向任何类型的地址,他表示,只是指向了一片内存,不清楚内存上有什么类型。

第二个指针初始化不合法的原因在于,类型不一致。

 

4.14

#include <iostream>
#include <vector>
#include <bitset>

using namespace std;

int main() {
    // 修改指针所指向对象的值
    int a;
    int *p = &a;
    cin >> a;
    cout << *p << endl;
    *p += 1;
    cout << *p << endl;

    // 修改指针的值
    int b;
    cin >> b;
    p = &b;
    cout << *p << endl;
    
    return 0;
}

 

4.15

指针和引用的区别:

  • 指针是所指对象的地址,引用是所关联对象的别名。
  • 指针可以修改,引用不能重新关联。
  • 指针可以判空,引用定义的时候必须初始化,没有空的引用。
  • 有指针的指针,没有引用的引用。

 

4.16

将j变成42*1024,将i变成42*42.

 

4.17

作用是将p1指向p2,先计算p2与p1的距离,p1加上这个距离就是p2所指向的地址。当p1是const类型是,该操作非法。

 

4.18

#include <iostream>
#include <vector>
#include <bitset>

using namespace std;

int main() {
    int a[] = {1,2,3};
    size_t sz = sizeof(a) / sizeof(a[0]);
    for(int *pbegin=a, *pend=a+sz; pbegin!=pend; pbegin++)
        *pbegin = 0;

    return 0;
}

 

4.19

(a) 定义一个int

(b) 定义一个常量int,定义的时候没有初始化,非法

(c) 定义一个指针,指向的类型是const int

(d) 定义一个const指针,指向的类型是int,定义的时候必须初始化,之后不能指向其他的地址,该项明显非法。

(e) 定义一个const指针,指向的类型也是const int,非法,定义的时候没有初始化,其初始化的对象可以是const也可以是非const,但是都不能修改该指针指向别的地址,也不能修改该指针指向的值。

 

4.20

(d) 是非法的,ic是一个const int,但是cpi是一个const指针,指向的是个非const int,通过cpi是可以修改所指向的值的。其余都正确。

(a) 是普通int

(b) 是const int;

(c) 是非const指针,指向const int

(e) 是const指针,指向const int

 

4.21

(a) 合法,用const变量赋值非const变量

(b) 合法,pic是个指针,指向const int类型的变量,ic就是 const int,取ic的地址给给pic,使其指向ic

(c) 非法, cpi是个const指针,指向int,初始化之后不能再被赋值

(d) 合法,虽然pic和cpic的类型不一致,但是pic指向的是一个const int,cpic也是指向的一个const int

(e) 非法,cpic是一个const指针,初始化之后不能被赋值

(f) 非法,ic是一个const int,初始化之后不能被赋值

 

4.22

第一个循环是死循环,cp是指针,会一直++;

第二个循环是正常的循环,*cp等于'\0'时,条件判断失败

 

4.23

想遍历输出字符串,但是循环不会停止,直到*cp=='\0'为止。因为C风格字符串没有'\0'结尾。

 

4.24

区别是,strncpy需要指定拷贝的字节数,也就是拷贝字符串的前几个字符。优点是有效的降低的数组溢出的可能性。安全性更高。

strcpy不需要指定拷贝的字节数。使用更便利。

两者都假设C风格的字符串以'\0'结尾,切被拷贝字符数组有足够的空间。

 

4.25

#include <iostream>

using namespace std;

int compare_string(const string &s1, const string &s2) {
    if(s1 == s2)
        return 0;
    else if(s1 > s2)
        return 1;
    else
        return -1;
}

int compare_c_style_string(const char* s1, size_t s1_sz, const char *s2, size_t s2_sz) {
    if(s1_sz > s2_sz)
        return 1;
    else if (s1_sz < s2_sz)
        return -1;
    else {
        for(size_t i=0; i<s1_sz; i++)
            if (s1[i] > s2[i])
                return 1;
            else if (s1[i] < s2[i])
                return -1;

        return 0;
    }
}


int main() {
    string s1("zhaosp"), s2("zhaa");
    cout << compare_string(s1, s2) << endl;
    cout << compare_c_style_string(s1.c_str(), s1.size(), s2.c_str(), s2.size()) << endl;

    s1 = "zhaosp";
    s2 = "zhaosp";
    cout << compare_string(s1, s2) << endl;
    cout << compare_c_style_string(s1.c_str(), s1.size(), s2.c_str(), s2.size()) << endl;

    s2 = "zhaosz";
    cout << compare_string(s1, s2) << endl;
    cout << compare_c_style_string(s1.c_str(), s1.size(), s2.c_str(), s2.size()) << endl;

    return 0;
}

 

4.26

#include <iostream>

#define INIT_SIZE 10
#define INCREMENTAL_SIZE 10

using namespace std;

int main() {
    /*
     * 从标准输入读取一个C风格字符串,fixme: run出一个随机性的crash
     *
     * */
    char ch;
    char *p = (char*)malloc(sizeof(char) * INIT_SIZE);
    size_t count(0), size(INIT_SIZE);
    while (true) {
        scanf("%c", &ch);
        if(count == size) {
            printf("realloc memory\n");
            p = (char*)realloc(p, sizeof(char) * (size + INCREMENTAL_SIZE));
        }

        p[count++] = ch;
        if(ch == '\n') {
            p[count] = '\0';
            break;
        }
    }

    printf("\nc style string: %s", p);

    free(p);

    return 0;
}

 

4.27

delete [] pa;

 

4.28

#include <iostream>
#include <cstring>
#include <vector>

using namespace std;

int main() {
    vector<int> a;
    int b;
    while (cin >> b)
        a.push_back(b);

    int *p = new int[a.size()];
    for(size_t i=0; i<a.size(); i++)
        p[i] = a[i];

    for(size_t i=0; i<a.size(); i++)
        cout << p[i] << endl;

    delete [] p;

    return 0;
}

 

4.29

(a) 哪两个?

(b) 预计一样。还不知道具体什么原因。

 

4.30

#include <iostream>
#include <cstring>
#include <vector>

using namespace std;

int main() {
    char str1[10] = "fule";
    const char *str2 = "sbhwt";
    strcat(str1, str2);
    printf("%s\n", str1);

    string s1("fule"), s2(str2);
    cout << s1 + s2 << endl;

    return 0;
}

 

4.31

纯C风格的处理方式,回车换行,结束一个字符串的处理,quit退出程序。

#include <iostream>
#include <cstring>

#define INIT_SIZE 10
#define INCREMENTAL_SIZE 5

using namespace std;

int main() {
    char test[5];
    scanf("%s", test);  // 不会考虑到字符数组的长度是否合适,是否溢出,通常溢出会crash
    printf("%s", test);

    // 脱了裤子放屁的方式
    string s;
    cin >> s;
    char tmp[s.size()+1];
    for(size_t i=0; i<s.size(); i++)
        tmp[i] = s[i];
    tmp[s.size()] = '\0';
    printf("%s", tmp);

    while (true) {
        char ch;
        char *p = (char*)malloc(sizeof(char) * INIT_SIZE);
        size_t count(0), size(INIT_SIZE);
        while (true) {
            scanf("%c", &ch);
            if(ch == '\n')
                break;

            if(count == size-1) {
                p = (char*)realloc(p, sizeof(char) * size + INCREMENTAL_SIZE);
                size += INCREMENTAL_SIZE;
            }

            p[count++] = ch;
        }
        p[count] = '\0';
        printf("%s", p);
        int flag = strcmp("quit", p);
        free(p);

        if(flag==0)
            break;
    }

    return 0;
}

 

4.32

#include <iostream>
#include <vector>

using namespace std;

int main() {
    int a[] = {0,1,2,3};
    vector<int> b(a, a + sizeof(a)/sizeof(a[0]));
    for(vector<int>::const_iterator iter=b.begin(); iter!=b.end(); iter++)
        cout << *iter << endl;

    return 0;
}

 

4.33

#include <iostream>
#include <vector>

using namespace std;

int main() {
    vector<int> a(3, 1);
    int b[a.size()];
    for(vector<int>::size_type i=0; i<a.size(); i++)
        b[i] = a[i];

    for(size_t i=0; i<a.size(); i++)
        cout << b[i] << endl;

    return 0;
}

 

4.34

#include <iostream>
#include <vector>
#include <cstring>

using namespace std;

int main() {
    vector<string> vs;
    string tmp;
    while (cin >> tmp) {
        if (tmp == "quit")
            break;

        vs.push_back(tmp);
    }

    for(vector<string>::const_iterator iter=vs.begin(); iter!=vs.end(); iter++)
        printf("%s\t", iter->c_str());
    printf("\n");

    char* arr[vs.size()];
    for(vector<string>::size_type i=0; i<vs.size(); i++) {
        size_t sz = vs[i].size();
        arr[i] = new char[sz +1];
        strcpy(arr[i], vs[i].c_str());
        arr[i][sz] = '\0';
    }

    for(size_t i=0; i<vs.size(); i++) {
        printf("%s\t", arr[i]);
        delete [] arr[i];
    }

    return 0;
}

 

4.35

见4.34

 

4.36

#include <iostream>
#include <vector>
#include <cstring>

using namespace std;

typedef int int_array[4];

int main() {
    int a[3][4] = {1,2,3,4,5,6};
    int b[3][4] = {{1}, {2,3}, {4, 0, 0, 1}};

    // 题目要求的输出
    int_array *ip = a;
    for(size_t i=0; i<3; i++) {
        for(int *q = a[i]; q!= a[i] +4; ++q)
            printf("%d\t", *q);
        printf("\n");
    }

    // 数组方式的输出
    for(size_t i=0; i<3; i++) {
        for(size_t j=0; j<4; j++)
            printf("%d\t", a[i][j]);
        printf("\n");
    }
    printf("\n");

    // 数组方式的输出
    for(size_t i=0; i<3; i++) {
        for(size_t j=0; j<4; j++)
            printf("%d\t", b[i][j]);
        printf("\n");
    }
    printf("\n");

    int (*p)[4] = b;
    for(size_t i=0; i<3; i++)
        cout << **(p+i) << endl; // p指向第一行,p+i指向第i行,*p是第一行数组的地址,**p是第一行数组的首元素的地址,*(*(p+i)+j)就是a[i][j]

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值