C++primer习题集(第二章)

2.1 类型int,long,longlong,short的区别是什么? 无符号和带符号的区别是什么?float和double的区别是什么?

  • int和long的区别,下面的图片展示的很清晰了。一般情况下,int是32位,long是32位,long long是64位,short是16位。
  • 无符号和带符号的区别在于他们的范围不同,int(32位)的范围是-231~231-1,unsigned int 的范围是0~232-1
  • float是32位的单精度浮点型,double是64位的双精度浮点型,表示范围更大,也更加精确。

 图片来源:(29条消息) long型和int型的区别_long型与int型的区别_Leisure -_-的博客-CSDN博客(如有侵权请联系我删除)

 


2.2 计算按揭贷款时,对于利率、本金和付款应该分别选择什么数据类型?说明理由。

  应该都选择double型(尽可能高精度)

 


2.3 读程序写结果

#include<iostream>
using namespace std;
int main()
{
    unsigned u=10,u2=42;
    cout<<"unsigned u=10,u2=42"<<endl;
    cout<<"u2-u="<<u2-u<<endl;
    cout<<"u-u2="<<u-u2<<endl<<endl;

    int i=10,i2=42;
    cout<<"int i=10,i2=42"<<endl;
    cout<<"i2-i="<<i2-i<<endl;
    cout<<"i-i2="<<i-i2<<endl<<endl;

    //这里转换为无符号数
    cout<<"i-u="<<i-u<<endl;
    cout<<"u-i="<<u-i<<endl;

    return 0;
}

输出结果如下(建议最后两行换成i-u2和u-i2看看结果):

unsigned u=10,u2=42
u2-u=32
u-u2=4294967264

int i=10,i2=42
i2-i=32
i-i2=-32

i-u=0
u-i=0

  


2.4 编写程序检查你的估计是否正确。如果不正确,自己去看。

  见2.3。

 


2.5 指出下面字面值的类型并说明每一组中几种字面值的区别。

#include <iostream>

int main()
{
    char c1='a';
    wchar_t c2=L'a';                //宽字符类型,支持更多的字符
    const char s1[]="a";            //字符串
    const wchar_t s2[] = L"a";      //宽类型字符串
    
    int n1 = 10;
    unsigned n2 = 10u;
    long n3 = 10L;
    unsigned long n4 = 10UL;
    int n5 = 012;   //八进制整型
    int n6 = 0xC;   //十六进制整型
    
    double d1 = 3.14;
    float d2 = 3.14F;
    long double d3 = 3.14L;
    
    int x1 = 10;
    unsigned int x2 = 10u;
    double x3 = 10.;
    double x4 = 10e-2; 
    
    return 0;
}

 


2.6 下面两组定义是否有区别,如果有请进行论述。

#include<iostream>
using namespace std;

int main()
{
    /*0打头代表八进制*/
    int month=6,day=17;
    int month2=06,day2=017;
    cout<<"month="<<month<<",day="<<day<<endl;
    cout<<"month2="<<month2<<",day2="<<day2<<endl;

    return 0;
}
/*
原书中month是9和09,day是7和07
int month=9,day=7;
int month=09,day=07;
*/
输出的是十进制
month=6,day=17
month2=6,day2=15

  


2.7 下述字面值表示何种含义?他们各自的数据类型是什么?

#include <iostream>
using namespace std;
int main()
{
    char s[]="Who goes with F\145rgus?\012";
    cout<<s<<endl;
    long double i1 = 3.14e1L;
    // i2 = 1024f;  //应该改为1024.f
    long double i3 = 3.14L;

    return 0;
}
Who goes with Fergus?

  


2.8 利用转义序列编写一段程序,输出2M。修改程序使他输出2,然后输出制表符,再输出M,最后换行。

#include <iostream>
using namespace std;
int main()
{
    cout<<"2\tM\n";

    return 0;
}

 


2.9 解释下列定义的含义。对于非法的定义进行改正。

#include <iostream>
using namespace std;
#include<stdio.h>

int main()
{
    //a:错误,必须先定义
    int input_value;
    cin>>input_value;

    //b:{}要求比较严格,去掉大括号,或者int改成double
    double i={3.14};
    cout<<i<<endl;

    //c
    double salary=9999.99,wage=salary;
    cout<<salary<<"\t"<<wage<<endl;

    //d:会损失小数部分,但不会报错
    int d=3.14;
    cout<<d<<endl;

    return 0;
}
5(自己输入的)
3.14
9999.99 9999.99
3

  


2.10 下列变量的初值分别是什么?

#include <iostream>

std::string global_str;
int global_int;
int main()
{
    int local_int;
    std::string local_str;
    std::cout<<"global_str:"<<global_str<<std::endl;
    std::cout<<"global_int:"<<global_int<<std::endl;
    std::cout<<"local_str:"<<local_str<<std::endl;
    std::cout<<"local_int:"<<local_int<<std::endl;

    return 0;
}
global_str:
global_int:0
local_str:
local_int:4201472
//str均为空串,全局变量默认为0,局部变量未定义,数值与地址相关

  


2.11 指出下面的语句是声明还是定义。

#include <iostream>
using namespace std;

//警告:'ix'初始化并声明为'extern'
extern int ix=1024;
//声明,并自动初始化定义为0
int iy;
//声明
extern int iz;

int main()
{
    return 0;
}

 


2.12 指出下面哪些名字是非法的?

    //错误,double是关键字
    int double=3.14
    //正确,但是无意义,不建议
    int _;
    //错误,-是非法符号
    int catch-22;
    //错误,不能数字作为变量开头
    int 1_or_2;
    //正确,但是易混淆,不建议
    double Double=3.14;

 


2.13 下面程序中j的值是多少?

#include <iostream>
using namespace std;
int i=42;
int main()
{
    int i=100;
    int j=i;
    cout << "j=" <<j<< endl;
    return 0;
}
j=100

  


2.14 下面的程序合法吗?如果合法会输出什么?

  是合法的,循环里面声明的 i 的作用域也仅在循环内。

#include <iostream>
using namespace std;

int main()
{
    int i=100, sum=0;
    for(int i=0;i!=10;++i)
        sum+=i;
    cout << "i=" <<i<<"\tsum="<<sum<<endl;
    return 0;
}
i=100	sum=45

  


2.15 下面哪个定义是不合法的?为什么?

//a:合法
int ival=1.01;

//b:非法,引用的初始值必须是一个对象
int &rval1=1.01;

//c:合法
int &rval2=ival;

//d:非法,引用必须初始化
int &rval3;

 


2.16 考察下面所有赋值然后回答:哪些赋值是非法的,为什么?哪些赋值是合法的?他们执行了哪些操作?

#include <iostream>
using namespace std;

int main()
{
    int i=0,&r1=i;
    double d=0,&r2=d;
    
    r2=3.14159;
    cout<<"d="<<d<<"\tr2="<<r2<<endl;
    r2=r1;
    cout<<"d="<<d<<"\tr2="<<r2<<endl;
    d=3.14;        //我自己加的
    i=r2;
    cout<<"i="<<i<<"\tr1="<<r1<<endl;
    r1=d;
    cout<<"i="<<i<<"\tr1="<<r1<<endl;
    
    return 0;
}
d=3.14159	r2=3.14159
d=0	r2=0
i=3	r1=3
i=3	r1=3
都是合法的,基本就是等于来回赋值。

  


2.17 执行下面的代码将输出什么结果?

#include <iostream>
using namespace std;

int main()
{
    int i=0,&ri=i;
    i=5;
    ri=10;
    cout<<i<<"  "<<ri<<endl;
    
    return 0;
}
10  10

  


2.18 编写代码,分别修改指针的值以及指针所指对象的值。

#include <iostream>
using namespace std;

int main()
{
    int i=0,j=10;
    int *ri=&i;
    cout<<"最开始的值和地址"<<endl;
    cout<<*ri<<"\t"<<ri<<endl;
    
    cout<<"换指针的值"<<endl;
    ri=&j;
    cout<<*ri<<"\t"<<ri<<endl;
    
    cout<<"换指针所指对象的值"<<endl;
    *ri=100;
    cout<<*ri<<"\t"<<ri<<endl;
    
    return 0;
}
最开始的值和地址
0	0x7ffd804a4134
换指针的值
10	0x7ffd804a4130
换指针所指对象的值
100	0x7ffd804a4130

  


2.19  说明指针和引用的主要区别。

  1. 定义和使用方式:指针是一个变量,用于存储另一个变量的内存地址。它需要使用星号(*)来声明指针类型,并使用取地址符(&)来获取变量的地址。而引用是一个别名,用于给已存在的变量起一个新的名称。它使用变量的名称来声明引用,没有自己的内存地址

   2. 空值:指针可以具有空值(NULL或nullptr),表示指向无效内存地址。而引用必须始终引用有效的对象,不能为null

   3. 变量绑定:指针可以在声明后重新指向其他变量或空值。而引用在声明后必须始终引用同一个对象,不能重新绑定到其他对象。

   4. 内存访问:指针可以通过解引用操作符(*)来访问所指向的对象的值。而引用直接访问所引用对象的值,无需解引用。

  5. 空间占用:指针本身需要占用一定的内存空间来存储地址值。而引用本身不需要额外的内存空间,它只是变量的别名。

   6. 传递方式:指针可以作为函数参数进行传递,可以传递地址或者通过指针修改原始变量的值。而引用也可以作为函数参数进行传递,可以直接修改原始变量的值,但不需要使用指针操作符。

 


2.20 叙述下面这段代码的作用

#include <iostream>
using namespace std;
int main()
{
    int i=42;
    int *p1=&i;
    *p1=*p1 * *p1;
    cout<<*p1<<endl;
    return 0;
}
1764
作用是让i=i*i

  


2.21 请解释下面的定义?他们有非法的吗?如果有,为什么?

#include <iostream>
using namespace std;
int main()
{
    int i=2;
    //a 非法,指针和对象的数据类型不一致
    //double *dp=&i;
    //b 非法,ip是一个指针,右边应该也是对应的类型,而非int,报错为error: invalid conversion from ‘int’ to ‘int*’
    //int *ip=i;
    //c  合法
    int *p=&i;
    cout<<p<<"   "<<*p<<endl;
    return 0;
}
0x7ffd6a359b44   2

  


2.22 假设P是一个int类型的指针,说明下述代码的含义。

    if(p) //...p是一个指针,所以这里判断的是,指针p是否指向NULL
    if(*p) //...*p是一个指针指向的值/数据结构,这里判断的是,*p指的对象是否为0

 


2.23 给定指针*p,你能知道它是否指向了一个合法的对象吗?无论能不能,请叙述你的思路。

  这个问题,我个人只能想到通过判断指针是否为空来判断是否指向了对象,但是无法确定对象的合法性。

  下面是GPT给出来的答案,感觉比较全面:

    给定指针*p,我们可以通过以下几种方法来判断它是否指向了一个合法的对象:

    1. 空指针检查:首先,我们可以检查指针*p是否为NULL。如果指针为NULL,表示它没有指向任何对象,因此不是一个合法的对象。

    2. 野指针检查:我们可以尝试访问指针所指向的内存区域。如果访问该内存区域时发生了访问违例(如访问非法地址、访问未初始化的内存等),则可以判断指针指向的对象不是合法的。

    3. 动态内存分配检查:如果指针*p是通过动态内存分配函数(如malloc、new等)分配的内存,则可以通过检查分配函数的返回值是否为NULL来判断分配是否成功。如果分配失败,指针指向的对象不是合法的。

    4. 对象类型检查:如果我们知道指针*p应该指向的对象类型,可以使用类型检查来判断指针是否指向了一个合法的对象。例如,可以使用dynamic_cast或者typeid来检查指针所指向对象的类型是否与预期的类型匹配。

    需要注意的是,以上方法并非绝对可靠,因为在某些情况下,指针可能指向已经释放的内存或者已经销毁的对象。因此,在判断指针是否指向合法对象时,需要综合考虑多种因素,并根据具体情况进行判断。

 


2.24 下面这段代码中为什么指针p合法而指针ip非法?

    int i=42;
    void *p=&i;
    long *ip=&i;

  因为指针和值的数据类型,必须一致,所以ip是错的。

  但是void是一个例外,可以用void型的指针指向任何类型的值

 


2.25 说明下列变量的类型和值

    //a    指针,int,绑定i的引用
    int *ip,i,&r=i;
    //b  int,指针指向null
    int i,*ip=0;
    //c 指针,int
    int *ip,ip2;

 


2.26 下面哪些句子是合法的?如果有不合法的句子,请说明理由。

    const int buf;    //a
    int cnt=0;        //b
    const int sz=cnt;    //c
    ++cnt;++sz;        //d
    
    /*
    a:合法
    b:合法
    c:合法
    d:++cnt合法,++sz非法,因为sz被定义为const int型,不能修改
    */

 


2.27 下面哪些初始化是合法的?请说明原因。

    int i=-1,&r=0;                //a
    int *const p2=&i2;            //b
    const int i=-1,&r=0;        //c
    const int *const p3=&i2;    //d
    const int *p1=&i2;            //e
    const int const &r2;        //f
    const int i2=i,&r=i;        //g
    
    /*
    a:非法。非常量引用的必须为左值
    b:如果i2是int则合法,如果是const int则非法
    c:合法
    d:合法
    e:合法
    f:非法,const必须初始化
    g:合法
    */

 


2.28 说明下面这些定义是什么意思?挑出里面不合法的。

    int i,*const cp;        //a
    int *p1,*const p2;        //b
    const int ic,&r=ic;        //c
    const int *const p3;    //d
    const int *p;            //e

    
    /*
    a:非法。cp要初始化
    b:非法。p2要初始化
    c:非法。ic要初始化
    d:非法。P3要初始化
    e:合法。
    */

 


2.29 假定已有上一个练习中定义的变量,则下面哪些语句是正确的?请说明理由。

    i=ic;        //a
    p1=p3;        //b
    p1=&ic;        //c
    p3=&ic;        //d
    p2=p1;        //e
    ic=*p3;        //f

    
    /*
    a:合法
    b:非法。p3是const型,p1也是才行
    c:非法。p1要是const int的指针才行
    d:合法
    e:合法
    f:非法,ic是const型,不能修改它的值了
    */

 


2.30 对于下面这些对象,请说明被声明成了底层还是顶层const。

    const int v2=0;            //底层
    int v1=v2;                //都不是
    int *p1=&v1,&r1=v1;        //p1,r1都不是
    const int *p2=&v2,*const p3=&i,&r2=v2;    //p2是底层,p3是底层+顶层(指向常亮的常量指针),r2是底层

 


2.31 假设已有上一个练习所做的那些声明,则下面哪些语句是合法的?说明顶层const和底层const在下面的例子中有何体现。

    r1=v2;            //非法,v2是const常亮,而r1不是const型的引用
    p1=p2;p2=p1;    //不能p1=p2,因为p2是const而p1不是,但是反过来可以
    p1=p3;p2=p3;    //不能p1=p3,但是可以p2=p3

 


2.32 下面代码是否合法?如果非法请修正。

    int null=0, *p=null;  //非法
    
    int null=0, *p=nullptr;

 

 


2.33 利用本节定义的变量,判断下列语句的运行结果。

#include <iostream>
using namespace std;
int main()
{
    /*---------------------定义的变量-----------------------*/
        int i=0,&r=i;
        auto a=r;        //a是一个整数
        const int ci=i,&cr=ci;        
        auto b=ci;                //b是一个整数
        auto c=cr;                //c是一个整数
        auto d=&i;                //d是一个整型指针
        auto e=&ci;                //e是一个指向整数常量的指针
        const auto f=ci;//ci的推演类型是int,f是const int
        auto &g=ci;                //g是一个整型常量引用,绑定到ci
        
    
    /*------------------判断下面的结果--------------------*/
    a=42;b=42;c=42;
    d=42;e=42;g=42;
    
    /*
    a为int的42
    b为int的42
    c为int的42
    d为一个int的指针,会报错
    e为const int的指针,会报错
    g为const int的引用,会报错
    */
    return 0;
}

 


2.34 基于上一个练习中的变量和语句编写一段程序,输出赋值前后的内容,你刚才的推断正确吗?不对就去学。

#include <iostream>
using namespace std;
int main()
{
    /*------------------------------------------*/
    int i=0,&r=i;
    auto a=r;        //a是一个整数
    const int ci=i,&cr=ci;        
    auto b=ci;                //b是一个整数
    auto c=cr;                //c是一个整数
    auto d=&i;                //d是一个整型指针
    auto e=&ci;                //e是一个指向整数常量的指针
    const auto f=ci;//ci的推演类型是int,f是const int
    auto &g=ci;                //g是一个整型常量引用,绑定到ci
        
    cout<<"a:"<<a<<endl;
    cout<<"b:"<<b<<endl;
    cout<<"c:"<<c<<endl;

    /*--------------------------------------*/
    a=42;b=42;c=42;
    //d=42;e=42;g=42;
    
    cout<<"new a:"<<a<<endl;
    cout<<"new b:"<<b<<endl;
    cout<<"new c:"<<c<<endl;
    
    
    return 0;
}
a:0
b:0
c:0
new a:42
new b:42
new c:42

  


2.35 判断下列定义推断出来的类型是什么,然后编写程序进行验证。

#include <iostream>
using namespace std;
int main()
{
    const int i=42;
    auto j=i;
    const auto &k=i;
    auto *p=&i;
    const auto j2=i,&k2=i;
    
    /*
    i:const int
    j:int
    k:const int 的引用
    p:const int 的指针
    j2:const int
    k2:const int 的引用
    */
    
    return 0;
}

 


2.36 关于下面的代码,请指出每一个变量的类型以及程序结束的时候它们各自的值。

  这里d是对a的引用,所以改变d等于改变a的值。

#include <iostream>
#include<typeinfo>
using namespace std;
int main()
{
    int a=3,b=4;
    decltype(a) c=a;
    decltype((b)) d=a;
    ++c;
    ++d;
    cout<<"a:"<<a<<endl;
    cout<<"b:"<<b<<endl;
    cout<<"c:"<<c<<endl;
    cout<<"d:"<<d<<endl;
    return 0;
}
a:4
b:4
c:4
d:4

  


2.37 赋值是会产生引用的一类典型表达式,引用的类型就是左值的类型。也就是说,如果i是int,则表达式i=x的类型是int&。根据这一特点,请指出下面的代码中每一个变量的类型和值。

#include <iostream>
#include<typeinfo>
using namespace std;
int main()
{
    int a=3,b=4;        //a:int    b:int
    decltype(a) c=a;    //a:int&   c:int
    decltype(a=b) d=a;    //这里不会改变a的值
             
    printf("%d %d %d %d\n", a, b, c, d);
    
    return 0;
}
3 4 3 3

  


2.38 说明由 decltype 指定类型和由 auto 指定类型有何区别。请举出一个例子,decltype指定的类型与auto指定的类型一样;再举一个例子,decltype指定的类型与auto指定的类型不一样。

   decltype用于从表达式中推导出变量的类型,而auto用于从变量的初始值推导出变量的类型。

一样:

  int x = 10;
  decltype(x) y = x; // y的类型被推导为int
  auto z = x; // z的类型也被推导为int

不一样:

    const int x = 10;
    decltype(x) y = x; // y的类型被推导为const int
    auto z = x; // z的类型被推导为int

 


2.39 编译下面的程序观察运行结果。注意如果忘记写类定义体后面的分号会发生什么情况?

#include <iostream>

struct Foo { }

int main()
{


    return 0;
}

/**
 * [2_39.cpp 2021-02-17 09:53:32.462]
,,2_39.cpp:3:15: error: expected ';' after struct definition
 struct Foo { }
               ^
               ;
*/

 


2.40 根据自己的理解写出sales_data类,最好和书中的例子有所区别。

struct Sales_data{
    //编号
    std::string bookNo[20];
    //价格
    double price;
    //总收入
    double sum=0;
    //数目
    int num=0;
};

 


2.41 使用你自己的Sales_data类重写1.5.1节(第20页)、1.5.2节(第21页)和1.6节(第22页)的练习。眼下先把Sales_data类的定义和main函数放在同一个文件里

2.42 根据你自己的理解重写一个Sales_data.h头文件,并以此为基础重做2.6.2节(第67页)的练习。

#include <iostream>
#include<time.h>
#include<vector>
#include<string.h>
using namespace std;
struct Sales_book{
    //编号
    char bookNo[20];
    //价格
    double price;
    //总收入
    double sum;
    //数目
    int num=0;
};

int main()
{
    vector<Sales_book> data;
    Sales_book book;
    /*----------------1.20---------------------*/
    cout<<"1.20"<<endl;
    while(cin>>book.bookNo)
    {
        cin>>book.price;
        cin>>book.sum;
        cin>>book.num;
        data.push_back(book);
        if (strcmp(book.bookNo,"0")==0) {
            break;
        }
    }
    for(auto &i:data)
    {
        cout<<"part1: "
            <<i.bookNo<<", "
            <<i.price<<", "
            <<i.sum<<", "
            <<i.num<<endl;
    }
    /*----------------1.21---------------------*/
    cout<<"1.21"<<endl;
    Sales_book data1,data2;

    printf("请输入:\n");
    char c=getchar();
    c=getchar();
    while (true)
    {
        cout<<"input:"<<endl;
        cin >> data1.bookNo >> data1.price >> data1.sum >> data1.num;
        cin >> data2.bookNo >> data2.price >> data2.sum >> data2.num;

        if (data1.bookNo == data2.bookNo)
        {
            std::cout << data1.bookNo << ", "
                      << data1.price<<", "
                      << data1.sum + data2.sum << ", "
                      << data1.num + data2.num << std::endl;
            break;
        }
        else
        {
            cerr << "No不一致,重新输入!" << endl;

        }
    }
    /*----------------1.22---------------------*/
    cout<<"1.22"<<endl;
    //...
    /*----------------1.23---------------------*/
    cout<<"1.23"<<endl;
    Sales_book cur_item, item;
    if (cin >>cur_item.bookNo){
        cin>>cur_item.price;
        cin>>cur_item.sum;
        cin>>cur_item.num;
        int cnt=1;
            while(cin >> item.bookNo){
                if(strcmp(trans.bookNo,"0")==0)
                    break;
                cin>>item.price;
                cin>>item.sum;
                cin>>item.num;
                if (item.bookNo ==cur_item.bookNo)
                    ++cnt;              //将cnt加1
                else {
                    cout << cur_item.bookNo <<" occurs "
                               << cnt <<" times "<< endl;
                    cur_item=item;        //记住新值
                    cnt=1;              //重置计数器
                }
            }                       //while循环在这里结束


        cout << cur_item.bookNo <<" occurs "
            << cnt <<" times "<< endl;
    }                               //最外层的if语句在这里结束

    /*----------------1.24---------------------*/
    cout<<"1.24"<<endl;
    //...
    /*----------------1.25---------------------*/
    cout<<"1.25"<<endl;
    Sales_book total;//保存和的变量
    //读入第一条交易记录,并确保有数据可以处理
    if (cin >> total.bookNo)
    {
        cin>>total.price>>total.sum>>total.num;
        Sales_book trans;  //保存下一条交易记录的变量
        //读入并处理剩余交易记录
        while (cin >> trans.bookNo)
        {
            if(strcmp(trans.bookNo,"0")==0)
                break;
            cin>>trans.price>>trans.sum>>trans.num;
            //如果仍在处理相同的书
            if (total.bookNo == trans.bookNo)
            {
                total.num+=trans.num;
                total.sum+=trans.sum;
                total.price=total.sum/total.num;
            }
            else
            {
                //打印前一本书的结果
                cout<< total.bookNo <<", "
                    <<total.price <<", "
                    <<total.sum <<", "
                    <<total.bookNo <<", "
                    << endl;
                strcpy(total.bookNo,trans.bookNo);  //total现在表示下一本书的销售额
                total.price=trans.price;
                total.sum=trans.sum;
                total.num=trans.num;
            }
        }
        cout<< total.bookNo <<", "
                    <<total.price <<", "
                    <<total.sum <<", "
                    <<total.bookNo <<", "
                    << endl;
    }
    else
    {
        //没有输入!警告
        cerr << "No data!" << endl;
        return -1;
    }
    return 0;
}

 


 

posted @ 2023-07-24 17:27  para_dise  阅读(99)  评论(0)    收藏  举报