1. C/C++笔试面试经典题目一
1. 不用循环和递归,实现打印数字0到999。
1 #include <iostream> 2 #include<stdio.h> 3 using namespace std; 4 5 #define A(x) x;x;x;x;x;x;x;x;x;x; 6 7 int main(void) 8 { 9 int n = 0; 10 11 A(A(A(printf("%d\n", n++)))); 12 13 system("pause"); 14 return 0; 15 }
2. 写一个函数找出一个整数数组中第二大的数。
如:a[10]={1,2,3,4,5,6,7,8,9,10} ==> nextmax = 9;
a[10]={1,2,3,4,5,6,7,10,10,10} ==> nextmax = 7;
a[10]={8,8,8,2,8,8,8,8,8,8} ==> nextmax = 2;
a[10]={8,8,8,8,8,8,8,8,8,8} ==> nextmax = 不存在;
1 // C语言实现如下 2 #include <stdio.h> 3 #include <stdlib.h> 4 5 int getmax(int *p, int n) 6 { 7 //假定第一个数最大,与剩下的数逐一进行比较 8 int maxdata = p[0]; //最大数的值 9 int maxi = 0; //最大数的下标 10 11 for (int i = 1; i < n; i++) 12 { 13 if (maxdata<p[i]) 14 { 15 maxdata = p[i]; 16 maxi = i; 17 } 18 } 19 20 return maxi; //返回下标 21 } 22 23 void swap(int *p1, int *p2) //根据地址交换两个变量 24 { 25 int temp = *p1; 26 *p1 = *p2; 27 *p2 = temp; 28 } 29 30 31 void main() 32 { 33 int a[10] = { 8,8,8,8,5,8,8,8,8,8 }; 34 //printf("%d\n", getmax(a, 10)); 35 int maxi = getmax(a, 10); //保留最大值的下标 36 int max = a[getmax(a, 10)]; //保留最大值 37 38 swap(&a[0], &a[maxi]); 39 40 int i = 1; 41 int flag = 0; //0代表没有第二大的数,比如全部相同时 42 while (i<10) 43 { 44 int nextmaxi = i + getmax(a + i, 10-i); //注意下标+1 45 int nextmax = a[nextmaxi]; 46 47 if (max != nextmax) 48 { 49 printf("\nnextmax = %d", nextmax); 50 flag = 1; //代表数组并非全部相同 51 break; 52 } 53 54 swap(&a[i],&a[nextmaxi]); 55 i++; 56 } 57 58 if (!flag) 59 { 60 printf("next max不存在"); 61 } 62 63 system("pause"); 64 return ; 65 }
3. 看程序写结果:
char str1[] = "abc"; char str2[] = "abc"; const char str3[] = "abc"; const char str4[] = "abc"; const char *str5 = "abc"; const char *str6 = "abc"; char *str7 = "abc"; char *str8 = "abc"; cout << (str1 == str2) << endl; //0 不等 cout << (str3 == str4) << endl; //0 cout << (str5 == str6) << endl; //1 相等 cout << (str7 == str8) << endl; //1
4. 结构体重要考点:
struct name1 { char t; char k; unsigned short i; unsigned long m; }; struct name2 { char str2; short x2; int num2; }; struct name3 { char str3; int num3; short x3; }; printf("%d\n", sizeof(name1)); //8 printf("%d\n", sizeof(name2)); //8 printf("%d\n", sizeof(name3)); //12
5. 用宏定义写出swap(x,y),即交换两数。
1 #include <iostream> 2 using namespace std; 3 4 //方法一:加减 5 #define swap(x,y) (x)=(x)+(y);(y)=(x)-(y);(x)=(x)-(y); //注意需要加上() 6 7 //方法二:异或 8 #define swap(x,y) (x)=(x)^(y);(y)=(x)^(y);(x)=(x)^(y); //注意需要加上() 9 10 void main() 11 { 12 int a = 10, b = 20; 13 cout << "交换前:" << endl; 14 cout << "a:" << a << " " << "b:" << b << endl; 15 16 swap(a, b); 17 18 cout << "交换后:" << endl; 19 cout << "a:" << a << " " << "b:" << b << endl; 20 21 system("pause"); 22 return ; 23 }
6. 指针与整数相加: ====>与类型密切相关!
unsigned char *p1; unsigned long *p2; p1 = (unsigned char *)0x801000; p2 = (unsigned long *)0x810000; cout << p1 + 5 << endl; //0x801005 cout << p2 + 5 << endl; //0x810020
7. 数组指针的步长问题:
int a[5] = { 1,2,3,4,5 }; int *ptr = (int *)(&a + 1); printf("%d,%d", *(a + 1), *(ptr - 1)); // 2,5
8. 关于switch,输出结果是什么:
1 #include <iostream> 2 using namespace std; 3 4 int func(int a) 5 { 6 int b; 7 switch (a) 8 { 9 case 1: 10 b = 30; 11 case 2: 12 b = 20; 13 case 3: 14 b = 10; 15 default: 0; 16 } 17 return b; 18 } 19 20 void main() 21 { 22 printf("%d\n", func(1)); //10 23 24 system("pause"); 25 return ; 26 }
9. 关于malloc的用法:
1 #include <iostream> 2 using namespace std; 3 4 void main() 5 { 6 //char *p = (char *)malloc(0); //分配字节为0,仍然会返回地址,只有分配失败才会返回NULL 7 //printf("%d\n", p); //5210848 8 9 char *ptr= (char *)malloc(0); 10 if (ptr == NULL) 11 cout << "得到NULL指针" << endl; 12 else 13 cout << "得到非空指针" << endl; 14 15 system("pause"); 16 return ; 17 }
10. 编写strcpy函数:
已知strcpy函数的原型是char *strcpy(char *strDest,char *strSrc);其中strDest是目的字符串,strSrc是源字符串。
(1)不调用C/C++的字符串库函数,请编写出函数strcpy。
1 #include <iostream> 2 #include<assert.h> 3 using namespace std; 4 5 char *strcpy(char *strDest,char *strSrc) 6 { 7 assert((strDest != NULL) && (strSrc != NULL)); //异常处理 8 //if ((strDest == NULL) && (strSrc == NULL)) 9 //{ 10 // cout << "异常..." << endl; 11 //} 12 13 char *address = strDest; 14 while ((*strDest++ = *strSrc++) != '\0') //牛掰的语句,并没有把语句放在循环体中 15 NULL; 16 return address; 17 } 18 19 void main() 20 { 21 char str1[] = "hello world"; 22 char str2[20]; 23 24 cout << str1 << endl; 25 strcpy(str2, str1); 26 cout << str2 << endl; 27 28 system("pause"); 29 return ; 30 }
(2)strcpy()函数能把strSrc的内容复制到strDest,为什么还要用char * 类型的返回值?
答案:为了实现链式表达式,如:
int length = strlen(strcpy(str2, str1));
11. 请编写一个C函数,该函数给出一个字节中被置1的位的个数。
#include <iostream> using namespace std; unsigned int TestAsOne(char log) { int i; unsigned int num = 0, val; for (i = 0; i < 8; i++) { val = log >> i; //移位 val &= 0x01; //与1相与 if (val) num++; } return num; } void main() { char x = 'a'; int count = TestAsOne(x); cout << count << endl; //3 system("pause"); return ; }
12. 请编写一个C函数,该函数将给定的一个字符串转换成整数。
#include <iostream> using namespace std; int invert(char *str) { int num = 0; while (*str!='\0') { int digital = *str - 48; num = num * 10 + digital; str = str + 1; } return num; } void main() { char str[20] = "hello world"; cout << str << endl; int number = invert(str); cout << number << endl; //1186889628 system("pause"); return ; }
13. 请编写一个C函数,该函数将给定的一个整数转换成字符串。
void IntToChar(int num, char *pval) { char strval[100]; int i, j; int val0 = 0; int val1 = 0; val0 = num; for (i=0;i<100;i++) { val1 = val0 % 10; //取余 val0 = val0 / 10; //取整 strval[i] = val1 + 48; //数字-->字符 if (val0 < 10) { i++; strval[i] = val0 + 48; break; } } for (j=0;j<=i;j++) //倒置 { pval[j] = strval[i - j]; } pval[j] = '\0'; }
14. 实现strcmp()函数:
已知strcmp函数的原型是 int strcmp(const char *str1,const char *str2),不调用C/C++的字符串库函数,请编写函数strcmp。
#include <iostream> #include <assert.h> using namespace std; int strcmp(const char *str1, const char *str2) { assert((str1 != NULL)&&(str2 != NULL)); int ret = 0; while ( !(ret = *(unsigned char *)str1 - *(unsigned char *)str2) && *str2 ) { str1++; str2++; } if (ret > 0) ret = 1; //str1 > str2 else if (ret < 0) ret = -1; //str1 < str2 return ret; } void main() { char str1[] = "aBcDeF"; //a ==>97 char str2[] = "AbCdEf"; //A ==>65 int ret = strcmp(str1, str2); cout << ret << endl; if(ret == 1) cout << "str1 > str2" << endl; else cout << "str1 < str2" << endl; system("pause"); return ; }
15. 请编写一个C函数,该函数将一个字符串逆序。
#include <iostream> #include <string> #include <algorithm> using namespace std; //方法一: void reverse1(char *str) { char t; //交换的中间变量 for (int i = 0, j = strlen(str) - 1; i < strlen(str) / 2; i++, j--) { t = str[i]; str[i] = str[j]; str[j] = t; } } //方法二: void reverse2(char *str) { char t; //交换的中间变量 int head = 0; //字符数组第一个字符 int tail = strlen(str) - 1; //字符数组最后一个字符 for (; head < tail; head++, tail--) { swap(str[head], str[tail]); } } //方法三:直接调用函数 _strrev() ,注意:strrev()不能对string类型使用 //方法四:直接调用算法中的reverse()函数,需要包含头文件 #include <algorithm> //方法五:使用replace()函数 void main() { char a[50]; memset(a, 0, sizeof(a)); cin.getline(a, 50, '\n'); //reverse1(a); //reverse2(a); //_strrev(a); reverse(a,a+strlen(a)); //此处本应该用迭代器,改为了指针,正常用法如下: //string s = "hello"; //reverse(s.begin(),s.end()); cout << a << endl; cin.get(); }
16. 请编写一个 C 函数,该函数在给定的内存区域搜索给定的字符,并返回该字符所在位置索引值。(内存搜索)
int search(char *cpSource,int n,char ch) //起始地址,搜索长度,目标字符 { int i; for (i = 0; i < n && *(cpSource + i) != ch; ++i) { return i; } }
17. 请编写一个 C 函数,该函数在一个字符串中找到可能的最长的子字符串,该字符串是由同一字符组成的。
int ChildString(char *p) { char *q = p; int stringlen = 0, i = 0, j = 1, len = 0, maxlen = 1; while (*q != '\0') //不能用strlen求得字符串长度 { stringlen++; q++; } while (i<stringlen) { if ( *(p+i)==*(p+j) && j<stringlen ) { len++; //统计子串的长度 i++; j++; } else { if (len>maxlen) //统计最大子串的长度 { maxlen = len + 1; len = 0; } else { len = 0; } i++; j++; } } return maxlen; }
18. 华为面试题:怎么判断链表中是否有环?
【参考答案】答:用两个指针来遍历这个单向链表,第一个指针p1,每次走一步;第二个指针p2,每次走两步; 当p2 指针追上 p1的时候,就表明链表当中有环路了。
int testLinkRing(Link *head) { Link *t1 = head, *t2 = head; while (t1->next && t2->next) { t1 = t1->next; if (NULL == (t2 = t2->next->next)) return 0; //无环 if (t1 == t2) return 1; //有环 } return 0; }
19. 有一浮点型数组A,用C语言写一函数实现对浮点数组A进行降序排序,并输出结果,要求要以数组A作为函数的入口。(建议用冒泡排序法)
#include <iostream> using namespace std; void BubbleSort(double arr[], int n) { int i, j; int exchange = 1; //交换标志 for (i = 1; i < n; i++) //最多做n-1趟排序 { exchange = 0; //本趟排序开始前,交换标志应为假 for(j=n-1;j>=i;j--) //对当前无序区R[i..n]自下向上扫描 if (arr[j + 1] > arr[j]) //交换记录 { arr[0] = arr[j + 1]; //R[0]不是哨兵,仅做暂存单元 arr[j + 1] = arr[j]; arr[j] = arr[0]; exchange = 1; //发生了交换,故将交换标志置为真 } if (!exchange) //本趟排序未发生交换,提前终止算法 return; } } void main() { double A[20] = { 0 }; int n; cout << "请输入数组元素的个数( <20 ):" << endl; cin >> n; cout << "请输入数组的每个元素:" << endl; for (int i = 1; i <= n; i++) cin >> A[i]; cout << "数组如下:" << endl; for (int i = 1; i <= n; i++) cout << A[i] << " "; cout << endl; BubbleSort(A, n); cout << "降序排列结果如下:" << endl; for (int i = 1; i <= n; i++) cout << A[i] << " "; cout << endl; system("pause"); return ; }
20. 实现双向链表删除一个节点P,在节点P后插入一个节点,写出这两个函数。
//删除操作 Status ListDelete_Dul(DuLinkList &L, int i, ElemType &e) { if (!(p = GetElemP_DuL(L, i))) return ERROR; e = p->data; p->prior->next = p->next; p->next->prior = p->prior; free(p); return OK; } //插入操作 Status ListInsert_DuL(DuLinkList &L, int i, ElemType &e) { if (!(p = GetElemP_DuL(L, i))) return ERROR; if (!(s = (DuLinkList)malloc(sizeof(DuLNode)))) return ERROR; s->data = e; s->prior = p; p->next->prior = s; p->next = s; s->next = p->next->next; return OK; }
21. 读文件 file1.txt 的内容(例如):
12
34
56
输出到 file2.txt :
56
34
12
22. 写一个函数,求一个字符串的长度,在main函数中输入字符串,并输出其长度。
#include <iostream> using namespace std; int strLength(char *str) { int length=0; while (*str != '\0') { length++; str++; } return length; } void main() { int len; char str[20]; cout << "请输入一个字符串:" << endl; cin >> str; len = strLength(str); cout << "字符串的长度为: " << len << endl; system("pause"); return ; }
23. 把一个链表反向(链表逆置)。
void reverse(test *head) { test *pe = head; test *ps = head->next; while (ps) { pe->next = ps->next; ps->next = head; head = ps; ps = pe->next; } }
24. 有两个双向循环链表 A,B,知道其头指针为:pHeadA,pHeadB,请 写一函数将两链表中 data 值相同的结点删除。
25. 输出和为一个给定整数的所有组合。
26. 输入一行字符,统计其中有多少个单词。
#include <iostream> using namespace std; int wordCount(string str) { int num = 0, word = 0; char c; for (int i = 0; (c = str[i]) != '\0'; i++) if (c == ' ') word = 0; else if (word == 0) { word = 1; num++; } return num; } void main() { char str[81]; int num; cout << "请输入一行字符,以回车结束:" << endl; gets_s(str); num=wordCount(str); cout << "共有 " << num << " 个单词" << endl; system("pause"); return ; }
27. 写一个内存拷贝函数memcpy(),不用任何库函数。
#include <iostream> #include <assert.h> using namespace std; //内存拷贝函数: //功能:由src指向地址为起始地址的连续n个字节的数据复制到以destin指向地址为起始地址的空间内。 //返回值:函数返回一个指向dest的指针 //与strcpy相比:memcpy并不是遇到'\0'就结束,而是一定会拷贝完n个字节 //memcpy用来做内存拷贝,可以拿它拷贝任何数据类型的对象,可以指定拷贝的数据长度 void *memcpy(void *dest, const void *src, size_t size) { assert((dest != NULL) && (src != NULL)); char *pdest = (char *)dest; char *psrc = (char *)src; while ( (size--) > 0 ) { *pdest++ = *psrc++; } return pdest; } void main() { char str1[10] = "abcdefghi"; char str2[20]; memcpy(str2, str1, sizeof(str1)); cout << str1 << endl; //abcdefghi cout << str2 << endl; //abcdefghi //若改为如下: char str3[20] = "abcdefghi"; char str4[10]; memcpy(str4, str3, sizeof(str3)); //此时会造成str4内存地址溢出 cout << str3 << endl; cout << str4 << endl; system("pause"); return ; }
【解析】面试中如问到memcpy的实现,要小心了,这里有陷阱。标准的memcpy()函数中,对于地址重叠的情况,该函数的行为是未定义的。事实上陷阱也在于此,自己动手实现memcpy()时就需要考虑地址重叠的情况。
库函数中的memcpy不能处理src和dest有重叠的情况。如果是自己实现memcpy的话,最好还是把地址有重叠的情况考虑进去,这样才能更好的体现编码的严谨。
//把地址有重叠的情况考虑进去 void *memcpy(void *dest, const void *src, size_t size) { assert((dest != NULL) && (src != NULL) && (size > 0) ); //添加了size > 0的条件 char *pdest, *psrc; if ((dest > src) && ((char *)dest < (char *)src + size)) //有内存重叠,则从后向前拷贝 { pdest = (char *)dest + size - 1; //指针指向拷贝的最后一个位置 psrc = (char *)src + size - 1; while (size--) { *pdest-- = *psrc--; } } else //没有内存重叠,从前往后拷贝即可 { pdest = (char *)dest; //指针指向拷贝的起始位置 psrc = (char *)src; while (size--) { *pdest++ = *psrc++; } } return pdest; }
【扩展】memmove和memcpy函数都是C语言中的库函数,作用是拷贝一定长度的内存的内容,它们的作用是一样的,唯一的区别就是当内存发生局部重叠的时候,memmove保证拷贝的结果是正确的,memcpy不保证拷贝的结果是正确的。它与memcpy的功能相似,都是将src所指的n个字节复制到dest所指的内存地址起始位置中,但该函数可以处理src和dest有重叠的情况。实际上,memcpy可以看作是memmove的子集。
上面优化后的memcpy()函数实际上就是memmove()函数的实现。
28. 有1、2、3、4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少?
#include <iostream> using namespace std; void main() { int i, j, k,count=0; cout << endl; for(i=1;i<5;i++) for(j=1;j<5;j++) for (k = 1; k < 5; k++) { if (i != j&&i != k&&j != k) { cout << i << "," << j << "," << k << endl; count++; } } cout << "能组成" << count << "个互不相同且无重复数字的三位数" << endl; system("pause"); return ; }
29. 取一个整数a从右端开始的4~7位。
void main() { unsigned a, b, c, d; scanf("%o", &a); b = a >> 4; c = ~(~0 << 4); d = b&c; printf("%o\n%o\n", a, b); }
30. (回文字符串)判断一个字符串是否是回文字符串。
31. 给定字符串 A 和 B,输出 A 和 B 中的最大公共子串。
32. 写一个函数,将一个整数逆转,例如12345,转换为54321。
33. 809*??=800*??+9*??+1 其中??代表的两位数,8*??的结果为两位数,9*??的结果为3位数。求??代表的两位数,及809*??后的结果。
#include <iostream> #include <stdio.h> using namespace std; void output(long b, long i) { printf("\n %ld%ld=809*%ld+%ld,b,i,b,ib%i"); } void main() { long int a, b, i; a = 809; for (i = 10; i < 100; i++) { b = i*a + 1; if (b >= 1000 && b <= 10000 && 8 * i < 100 && 9 * i >= 100) output(b, i); } system("pause"); return ; }
34. 某个公司采用公用电话传递数据,数据是四位的整数,在传递过程中是加密的,加密规则如下:
每位数字都加上5,然后用和除以10的余数代替该数字,再将第一位和第四位交换,第二位和第三位交换。
#include <iostream> using namespace std; void main() { int a, i, aa[4], t; cout << "请输入一个4位整数:" << endl; cin >> a; aa[0] = a % 10; //个位 aa[1] = a % 100 / 10; //十位 aa[2] = a % 1000 / 100; //百位 aa[3] = a / 1000; //千位 for (i = 0; i <= 3; i++) { aa[i] += 5; aa[i] %= 10; } for (i = 0; i <= 3 / 2; i++) { t = aa[i]; aa[i] = aa[3 - i]; aa[3 - i] = t; } for (i = 3; i >= 0; i--) cout << aa[i]; system("pause"); return ; }
35. 计算字符串中子串出现的次数。
#include <iostream> using namespace std; void main() { char str1[20], str2[20], *p1, *p2; //str1为父串 str2为子串 int sum = 0; cout << "Please input two strings:" << endl; cin >> str1; cin >> str2; p1 = str1; p2 = str2; while (*p1 != '\0') { if (*p1 == *p2) { while (*p1 == *p2 && *p2 != '\0') { p1++; p2++; } } else p1++; if (*p2 == '\0') sum++; p2 = str2; } cout << "子串出现次数为:" << sum << endl; system("pause"); return ; }
36. 有两个磁盘文件A和B,各存放一行字母,要求把这两个文件中的信息合并(按字母顺序排列),输出到一个新文件C中。
#include <iostream> using namespace std; void main() { FILE *fp; int i, j, n, ni; char c[160], t, ch; if ((fp = fopen("A", "r")) == NULL) { cout << "file A cannot be opened" << endl; exit(0); } cout << "A contents are:" << endl; for (i = 0; (ch = fgetc(fp)) != EOF; i++) { c[i] = ch; putchar(c[i]); } fclose(fp); ni = i; if ((fp = fopen("B", "r")) == NULL) { cout << "file B cannot be opened" << endl; exit(0); } cout << "B contents are:" << endl; for (i = 0; (ch = fgetc(fp)) != EOF; i++) { c[i] = ch; putchar(c[i]); } fclose(fp); n = i; for(i=0;i<n;i++) for(j=i+1;j<n;j++) if (c[i] > c[j]) { t = c[i]; c[i] = c[j]; c[j] = t; } cout << "C file is:" << endl; fp = open("C", "w"); for (i = 0; i < n; i++) { putc(c[i], fp); putchar(c[i]); } fclose(fp); system("pause"); return ; }
37. 写一个函数strlen(),求一个字符串的长度。
38.写出二分查找的代码。
#include <iostream> using namespace std; int binary_search(int *arr, int key, int n) { int low = 0; int high = n - 1; int mid; while (low <= high) { mid = (low + high) / 2; if (key < arr[mid]) high = mid - 1; else if (key > arr[mid]) low = mid + 1; else return mid; } return -1; } void main() { int A[] = { 1,3,5,7,9,11,13,15,17 }; int len = sizeof(A) / sizeof(A[0]); int key; cout << "数组如下:" << endl; for(int i=0;i<len;i++) cout << A[i] << " "; cout << endl; cout << "请输入待查找的关键字key:" << endl; cin >> key; int ret=binary_search(A, key, len); if (-1 == ret) cout << "没有找到,数组中无关健值" << key << endl; else cout << "已找到关键值" << key << ",它是A[" << ret << "]" << endl; system("pause"); return ; }