自学内容网 自学内容网

C++学习笔记01-语法基础(问题-解答自查版)

前言

以下问题以Q&A形式记录,基本上都是笔者在初学一轮后,掌握不牢或者频繁忘记的点

Q&A的形式有助于学习过程中时刻关注自己的输入与输出关系,也适合做查漏补缺和复盘。

本文对读者可以用作自查,答案在后面,需要时自行对照。

--

问题集

Q1:结构化编程?C++的核心:OOP和泛型编程?

Q2:关于头文件命名,#include 合规,#include 语法没有错误,为什么却编译报错?

Q3:using namespace std; 中,using语法是属于编译指令吗?namespace的作用域的设计目的?

Q4:cout << 中的 “<<” 运算符叫什么名字?stream/流 是什么?控制符(manipulator)是什么?

Q5:const在C和C++的区别?const安全的底层原理?

Q6:在函数运行中定义变量合适吗?推荐做法是什么?a的值会随着循环每次变化吗?eg :

int main() {
    while(1) {
        int a = 0; print(a++);   // 这里的 定义int a变量是合理的吗?
    }
}

Q7:C风格中,原来需要预处理的 xxx.h 头文件在C++的新方式?

Q8:int在不同系统上可能有不同的位数表现(16bits/32bits),那么有办法设置int位宽吗?

Q9:以下两条语句的含义?

        int a{5};

        int b = {5};

Q10:unsigned类型有浮点数吗?

Q11:如果提前知道变量可能表示的int值大于16位,则推荐使用 long 而不是 int(大于20e则使用 long long),why?

Q12:伪代码 int a + bool b 的执行结果如何?其背后原理?进一步地,两个float数 f1+f2 内部运算是怎么样的?

Q13:语句 short i;  cout << int(i); 的含义是什么?为什么要这样设计?这里的int()是一个函数吗?

Q14:关于auto关键字原初的设计意图?

Q15:char a[n] 和 string的本质区别?

Q16:关于连续使用cin,我们已知的问题是第一个cin随着回车会导致遗留\0到下一个cin被读到

标准的解决方式是什么?

Q17:输出结果?

cout << R"(Jim "King" Tutt uses "\n" instead of endl.)" <<'\n';

Q18:C++允许在声明结构变量时省略关键字struct?

Q19:bit field 是什么?(也叫位域,From 小盖伦er)

Q21:关于枚举型变量对象band,下面几个表达式的正确性?(思考:enum-整型之间的提升)

Q22:指针的危险?(与之关联:Q27)

Q23:指针解引用之前的金科玉律?(这个学过c都会,跟Q22一样看看即可)

Q24:动态数组?动态联编?如何创建?如何释放?

Q25:对于C++, int *psome = new int[x]; 这个语句中,sizeof(psome)代表什么?sizeof(*psome)又代表什么?

Q26:p是一个指针,那么 p = p+1 之后,p指向哪?(以C++11标准-巩固)

Q27:假设有一个字符串 str1,那么下面的表达式语法合理吗?

        str1 [-1]

        *(str1 - 1)

Q28:除了vector和 xx[ ],还有什么方式可以表示数组?

Q29:关于vector和array,vector的底层实现是什么?

Q30:二维数组在内存的空间地址是连续的么?

Q31:关于RAII,说说RAII的简单理念是什么?

Q32:比起 cin >> sr.arr 说说这里为什么用 cin.getline() ?


参考解答

Q1:结构化编程?C++的核心:OOP和泛型编程?

A1:结构化编程简单来说就是 if-else 等结构的使用,属于早期设计。OOP+泛型编程是C++核心

Q2:关于头文件命名,#include 合规,#include 语法没有错误,为什么却编译报错?为什么这样设计?

A2:其实这两种都是支持的。但是

1)<iostream.h> 是一个过时的包含方式,编译器所选定的标准可能不支持了
2)<iostream> 将库的内容包含在  std 命名空间中,这有助于避免命名冲突,是现代C++编程中推荐的做法。

Q3:using namespace std; 中,using语法是属于编译指令吗?namespace的意义是什么?

A3:namespace 的作用:一个潜在的问题是,可能使用两个已封装好的空间,它们都包含一个名为 xxx() 的函数。

这样,使用 xxx() 函数时,编译器将不知道指的是哪个版本。命名空间是为了避免这个问题。

eg:

        Microflop::wanda("go dancing?");

        Piscine::wanda("a fish named Desire");

using namespace std; 的作用域:affects all function definitions in this file;也就是一次using会影响整个.cpp

Q4:cout << 中的 “<<” 运算符叫什么名字?stream/流 是什么?控制符(manipulator)是什么?

A4:

        “<<” 运算符是重载之后,根据实际功能的定义,在cout语境下为“插入”。(形同左移,但不是左移)
        endl 是一个典型的控制符,由iostream中定义,且位于std中,在输出流中插入endl将导致屏幕光标移到下一行开头。

Q5:const在C和C++的区别?为什么const在C++中相对安全一些?

A5:const在C++中不能被通过&的方式进行改写。主要的操作是在编译阶段把这个const修饰的变量偷换了,让程序员没法找到他。

Q6:在函数运行中定义变量合适吗?推荐做法是什么?a的值会每次变化吗?eg :

int main() {
    while(1) {
        int a = 0; print(a++);
    }
}

A6:在C中,所有的变量声明通常都位于函数或过程的开始位置,但C++没有这种限制。

不过,对于声明变量,C++的做法是尽可能在首次使用变量前声明它,以便于清楚的看出哪些在一起被定义了。

这个程序打印的结果是000000,说明 int a 在每次循环都会刷新。这里引用我和kimi的问答解释:

        Q:C++中的这段代码,变量a会不断地定义吗?还是说只是被赋值?

        A:在您提供的C++代码片段中,变量 a 会在每次 while 循环的开始时重新定义,并初始化为 0。

        这意味着每次循环都会创建一个新的局部变量 a,并且每次都会从 0 开始。

        Q:这个a变量的生命周期是仅在这次循环中?所以被创建在栈空间,在循环结束的时候被释放对吗?

        A:是的,您的理解是正确的。在C++中,局部变量(如在 while 循环中定义的变量 a)的生命周期仅限于它们被定义的代码块。一旦代码块执行完毕,局部变量就会被销毁,其占用的内存(在栈上)也会被释放。

Q7:math.h头文件在C++的新版本?

A7:cmath

Q8:int在不同系统上可能有不同的位数表现(16bits/32bits),那么有办法设置int位宽吗?

A8:标准C++并没有提供直接设置,但可以查。查 int 位宽的方法:在<climits>头文件中,通过宏 INT_MAX

Q9:以下两条语句的含义?

        int a{5};

        int b = {5};

A9:一种不是很常见,但实际是为新手考虑的变量赋值方法——列表初始化。

其内在设计思路是:将大括号 { } 作为一种通用的初始化器,对所有不同类型的变量进行统一化赋值

对于列表初始化有一定要求,就是不允许“缩窄”,即不能用越界赋值。这里考虑安全也不允许使用变量,避免运行时不安全:

Q10:unsigned类型有浮点数吗?

A10:原文:注意, unsigned 本身是unsigned int 的缩写。

Q11:如果知道变量可能表示的int值大于16位,则使用long(大于20e则使用 long long),why?

A11:这样,将程序移植到16位系统时,就不会因为int范围改变导致突然无法正常工作。

所以即使系统上 int 为32位,也应这样做。

Q12:伪代码 int a + bool b 的执行结果如何?

        其背后的原理是什么?进一步地,两个float数 f1+f2 其内部运算是怎么样的?

    int  a = 1;
    bool b = true;
    cout << a+b;

A12:int a + bool b 会整形提升为 int a + int b,f1+f2 会提升为 double a + double b

Q13:语句 short i;  cout << int(i); 的含义是什么?为什么要这样设计?int是一个函数吗?

A13:这里是C++的强制转换语法,但只是看起来像是函数,实则不然

Q14:关于auto关键字的设计意图?

A14:自动推导那些不容易由程序员设计所产生变化的复杂类型,尤其是STL的iterator类型

Q15:char a[n] 和 string的本质区别?

A15:

Q16:关于连续使用cin

我们已知的问题是第一个cin随着回车会导致遗留\0到下一个cin被读到,标准的解决方式是什么?

A16:从cin后面补充一个 cin.get()

        cin >> year;

        cin.get();

        也可以利用表达式 cin>>year 返回 cin 对象,将调用拼接起来:

        (cin >> year).get();

 Q17:输出结果?

cout << R"(Jim "King" Tutt uses "\n" instead of endl.)" <<'\n';

A17:前缀R:输出原始字符串

        上述代码将显示如下内容:

        Jim "King" Tutt uses \n instead of endl //特别注意:这里的 "\n" 变成了 \n,但不是粗暴的去除""

Q18:C++允许在声明结构变量时省略关键字struct?

A18:yes:

Q19:bit field 是什么?(位域)

A19:

经过代码验证,位域的内存占用并不是简单地取4字节对齐(或者说存储字长对齐),而是根据以下因素决定的:

        1)位域的位数 2)结构体的内存对齐

        举个例子:假设一个结构体中有一个位域和一个整数成员,位域占用了23位,整数成员占用32位。那么,位域会占用3个字节(23位 / 8位/字节 = 2.875字节,向上取整为3字节),整数成员会占用4字节。整个结构体的总大小可能会因为整数成员的对齐而增加到 8字节。

        示例代码如下:

struct Example {

    bool flag : 1; // 占用1位

    unsigned int value : 23; // 占用23位

    int data; // 占用4字节

};

但要注意,有的编译器会把不同类型的数据分成不同位域,上面的代码会输出示例 Example e 的大小为12字节。

具体是8字节还是12字节,以编译器自己的对齐和打包规则为准!

Q20:union主要用来省内存。目前作用不大了。等于一个可选类型变量

Q21:关于枚举型变量对象band,下面几个表达式的正确性?(思考:enum-整型之间的提升)

A21:枚举可以被看作是整型的扩展,看起来好像 “整型是基类,枚举是整型的派生”。

这里扩充两个小知识:

1)枚举不能++操作 2)更有迷惑性的 enum = int 型赋值错误

虽然尝试直接将整型变量 i 赋值给枚举变量 c 是不允许的,但是,通过使用 static_cast<>,可以显式地将整型转换为枚举类型。

Q22:指针的危险

A22:

Q23:指针解引用之前所谓的“金科玉律”?

A23:

Q24:动态数组?动态联编?如何创建?如何释放?

A24:

创建:int *psome = new int[10];

释放:delete [ ] psome;

使用 new 时,如果在运行阶段需要数组,则创建它,如果不需要则不创建。

关于释放:如果使用 new[] 为数组分配内存,则应使用delete [] 来释放。

Q25:对于C++, int *psome = new int[x]; 这个语句

        sizeof(psome)代表什么?

        sizeof(*psome)代表什么?

A25:这段代码是创建了一个动态数组,其中,sizeof(*psome)表示的是psome指针所指向的对象的类型 int 的大小。

它只表示单个int类型的大小,与x无关,也就是 sizeof(int)

由于psome是一个指向int的指针,*psome表示的是psome所指向的int变量的值。

那么是否能查找到动态数组的大小呢?答案是:程序跟踪了由 new int[] 创造的数组大小,用于delete [],但由于信息不公开,所以不能通过sizeof() 的方式来对整个动态数组的大小进行查询。

Q26:p是一个指针,那么 p = p+1 之后,p指向哪?

A26:将指针变量加1后,增加的量等于它指向的类型的字节数。

Q27:假设有一个字符串 str1,那么下面的语法合理吗?

        str1 [-1]

        *(str1 - 1)

A27:至少合法。与C语言一样,C++默认也不检查这种超界错误,无论是数组,vector还是array

Q28:除了vector和xx[ ],还有什么方式可以表示数组?

A28:在这些如array的模板类中,有很多设计是为了防止越界而进行设计的。

Q29:关于vector和array,vector的底层实现是什么?

A29:vector的底层实现是array,大小可变,注意添加删除操作实际上就是array重建,然后动态地管理len大小

Q30:二维数组在内存的空间地址是连续的么?

A30:不同编程语言的内存管理是不一样的,以C++为例,在C++中二维数组是连续分布的。

Q31:关于RAII,说说RAII的简单理念是什么?

A31:RAII(Resource Acquisition Is Initialization) 是 C++ 中一种重要的编程技术。

它通过对象的生命周期来管理资源,确保资源在使用完毕后能够被正确释放。

说白了也很简单,就是让设计好的构造析构函数对申请和释放进行封装,避免遗忘的同时,便于找到内存问题的根源:

#include<cstdio>
#include<iostream>

using namespace std;

class safeResource{
public:
    int name;
    char *arr;        // 这里维护一个动态数组
    safeResource(){
        arr = new char[5];    // 构造申请
    }

    ~safeResource(){
        delete [] arr;        // 析构释放
    }
};

int main(){
    safeResource sr;
    if(!cin.getline(sr.arr, 5)){
        cout << "input error" << endl;
    }
    cout << sr.arr << " " << endl;
    return 0;
}

Q32:比起 cin >> sr.arr 说说这里为什么用 cin.getline() ?

    // sr.arr 是一个动态数组的起始地址
    if(!cin.getline(sr.arr, 5)){
        cout << "input error" << endl;
    }

A32:虽然用 cin >> sr.arr 也能通过,但是 cin 的方法不会自带一个 '\0'

        getline的方法就可以为 sr.arr 附带一个可靠的结束符号,经测试,即使是输入多了,最后一个字符仍然是\0,其他则被丢弃。

        并且 cin.getline 的方法更易于异常处理。

Q33:在大多数现代系统上,指针的大小通常是 4 或 8 字节(取决于_____)

A33:系统是32位还是64位


原文地址:https://blog.csdn.net/qq_29068607/article/details/140616471

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!