复习内容

  • 函数重载与继承
  • 指针
  • 排序与查询算法
  • C 语言数组
  • 指针
  • Linux 文件操作

# 选择题 (每题三分)

1、一个 C 程序的 执行 是从 A

(A)本程序的 main函数开始main函数结束

(B)本程序文件的第一个函数开始到本程序文件的最后一个函数结束

(C)本程序的 main 函数开始到本程序文件的最后一个函数结束

(D)本程序文件的第一个函数开始到本程序 main 函数结束

2、若有定义: int a[3][4] ; 不能表示数组元素 a[1][1] 的是 D
a[3][4] 在底层存储使用连续存储,存储方式为:

a[0][0] a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] a[1][2] a[1][3] a[2][0] a[2][1] a[2][2] a[2][3]

(A) *(a[1]+1)       (B) *(&a[1][1])     (C) (*(a+1))[1]       (D) *(a+5)

  • (a+5) 并不是表示 a 的地址加上 5,指向 a[5] 的指针。因为数组 a 只有 3 行,所以 a[5]越界访问 ,正确的当时 *(a[0]+5)

数组元素

3、以下哪一关键字可用于重载函数的区分 C

(A)extern // 全局
(B)static // 静态变量
(C) const // 可用于区分
(D)virtual // 设置虚函数
4、下列有关继承和派生的叙述中,正确的是 C 。

(A)派生类不能访问通过私有继承的基类的保护成员 (不能对外传承)

(B)多继承的虚基类不能够实例化 (X) 可以被实例化 ,就是实例化引入

(C) 如果基类没有默认构造函数,派生类构造函数必须显式地调用基类的带参构造函数

(D)基类的析构函数和虚函数都不能够被继承,需要在派生类中重新实现(构造函数)

派生类需要 确保基类 的成员被正确的 初始化 。如果基类没有默认构造函数,即没有 无参 构造函数,那么派生类无法自动调用基类的构造函数来 初始化基类 的成员。

5、下面程序的输出结果是 A 。

#include <iostream.h>  // 不带.h
using namespace std;
void swap1(int &v1, int &v2) // 取地址实现交换
{
	int tmp = v2; v2 = v1; v1 = tmp;
}
void swap1(int *v1, int *v2)  // 地址交换
{
	int tmp = *v2; *v2 = *v1; *v1 = tmp;
}
void main()
{
    int i = 10, j = 20; 
    swap1(i, j);
    swap1(&i, &j);
    cout << i <<,<< j << endl;
}

(A) 10,20

(B)20,10

(C)10,10

(D)20,20

6 、用某种排序方法对关键字序列 {35,84,21,47,15,27,68,25,20} 进行排序时,序列的变化情况如下:

20,15,21, 25 ,47,27,68,35,84

15, 20 ,21,25,35,27, 47 ,68,84

15,20,21,25,27,35,47,68,84

则采用的方法是 。

(A)直接选择排序

(B)希尔排序

(C)堆排序

(D)快速排序

7、队列通常采用两种存储结构是 A

(A) 顺序存储结构链表存储结构

(B)散列方式和索引方式

(C)链表存储结构和数组

(D)线性存储结构和非线性存储结构

8、C++ 基类中的 private 成员通过 A 类型的继承,可以被派生类访问。

(A) public

(B)protected

(C)private

(D)任何类型的继承都不能使得派生类可以访问基类的 private 成员

9、如果基类 A 和 A 的派生类 B 中都有成员函数 func() ;要在派生类的 func() 中调用同名的 基类 的 func () 成员函数,下列 B 操作是正确的。

(A)func();

(B) A::func();

(C)B::func();

(D)A.func();

10、下面对静态数据成员的描述中,正确的是 A 。 static

(A) 静态数据成员是类的所有对象共享的数据

(B)类的每个对象都有自己的静态数据成员

(C)类的不同对象有不同的静态数据成员值

(D)静态数据成员不能通过类的对象调用 (静态数据成员可以通过类的对象或者类名加作用域运算符来访问和调用。)

11、下列代码的输出内容是 C

#include<stdio.h>

main()

{

int a, b, c, d;

a = 10;

b = a++;

c = ++a;

d = 10*a++;

printf("%d,%d,%d",b,c,d);

return 0;

}

(A)13,12,120   (B)10,11,120  (C) 10,12,120    (D)10,12,130

12、c++ 中以下关于函数调用说法正确的是 D

(A)传地址后实参和形参指向不同的对象 (X)

(B)传引用后实参和形参是不同的对象 X

(C)传值后对形参的修改会改变实参的值 X

(D)其他三项都不对

# 填空题 (每题 5 分)

1 、下列中 a 的值是 400

#defineAAA200
#defineBBBAAA+100   //define 仅是代码替换
int a = BBB*2   // 得出结构为 AAA+100*2 仅是代码替换,得出的结果是 400

2、使用 函数重载 的方法可以实现编译时多态,使用 虚函数 的可以实现 运行时 多态。

3、程序的局部变量存在于 中,全局变量存在于 静态区 中,动态申请数据存在于 中。

# 简答题 (每题 5 分)

1、用变量 a 给出下面的定义

(A)一个指向整型数的指针 int*a

(B)一个有 10 个指针的数组,该指针是指向一个整型数 int *a[10]

(C)一个指向有 10 个整型数组的指针 int (*a)[10]

(D)一个指向函数的指针,该函数有一个整型参数并返回一个整型数 typedef int(*a)(int)

(E)一个有 10 个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数 int (*a[10])(int)

3、一块 N 个字节的内存,它的首地址(头指针)为 pStart ,那么末地址为

pStart+N-1 首地址占用一个空间

4、计算下面结构体的大小,标注每个结构体成员的大小

typedef struct _a  14
{ 
   char c1; 1
   long i;  4  648个字节
   char c2; 1
   double f; 8
}a; 
typedef struct _b 
{ 
  char c1; 1
  char c2; 1
  long i;  4
  double f; 8
}b;

# 问答题 (每题 5 分)

# 第一题

查找单向链表 倒数第k 个位置上的结点。

不改变链表 的前提下,请设计一个 尽可能高效的算法 ,查找链表中倒数第 k (k> 0) 个位置的节点。

struct Node {
int  val;
Node *  next;
Node(int x) : val(x), next(NULL) {}
};

# 答:

建立 两个 单链表 子链 ,一个链表向 末尾next ,当到 第search个节点 时,另一个节点也开始从 头部next ,当一个链表 到达末尾 ,另一个 链表正好 位于 倒数第seach个 节点。时间复杂度 O(n) , 空间复杂度 O(n) ;

#include <iostream>
using namespace std;
struct Node {
    int       val;
    Node *   next;
    Node(int x) : val(x), next(NULL) {}
};
Node* search(struct Node *node,int search)  // 返回倒数第 search 个节点
{
    // 定义两个节点一个向前走,一个维持 k 的位置
    Node* p = node;
    Node* search_p = node;
    int number = 0;
    while (p!=nullptr) // 当判运行到结尾
    {
        p = p->next;
        number++;
        if (number > search)  //seatch_p 从 search 位置开始往后移动
        {
            search_p = search_p->next;
        }
    }
    if (search <= number)
    {
        // 搜索到了
        return search_p;
    }
    else
    {
        //node 节点没有倒数第 seach 个
        return nullptr;
    }
}
int main(void)
{
    // 初始化
    Node* nodes = new Node(NULL);
    Node* node = nodes;
    for (int i = 0; i < 10000; i++)
    {
        Node* add = new Node(i);
        node->next = add;
        node = node->next;
    }
    struct Node* p = search(nodes, 7);
    if (p != nullptr)
    {
        cout << "倒数第7个数值为:" << p->val << endl;
    }
    else
    {
        cout << "Nodes节点总数不满足seach要求" << endl;
    }
    delete nodes;
	return 0;
}

# 第二题

以下程序,会存在什么问题?如果有问题,请更正.

void GetMemory(char *p) 
{
    p = (char *)malloc(100);
} 
void Test(char *s) 
{ 
    char *str = NULL; 
    GetMemory(str); 
    strcpy(str, s); 
    printf(str); 
}

#

  • str字符 串空间分配问题, GetMemory`并没有分内存给`str`,需要调用str的`二重指针 ,传递给参数,来进行空间 赋值
  • 空间大小问题,申请空间可能会因为申请空间过小而发生溢出。
  • 使用过后,需 空间释放避免 出现 野指针
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
void GetMemory(char** p)
{
    *p = (char*)malloc(100); //*p 获取 str // 空间大小问题若输入过大会溢出
}
void Test(char* s)
{
    char* str = NULL;
    //P 的申请空间,并没有赋值给 str
    GetMemory(&str);// 传递 &str 来获取 str 的地址。
    //s 空间大于 str 申请的空间出现移除
    strcpy(str, s);
    
    printf(str);
    free(str);
}
int main(void)
{
    char s[100] = "TLove YOU,heihahiehahieha";
    Test(s);
    return 0;
}

# 第三题

代码 存在 什么 缺陷 ,请进行说明并将修改的贴上来

unsigned long long fun(unsigned long long a, unsigned long long b)
{
        return (a + b) / 2;
}

#

  • long long 解决 a+b 可能的 溢出 。但是吧!(其它暂时没有发现)
unsigned long long fun(unsigned long long a, unsigned long long b)
{
    // 如果 a+b 超过了最大,可能出现移除问题
    return (a + b) >> 1; // 使用位运算进行除以 2 操作
}

# 第四题

代码存在什么缺陷,请尝试修改,将修改的贴上来

bool cmp(double a, double b, double c)
{
    return (a + b) == c;
}

#

浮点数双精度 末尾数具有 不确定性 ,一般用 减法 判断

  • 浮点精度存在限制 (a + b)c 的差的绝对值是否小于某个小的阈值来进行判断
  • 传入值的判断

双精度浮点数

#include <iostream>
using namespace std;
bool cmp(double a, double b, double c)
{
    if (a == NULL || b == NULL || c == NULL)
    {
        cout << "exit parameter null" << endl;
        return false;
    }
    //return (a + b) == c;
    return a + b - c < 0.000000000001;
}
int main(void)
{
    double a = 3.14526;
    double b = 3.96515;
    double c = 7.11041;
    if (cmp(a, b, NULL)) // 在单计算上时相等的,但是 double 后面的位数具有随机性要用减法
    {
        cout << "得出相等" << endl;
    }
    else
    {
        cout << "不相等哟或异常" << endl;
    }
        
}

# 第五题

以下代码存在什么问题,请指出,并将修改后的代码贴出。 文件一定考

void read_file(FILE* file, size_t filesize)
{
    char* buffer = (char*)malloc(filesize);
    if (NULL != buffer)
    {
        memset(buffer, 0, filesize);
        fread(buffer, filesize, 1, file);
        printf("%s\n", buffer);
        free(buffer);
        buffer = NULL;
    }
}

#

不健壮 ,修改一些 bug 和可能得错误

文件是否 打开filesize 是否正确,是否完全将 数据读完

void read_file(FILE* file, size_t filesize)
{
	if (file == nullptr || filesize <= 0)
	{
		printf("read_file init error");
		return;
	}
	// 申请内存空间
	char* buffer = (char*)malloc(filesize);
	if (buffer == nullptr)
	{
		printf("Memory allocation failed.\n");
		return;
	}
	// 对申请的空间 buffer 的 filesize 大小空间设置为 0
	memset(buffer, 0, filesize);
	// 读取 file 的内容 filesize 要读元素快的大小,1 为元素个数,存档到 buffer 里面,成功返回 filesize 大小
	size_t count = fread(buffer, filesize, 1, file);
	if (count != filesize)
	{
		printf("Error reading the file\n");
		free(buffer);
		buffer = NULL;
		return;
	}
	printf("%s\n", buffer);
	free(buffer);
	buffer = NULL;
}

# 第六题

以下代码存在什么问题,请指出,并将修改后的代码贴出。

vector<int> vecTest = { 1,2,3,4 };
vector<int>::iterator iter1;  
for (iter1 = vecTest.begin(); iter1 != vecTest.end(); iter1++){
    printf("%d ", *iter1);
    if (*iter1 == 3) {
     	vecTest.erase(iter1);
    }    
}

# 答:

在删除 iter1 之后, 迭代器iter1 失效,无法再继续进行 遍历或递增 操作,产生 未定义

erase 删除之后,将会 返回vector删除位置 的写一个迭代器

vector<int> vecTest = { 1,2,3,4 };
vector<int>::iterator iter1;   // 好奇怪,
for (iter1 = vecTest.begin(); iter1 != vecTest.end();)
{
    printf("%d ", *iter1);
    if (*iter1 == 3)
    {
        iter1 = vecTest.erase(iter1); 
        // 指向被删除元素的下一个元素的位置
    }
    else
    {
        iter1++;
    }
}

# 第七题

以下代码存在什么问题,请指出。

queue<int*> testQueue; // 队列 先进先出
for (int i=0; i< 10000000; i++)
{
    int* p = new int(i);
    testQueue.push(p); 
}
for (int i=0; i < 10000000; i++)
{
    int* p = testQueue.front();
    testQueue.pop();		
	if (p)
    {
        delete p;
        p = NULL;
    }
}

# 答:

除了最后释放内存的可能存在的 内存泄漏 ,和 健壮问题 ,暂时没发现其它问题

#include <iostream>
#include <queue> // 队列
using namespace std;
int main(void)
{
    queue<int*> testQueue; // 队列 先进先出
    for (int i = 0; i < 10000000; i++)
    {
        int* p = new int(i);
        if (p == nullptr)
        {
            cout << "new p error:" << i << endl;
        }
        testQueue.push(p);
    }
    while(!testQueue.empty())
    {
        int* p = testQueue.front();
        testQueue.pop();
        if (p)
        {
            delete p;
            p = nullptr;
        }
    }
}