本文最后更新于:2020年4月28日 凌晨

昨天在拉勾上投了鲁大师的C++实习岗位,今天下午接到了HR的电话,商量了下晚上七点做笔试。

没有使用在线笔试平台,HR直接发给我的一个word文档。简要记录一下,以下解答为笔试结束后整理~

题目一:符号&的意义

题目:下列几个C语言表达式是否正确?如果正确,写出它们表达的意思:

  1. a&b
  2. a&(&b)
  3. a&&b
  4. a**b

解答:

  1. 正确。结果为 ab 的二进制按位相与;
  2. 不正确。括号内为取址符,取变量 b 的地址;括号外为按位与运算;
  3. 正确。逻辑运算符,当且仅当 ab 同时为真时,结果为真;
  4. 正确。前一个为乘法运算,后一个表示指针,即变量 a 乘上指针 b 所指向的变量的值。

题目二:内存分配

题目:char a[] = "Hello"; sizeof(a) 是多少?char *b= "Hello"; sizeof(b) 是多少?

解答:

  1. char a[] = "Hello"; sizeof(a)6。五个字符加一个结束符 '\0'

  2. char *b= "Hello"; sizeof(b) 在32位系统下是 4 ,64位系统下是 8 ,即 sizeof(char*) 的大小。

题目三:宏定义

题目:#ifndef#define#endif 是做什么用的?构思一个场景用一下。

解答:

宏定义。#define 为定义一个宏;#ifndef 判断一个宏是否已经定义过,避免重复定义;#endif 搭配 #ifndef 使用,结束判断。

场景:可以用于头文件的引用,多文件相互引用时,可能会存在重复引用的情况,这时就可以先判断一个头文件是否已经引用,如果未引用,则通过宏定义引用,否则不再重复引用。

题目四:static

题目:C语言函数前面加static,和C++类的成员函数前面加static,两者的意义有何区别?

解答:

在C和C++中 static 都有扩展生存周期的作用,static 静态变量在其作用范围内仅进行一次初始化操作。

C++中在类的成员函数前面加 static 表示该函数为静态成员函数,这个函数不属于这个类的任何一个实例化对象,而仅属于这个类,并且静态成员函数内部也不能访问该类的非静态成员。

C/C++ 中 static 的用法全局变量与局部变量:https://www.runoob.com/w3cnote/cpp-static-usage.html

题目五:找出程序的问题

题目:这段代码有哪些问题。

char* GetTextA(void)
{
   char p[] = "AAAAAAAA";
   return p;
}

char* GetTextB(void)
{
   char *p = "BBBBBBBB";
   return p;
}

void main(void)
{
   char *p = NULL;
   p = GetTextA();
   printf(p);
   p = GetTextB();
   printf(p);
}

解答:

  • char* p = "BBBBBBBB";"BBBBBBBB"const char* 类型的常量,不能用来初始化一个 char* 类型的变量。可以使用 const_cast<>() 函数去除常量性,也就是可以将该语句更改为:char* p = const_cast("BBBBBBBB");
  • 函数GetTextB(void)GetTextB(void) 中的变量 p 为局部变量,作用域为所在的函数内部,函数调用结束后变量 p 所占用的内存就会被释放掉,而 main() 函数中的指针 p 仍指向已释放内存的地址,输出的结果将是无意义的。一个简单的解决办法是,可以将两个函数中的 p 声明为 static 的,延长其生命周期,直到程序运行结束以后才释放。(参考题目四)

修改后的代码为:

char* GetTextA(void)
{
    static char p[] = "AAAAAAAA";
    return p;
}

char* GetTextB(void)
{
    static char* p = const_cast<char*>("BBBBBBBB");
    return p;
}

void main(void)
{
    char* p = NULL;
    p = GetTextA();
    printf(p);
    p = GetTextB();
    printf(p);
}

题目六:内存泄漏

题目:什么是内存泄漏?

解答:由于疏忽或错误造成程序未能释放已经不再使用的内存。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,导致在释放该段内存之前就失去了对该段内存的控制,从而造成了内存的浪费。(来自维基百科

题目七:Windows API

题目:描述三个 Windows API。(用途、大致用法)

解答:API Index for desktop Windows applications:https://docs.microsoft.com/en-us/windows/win32/apiindex/api-index-portal

题目八 unsigned long 转字符串

题目:写程序,把 unsigned long 型变量转为字符串。在函数调用上,只允许使用 malloc 这个函数,无需 free,不准调用其它函数。如果不调用任何函数更好。如果使用数组要指出数组大小的设置理由。用注释指出哪个变量是结果即可,无需输出。

解答:

string ultostr(unsigned long n) {
	string str = "";
	while (n != 0)
	{
		unsigned long x = n % 10;
		str.insert(str.begin(), '0' + x);
		n /= 10;
	}
	return str;//结果
}

题目九:统计字母出现的次数

题目:写程序,输入一个由英文小写字母组成的字符串,字母可重复出现,'0' 结尾,统计每个字母出现的次数。输出格式自定。

解答:

笔试的时候连题目都搞错了,因为前些天刚做过压缩字符串的题目,那个题是把连续相同的多个字符压缩为两个个数加该字符,例如字符串 "aaabbbbcc" 就可以压缩为 "3a4b2c" 。但是,这个题目它不一样吖,人都傻了……

'0' 应该也是字符串的一部分,解题的时候我并没有把它作为字符串的一部分。

#include <iostream>
#include <vector>
using namespace std;

int main() {
	string str = "";
	char c;
	while (cin >> c)
	{
        str += c;
		if (c == '0') {//'0'应该也是字符串的一部分
            break;
        }
	}
	
	vector<pair<char, int>> vec;//存储统计信息
	for (int i = 0; str[i] != '0'; i++) {
		bool exist = false;
		for (int j = 0; j < vec.size(); j++) {
			if (str[i] == vec[j].first) {
				exist = true;
				vec[j].second++;
				break;
			}
		}
		if (exist == false) {
			vec.push_back({ str[i],1 });
		}
	}
	//输出统计结果
	for (auto v : vec) {
		cout << v.first << v.second << endl;
	}
    return 0;
}

题目十:字符串查找

题目:完成这个程序。input 是一个由英文小写字母组成的字符串,'0' 结尾。sub_string 是一个由英文小写字母组成的字符串,'0' 结尾。要查找 sub_stringinput 中第一次出现时的位置(返回这个地址),如果没找到,则返回 NULL 。不准调用任何函数。

char* strstr(char *input, char *sub_string)
{
	...
}

解答:

笔试的时候做的这个题直接写的代码,都没来得及调试,实际上也确实写错了,其中找到的几个问题:

  • '0' 也应该是字符串的一部分;
  • sub_string 的遍历不应该以 NULL 作为结束标志,而是 '\0'
  • 二层循环对字符进行遍历,应该更新指针,最初的代码忘了更改指针了。
char* strstr(char* input, char* sub_string)
{
	char* ans = new char();//结果
	char* s1 = input;
	char* s2 = sub_string;
	while (s1 != NULL)
	{
		if (*s1 == *s2) {
			ans = &(*s1);
			bool find = true;
			while (*s2 != '\0')//NULL不是结束标志
			{
				if (*s1 != *s2) {
					find = false;
					break;
				}
                //更改指针指向下一个字符
				s1++;
				s2++;
			}
			if (find) {
				break;
			}
			else {
				s1 = ans;
				s2 = sub_string;
			}
		}
		s1++;
	}
	return ans;//返回结果
}