1、公务员面试
描述:
公务员面试现场打分。有7位考官,从键盘输入若干组成绩,每组7个分数(百分制),去掉一个最高分和一个最低分,输出每组的平均成绩。
(注:本题有多组输入)
输入描述:
每一行,输入7个整数(0~100),代表7个成绩,用空格分隔。
输出描述:
每一行,输出去掉最高分和最低分的平均成绩,小数点后保留2位,每行输出后换行。
示例1:
输入:99 45 78 67 72 88 60
输出:73.00
我的代码:
#include<stdio.h>
int main()
{
int arr[8];
int i = 0;
int j = 0;
int n = 0;
int exp = 0;
int sum = 0;
double average = 0;
while (scanf("%d %d %d %d %d %d %d", &arr[0], &arr[1], &arr[2], &arr[3], &arr[4], &arr[5], &arr[6]) != EOF)
{
//从小到大排列
for (i = 0; i < 6; i++)
{
for (j = 0; j < 6 - i; j++)
{
if (arr[j] > arr[j + 1])
{
exp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = exp;
}
}
}
//计算平均值
sum = 0;
for (i = 1; i <= 5; i++)
{
sum = sum + arr[i];
}
average = sum / 5.0;
//打印
printf("%.2lf", average);
printf("\n");
}
return 0;
}
代码:
2、计算一元二次方程
描述:
从键盘输入a, b, c的值,编程计算并输出一元二次方程ax2 + bx + c = 0的根,当a = 0时,输出“Not quadratic equation”,当a ≠ 0时,根据△ = b2 - 4*a*c的三种情况计算并输出方程的根。
输入描述:
多组输入,一行,包含三个浮点数a, b, c,以一个空格分隔,表示一元二次方程ax2 + bx + c = 0的系数。
输出描述:
针对每组输入,输出一行,输出一元二次方程ax2 + bx +c = 0的根的情况。
如果a = 0,输出“Not quadratic equation”;
如果a ≠ 0,分三种情况:
△ = 0,则两个实根相等,输出形式为:x1=x2=...。
△ > 0,则两个实根不等,输出形式为:x1=...;x2=...,其中x1 <= x2。
△ < 0,则有两个虚根,则输出:x1=实部-虚部i;x2=实部+虚部i,即x1的虚部系数小于等于x2的虚部系数,实部为0时不可省略。实部= -b / (2*a),虚部= sqrt(-△ ) / (2*a)
所有实数部分要求精确到小数点后2位,数字、符号之间没有空格。
示例1:
输入:0.0 3.0 3.0
输出:Not quadratic equation
示例2:
输入:1 2 1
输出:x1=x2=-1.00
示例3:
输入:2.0 7.0 1.0
输出:x1=-3.35;x2=-0.15
示例4:
输入:2 2 5
输出:x1=-0.50-1.50i;x2=-0.50+1.50i
示例5:
输入:4 0 0
输出:x1=x2=0.00
我的代码:
#include<stdio.h>
#include<math.h>
int main()
{
double a = 0;
double b = 0;
double c = 0;
while (scanf("%lf %lf %lf", &a, &b, &c) != EOF)
{
if (a == 0)
{
printf("Not quadratic equation\n");
}
else
{
if (b * b - 4 * a * c == 0)
{
printf("x1=x2=%.2lf\n", (-b + 0) / (2 * a));
}
else if (b * b - 4 * a * c > 0)
{
printf("x1=%.2lf;x2=%.2lf\n", ((-b - sqrt(b * b - 4 * a * c)) / (2 * a)), ((-b + sqrt(b * b - 4 * a * c)) / (2 * a)));
}
else
{
printf("x1=%.2lf-%.2lfi;x2=%.2lf+%.2lfi\n", (-b + 0) / (2 * a), sqrt(-(b * b - 4 * a * c)) / (2 * a), (-b + 0) / (2 * a), sqrt(-(b * b - 4 * a * c)) / (2 * a));
}
}
}
return 0;
}
代码:
#include <stdio.h>
#include <math.h>
#define ESP 0.00000001
int main()
{
float a = 0.0f;
float b = 0.0f;
float c = 0.0f;
while (scanf("%f %f %f", &a, &b, &c) != EOF)
{
//指定一个精度
if (fabs(a - 0.0) < ESP)
{
printf("Not quadratic equation\n");
}
else
{
float disc = b * b - 4 * a * c;
if (fabs(disc - 0.0) < ESP)//表示==0
{
printf("x1=x2=%.2f\n", (-b + sqrt(disc)) / (2 * a));
}
else if (disc >= ESP)//>0
{
printf("x1=%.2f;x2=%.2f\n", (-b - sqrt(disc)) / (2 * a), (-b + sqrt(disc)) / (2 * a));
}
else //<0
{
float real = (-b) / (2 * a);
float image = sqrt(-disc) / (2 * a);
printf("x1=%.2f-%.2fi;x2=%.2f+%.2fi\n", real, image, real, image);
}
}
}
return 0;
}
注:
1.浮点数是有-0的概念的,在计算时,应该给-b+0(如下图所示),如果不加的话, 当b=0时,前面有负号输出的结果就是-0,与标准输出不符(如下图所示)
2.浮点数直接进行比较是不精确的,因为0.0...01并不是零,而要是与0相比的话,可能是相等的,因为计算机比的时候总会取小数点后有限位。
3.在浮点数比较时,应该给一个精度(如上面的ESP),规定在小于这个精度的时候就可以认为是等于0的
3、获得月份天数
描述:
KiKi想获得某年某月有多少天,请帮他编程实现。输入年份和月份,计算这一年这个月有多少天。
输入描述:
多组输入,一行有两个整数,分别表示年份和月份,用空格分隔。
输出描述:
针对每组输入,输出为一行,一个整数,表示这一年这个月有多少天。
示例1:
输入:2008 2
输出:29
我的代码:
#include<stdio.h>
int judge(int y)
{
if (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
{
return 1;
}
else
{
return 0;
}
}
int main()
{
int y = 0;
int m = 0;
while (scanf("%d %d", &y, &m) != EOF)
{
//如果年份是闰年
if (judge(y)==1)
{
if (m == 1 || m == 3 || m == 5 || m == 7 || m == 8 || m == 10 || m == 12)
{
printf("%d", 31);
}
else if (m == 2)
{
printf("%d", 29);
}
else
{
printf("%d", 30);
}
}
//如果年份是平年
if (judge(y) == 0)
{
if (m == 1 || m == 3 || m == 5 || m == 7 || m == 8 || m == 10 || m == 12)
{
printf("%d", 31);
}
else if (m == 2)
{
printf("%d", 28);
}
else
{
printf("%d", 30);
}
}
printf("\n");
}
return 0;
}
代码:
4、字符串左旋
描述:
实现一个函数,可以左旋字符串中的k个字符。
例如:
ABCD左旋一个字符得到BCDA
ABCD左旋两个字符得到CDAB
代码1:
#include <stdio.h>
#include <string.h>
void left_move(char* str, int k)
{
int i = 0;
for (i = 0; i < k; i++)
{
//每次旋转一个字符
char tmp = *str;
int len = strlen(str);
int j = 0;
for (j = 0; j < len - 1; j++)
{
*(str + j) = *(str + j + 1);
}
*(str + len - 1) = tmp;
}
}
int main()
{
char arr[] = "abcdef";
int k = 0;
scanf("%d", &k);
left_move(arr, k);
printf("%s\n", arr);
return 0;
}
代码2:
#include <stdio.h>
#include <string.h>
void reverse(char* left, char* right)
{
while (left<right)
{
char tmp = *left;
*left = *right;
*right = tmp;
left++;
right--;
}
}
void left_move(char* str, int k)
{
int len = strlen(str);
k %= len;
reverse(str, str+k-1);//前
reverse(str+k, str+len-1);//后
reverse(str, str+len-1);//整体
}
int main()
{
char arr[] = "abcdef";
int k = 0;
scanf("%d", &k);
left_move(arr, k);
printf("%s\n", arr);
return 0;
}
注:
1.代码1的思路:将第一个字符存在tmp中,然后将后面每一个字符往前移动一个,最后将tmp中的字符存在最后一个字符的位置。如果要移动k个字符,前面的操作执行k次即可
2.代码2的思路:如果左旋k个字符,那么先将字符串前k个字符进行逆序,然后将字符串除前k个字符外其余的字符进行逆序,最后将整个字符串再进行一次逆序即可。此方法k不能大于字符串的长度,因此需要k %= len操作
5.杨氏矩阵
描述:
有一个数字矩阵,矩阵的每行从左到右是递增的,矩阵从上到下是递增的,请编写程序在这样的矩阵中查找某个数字是否存在。
要求:时间复杂度小于O(N)(也就是说不能遍历整个数组)
代码1:
#include <stdio.h>
#include <string.h>
void find_int_arr(int arr[3][3], int r, int c, int k)
{
int x = 0;
int y = c-1;
while (y >= 0 && x <= r-1)
{
if (arr[x][y] < k)
{
x++;
}
else if (arr[x][y] > k)
{
y--;
}
else
{
printf("找到了,下标是:%d %d\n", x, y);
return;
}
}
printf("找不到\n");
}
int main()
{
int arr[3][3] = { 1,2,3,4,5,6,7,8,9 };
int k = 0;
scanf("%d", &k);
find_int_arr(arr, 3, 3, k);
return 0;
}
运行结果1:
代码2:
#include <stdio.h>
#include <string.h>
void find_int_arr(int arr[3][3], int *px, int *py, int k)
{
int x = 0;
int y = *py-1;
while (y >= 0 && x <= *px-1)
{
if (arr[x][y] < k)
{
x++;
}
else if (arr[x][y] > k)
{
y--;
}
else
{
*px = x;
*py = y;
return;
}
}
*px = -1;
*py = -1;
}
int main()
{
int arr[3][3] = { 1,2,3,4,5,6,7,8,9 };
int k = 0;
int x = 3;
int y = 3;
scanf("%d", &k);
//参数是返回型参数
find_int_arr(arr, &x, &y, k);
if (x == -1 && y == -1)
{
printf("找不到了\n");
}
else
{
printf("找到了,下标是:%d %d\n", x, y);
}
return 0;
}
运行结果2:
注:
1.矩阵右上角的数是这一行里面的最大值这一列里面最小的,因此如果要找的数大于右上角的数,那就排除矩阵第一行(行的值+1),要是小于右上角的数,那就排除矩阵最后一列(列的值-1),依次用排除后的矩阵右上角元素进行判断,直到行数值小于二维数组行的值或列数值大于0为止
2.代码1中如果我们还需要在主函数里使用找到的坐标,那么我们需要把左边返回给主函数,但是不能return两个值。我们可以利用传址调用来解决,此时参数为返回型参数,如代码2所示
6.选择题
题目名称:
定义一个函数指针,指向的函数有两个int形参并且返回一个函数指针,返回的指针指向一个有一个int形参且返回int的函数?下面哪个是正确的?
题目内容:
A.int (*(*F)(int, int))(int)
B.int (*F)(int, int)
C.int (*(*F)(int, int))
D.*(*F)(int, int)(int)
答案:A
注:
1.A选项:int (* (*F)(int, int) )(int)中代码(*F)(int, int)的F是一个函数指针,指向的函数参数为(int,int),将其去掉剩余的便是其返回类型,去掉(*F)(int, int)A选项剩余int (* )(int),该返回类型返回一个形参为int,返回为int的函数指针。A选项符合题意
B选项:int (*F)(int, int)中F是一个函数指针,指向函数的参数为(int,int),返回类型是int
C选项:int (* (*F)(int, int) )中代码(*F)(int, int)的F是一个函数指针,指向的函数参数为(int,int),将其去掉剩余的便是其返回类型,去掉(*F)(int, int)C选项剩余int (*),这里int(*)与int *是一样的,函数指针的返回类型是整型指针int*
D选项:D选项代码有问题
7.选择题
题目名称:
声明一个指向含有10个元素的数组的指针,其中每个元素是一个函数指针,该函数的返回值是int,参数是int*,正确的是
题目内容:
A.(int *p[10])(int*)
B.int [10]*p(int *)
C.int (*(*p)[10])(int *)
D.int ((int *)[10])*p
答案:C
注:
1.A选项:(int *p[10])(int*)是一个返回值为int,参数为一个整型int的函数指针数组
B选项:p先和后面的圆括号相结合,p是一个函数名,代码错误
C选项:p先和*结合,说明p是一个指针;(*p)[10]说明指针p指向的是一个数组,数组10个元素;C选项代码将(*p)[10]删除得到int (* )(int *),说明指针p指向的是一个数组,数组10个元素,每个元素都是一个函数指针,所以该数组是一个存放函数指针的数组,函数的返回值是int,参数是int*符合题意,选项C正确
D选项:选项有问题
8.选择题
题目名称:
设有以下函数void fun(int n,char *s){……},则下面对函数指针的定义和赋值均是正确的是:
题目内容:
A.void (*pf)(int,char); pf=&fun;
B.void (*pf)(int n,char *s); pf=fun;
C.void *pf(); *pf=fun;
D.void *pf(); pf=fun;
答案:B
注:
1.A选项和B选项:A选项pf函数指针参数为(int,char),B选项pf函数指针参数为(int,char*)而fun函数参数为(int,char*),A选项错误,B选项正确。定义函数指针变量时形参有无变量名都可
2.C选项和D选项中pf是一个函数名,错误
9.判断一个字符串是否为另一个字符串旋转结果
题目内容:
写一个函数,判断一个字符串是否为另外一个字符串旋转之后的字符串。
例如:
给定s1 =AABCD和s2 = BCDAA,返回1
给定s1=abcd和s2=ACBD,返回0
代码1:
#include <stdio.h>
#include <string.h>
void left_move(char* str, int k)
{
int i = 0;
for (i = 0; i < k; i++)
{
//每次旋转一个字符
char tmp = *str;
int len = strlen(str);
int j = 0;
for (j = 0; j < len - 1; j++)
{
*(str + j) = *(str + j + 1);
}
*(str + len - 1) = tmp;
}
}
int is_left_move(char*arr1, char* arr2)
{
int len = strlen(arr1);
int i = 0;
for (i = 0; i < len; i++)
{
left_move(arr1, 1);
if (strcmp(arr1, arr2) == 0)
return 1;
}
return 0;
}
int main()
{
char arr1[] = "ABCD";
char arr2[] = "BCDAA";
//判断arr2是不是arr1旋转得到的
int ret = is_left_move(arr1, arr2);
printf("%d\n", ret);
return 0;
}
代码2:
#include <stdio.h>
#include <string.h>
int is_left_move(char* arr1, char* arr2)
{
int len1 = strlen(arr1);
int len2 = strlen(arr2);
if (len1 != len2)
return 0;
strncat(arr1, arr1, len1);
if (strstr(arr1, arr2))
return 1;
else
return 0;
}
int main()
{
char arr1[20] = "AABCD";
//AABCDAABCD
char arr2[] = "BCDAA";
//判断arr2是不是arr1旋转得到的
int ret = is_left_move(arr1, arr2);
printf("%d\n", ret);
return 0;
}
注:
1.当给一个字符串后面再追加一个相同的字符串,那么追加后的字符串里面就有追加前字符串旋转的所有可能结果,如代码2所示。使用这种方法,如果两个字符串的长度不相等就无法判断(因为长度不相等一个字符串肯定不是另一个字符串旋转的结果,但是此方法如果判断AABCD和BCD这样的字符串,得到的是相等的),所以我们要先对两个字符串长度进行判断,如果两个字符串不相等直接返回0
2.自己给自己追加的时候,用strcat函数会存在潜在的BUG,因为strcat函数自己给自己追加会把源字符串第一个字符覆盖到其'\0'的位置,因为最后的'\0'已经被覆盖,所以是无法追加'\0'的,因此这个追加是不会停下来的,如下图所示
10.选择题
题目名称:
有如下宏定义和结构定义
#define MAX_SIZE A+B struct _Record_Struct { unsigned char Env_Alarm_ID : 4; unsigned char Para1 : 2; unsigned char state; unsigned char avail : 1; }*Env_Alarm_Record; struct _Record_Struct *pointer = (struct _Record_Struct*)malloc (sizeof(struct _Record_Struct) * MAX_SIZE);
当A=2, B=3时,pointer分配( )个字节的空间。
题目内容:
A.20
B.15
C.11
D.9
答案:D
注:
1.分析可得_Record_Struct位段占用3个字节,sizeof(struct _Record_Struct) * MAX_SIZE将MAX_SIZE替换成A+B而A=2, B=3时,因此sizeof(struct _Record_Struct) * MAX_SIZE可以被替换成sizeof(struct _Record_Struct) * 2+3为3*2+3=9,选D选项
11.选择题
题目名称:
下面代码的结果是( )
int main() { unsigned char puc[4]; struct tagPIM { unsigned char ucPim1; unsigned char ucData0 : 1; unsigned char ucData1 : 2; unsigned char ucData2 : 3; }*pstPimData; pstPimData = (struct tagPIM*)puc; memset(puc,0,4); pstPimData->ucPim1 = 2; pstPimData->ucData0 = 3; pstPimData->ucData1 = 4; pstPimData->ucData2 = 5; printf("%02x %02x %02x %02x\n",puc[0], puc[1], puc[2], puc[3]); return 0; }
题目内容:
A.02 03 04 05
B.02 29 00 00
C.02 25 00 00
D.02 29 04 00
答案:B
注:
1.puc是数组名,是数组首元素地址,将其赋值给pstPimData指针变量,该指针变量是struct tagPIM*位段类型,将该数组所占字节全都置为0后,用pstPimData指针变量对数据进行修改,因为这个位段大小为2个字节,所以pstPimData位段类型指针变量只能访问puc数组前两个字节的内存空间
2.pstPimData->ucPim1 = 2:ucPim1成员1个字节空间,2的二进制为10占两个比特位,可以放下,因此第一个字节空间为00000010
pstPimData->ucData0 = 3,ucData0成员有1个比特位空间,3的二进制为11占两个比特位,放不下,只能放下最右边的1;pstPimData->ucData1 = 4,ucData1成员有2个比特位空间,4的二进制为100占三个比特位,放不下,只能放下右边的两位00;pstPimData->ucData2 = 5,ucData2成员有3个比特位空间,5的二进制为101占三个比特位,能放下,因此第二个字节数据为00101001
3.%x为十六进制打印,%02x为打印两位十六进制数字,打印出来数字为:02 29 00 00
12.选择题
题目名称:
在X86下,有下列程序
#include<stdio.h> int main() { union { short k; char i[2]; }*s, a; s = &a; s->i[0] = 0x39; s->i[1] = 0x38; printf(“%x\n”,a.k); return 0; }
输出结果是( )
题目内容:
A.3839
B.3938
C.380039
D.不确定
答案:A
注:
1.因为是联合体,所以short k和char i[2]共用两个字节空间,将第一个字节放入十六进制39第二个字节放入十六进制38,如下图所示
用短整型类型成员k进行访问,打印两个字节数据,因为是小段存储,所以打印出来为0x3839
13.有序序列的合并
描述:
输入两个升序排列的序列,将两个序列合并为一个有序序列并输出。
数据范围: 1 \le n, m \le 1000 \1≤n,m≤1000 , 序列中的值满足 0 \le val \le 30000 \0≤val≤30000
输入描述:
输入包含三行,
第一行包含两个正整数n, m,用空格分隔。n表示第二行第一个升序序列中数字的个数,m表示第三行第二个升序序列中数字的个数。
第二行包含n个整数,用空格分隔。
第三行包含m个整数,用空格分隔。输出描述:
输出为一行,输出长度为n+m的升序序列,即长度为n的升序序列和长度为m的升序序列中的元素重新进行升序序列排列合并。
示例1:
代码1:
#include <stdio.h>
int main()
{
int n = 0;
int m = 0;
scanf("%d %d", &n, &m);//
int arr1[1000];
int arr2[1000];
//输入第一个数组
int i = 0;
int k = 0;
for (i = 0; i < n; i++)
{
scanf("%d", &arr1[i]);
}
//输入第二个数组
for (i = 0; i < m; i++)
{
scanf("%d", &arr2[i]);
}
//合并输出
int j = 0;
i = 0;
while (i < n && j < m)
{
if (arr1[i] < arr2[j])
{
printf("%d ", arr1[i]);
i++;
}
else
{
printf("%d ", arr2[j]);
j++;
}
}
if (j == m)
{
for (; i < n; i++)
{
printf("%d ", arr1[i]);
}
}
else
{
for (; j < m; j++)
{
printf("%d ", arr2[j]);
}
}
return 0;
}
代码2:
#include <stdio.h>
int main()
{
int n = 0;
int m = 0;
scanf("%d %d", &n, &m);
int arr1[1000];
int arr2[1000];
int arr3[2000];
//输入第一个数组
int i = 0;
int k = 0;
for (i = 0; i < n; i++)
{
scanf("%d", &arr1[i]);
}
//输入第二个数组
for (i = 0; i < m; i++)
{
scanf("%d", &arr2[i]);
}
//合并输出
int j = 0;
i = 0;
while (i < n && j < m)
{
if (arr1[i] < arr2[j])
{
arr3[k++] = arr1[i];
i++;
}
else
{
arr3[k++] = arr2[j];
j++;
}
}
if (j == m)
{
for (; i < n; i++)
{
arr3[k++] = arr1[i];
}
}
else
{
for (; j < m; j++)
{
arr3[k++] = arr2[j];
}
}
//打印
for (i = 0; i < k; i++)
{
printf("%d ",arr3[i]);
}
return 0;
}
注:
1.本题将两个字符串的内容按数值大小从小到大打印即可,用i和j分别指向第一个和第二个序列0下标的位置,然后比较序列arr1[i]和arr2[j]的大小,如果arr1[i]较小则打印arr1[i]的内容并且i++,如果arr2[j]较小则打印arr2[j]的内容并且j++,依次类推,直到打印完两个序列中一个序列的所有内容,最后将未打印的序列剩下内容打印即可
2.代码1是直接将序列打印出来,没有保存,如果要将合并后的序列存起来,如代码2所示,思路和代码1相同
14.变种水仙花
描述:
变种水仙花数 - Lily Number:把任意的数字,从中间拆分成两个数字,比如1461 可以拆分成(1和461),(14和61),(146和1),如果所有拆分后的乘积之和等于自身,则是一个Lily Number。
例如:
655 = 6 * 55 + 65 * 5
1461 = 1*461 + 14*61 + 146*1
求出 5位数中的所有 Lily Number。
输入描述:
无
输出描述:
一行,5位数中的所有 Lily Number,每两个数之间间隔一个空格。
代码:
#include <stdio.h>
#include <math.h>
int main()
{
int i = 0;
for (i = 10000; i <= 99999; i++)
{
int j = 0;
int sum = 0;
for (j = 1; j <= 4; j++)
{
int m = i % (int)pow(10, j);
int n = i / pow(10, j);
sum += m * n;
}
if (i == sum)
{
printf("%d ", i);
}
}
return 0;
}
15.找单身狗
题目名称:
找单身狗
题目内容:
一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。
编写一个函数找出这两个只出现一次的数字。
代码1:
#include <stdio.h>
#include <math.h>
int main()
{
int arr[] = { 1,2,3,4,5,1,2,3,4,6 };
//1. 先异或在一起
int ret = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
for (i = 0; i < sz; i++)
{
ret ^= arr[i];
}
//2. 计算ret的二进制中第几个位是1
int pos = 0;
for (i = 0; i < 32; i++)
{
if (((ret >> i) & 1) == 1)
{
pos = i;
break;
}
}
//3.按照第pos位为0或1来分组
int n = 0;
int m = 0;
for (i = 0; i < sz; i++)
{
if (((arr[i] >> pos) & 1) == 1)
{
n ^= arr[i];
}
}
for (i = 0; i < sz; i++)
{
if (((arr[i] >> pos) & 1) == 0)
{
m ^= arr[i];
}
}
printf("%d %d\n", n, m);
return 0;
}
代码2:
#include <stdio.h>
#include <math.h>
int main()
{
int arr[] = { 1,2,3,4,5,1,2,3,4,6 };
//1. 先异或在一起
int ret = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
for (i = 0; i < sz; i++)
{
ret ^= arr[i];
}
//2. 计算ret的二进制中第几个位是1
int pos = 0;
for (i = 0; i < 32; i++)
{
if (((ret >> i) & 1) == 1)
{
pos = i;
break;
}
}
//3.按照第pos位为0或1来分组
int n = 0;
int m = 0;
for (i = 0; i < sz; i++)
{
if (((arr[i] >> pos) & 1) == 1)
{
n ^= arr[i];
}
}
m = ret ^ n;
printf("%d %d\n", n, m);
return 0;
}
注:
1.当一个数组只有一个数字出现一次的时候将所有数字异或,便可得到该数字(相同的数字异或为0,0和一个数字异或结果为该数字)
2.我们可以对该数组进行分组,分组的要求:
(1)只出现1次的2个数字,分别到2个组中,一个组中有一个
(2)每个组都满足,只有1个数字出现一次,其他数字都是成对出现的
然后将两个组所有的数字分别异或在一起,得到的两个数字即为所求数字
3.相同的数字其二进制位一定相同。将所有数字异或,得到的便是两个单身狗数字异或的结果,因为异或相同为0不同为1,因此所有二进制位异或的结果中二进制位1的位是两个单身狗数字二进制位不同的位。所以所有数字异或,我们找出一个二进制位为1的位,然后将所有数字该位为0的分为一组,所有数字该位为1的分为一组,就可以满足上述的分组条件。
如1 2 3 4 5 1 2 3 4 6进行分组,5的二进制位为101,6的二进制位为110,所有数字进行异或也就是5和6异或得011,我们就按最右边二进制位进行数组分类,也就是所有数字最低位为1的放到一个数组,最低位为0的放到一个数组,如下面所示:
最低位为1的数组:1 1 3 3 5
最低位为0的数组:2 2 4 4 6
16.模拟实现atoi函数
题目内容:
模拟实现atoi
-------------------------------------------------------------------------------------------------------------------------
atoi函数介绍:
参数:
const char *string:字符串名字(首地址)
返回:
int:转化后的整数值
功能:
把一个字符串转化成对应的整型
代码:
#include<stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <ctype.h>
enum State
{
INVALID,//非法
VALID //合法
};
enum State status = INVALID;
int my_atoi(const char* str)
{
assert(str);
//空字符串
if (*str == '\0')
return 0;
//空白字符(跳过)
while (isspace(*str))
{
str++;
}
int flag = 1;
//+-
if (*str == '+')
{
str++;
flag = 1;
}
else if (*str == '-')
{
str++;
flag = -1;
}
long long n = 0;
while (isdigit(*str))
{
n = n * 10 + flag*(*str - '0');
//越界的值
if (n > INT_MAX || n < INT_MIN)
{
return 0;
}
str++;
}
if (*str == '\0')
{
//合法返回
status = VALID;
return (int)n;
}
return (int)n;
}
int main()
{
int ret = my_atoi(" -111");//"0"
if (status == VALID)
printf("%d\n", ret);
else
printf("非法返回\n");
return 0;
}
注:
1.进行模拟实现atoi函数时要考虑的全面一些:
(1)传的是空指针:assert(str)
(2)传的是空字符串:返回0并且status为INVALID
(3)传的是空白字符(不考虑12 34这种情况,因为这种情况库函数里的atoi也只返回12,需要考 虑的是 123这种情况):跳过空白字符
(4)传的字符串里面有正负号,比如"-123":正负号判断,用flag记录
(5)传的字符串里面有非数字字符:返回非数字字符前的数字字符对应的数值并且status为 INVALID
(6)传的字符串转换成数字后一个int整型类型存不下:如果超出整型最大值和最小值就返回0, 并且status为INVALID
17.选择题
下列关于文件名及路径的说法中错误的是:
A.文件名中有一些禁止使用的字符
B.文件名中一定包含后缀名
C.文件的后缀名决定了一个文件的默认打开方式
D.文件路径指的是从盘符到该文件所经历的路径中各符号名的集合
答案:B
注:
1.文件名中有一些禁止使用的字符,创建一个文本使用不能包含的字符命名,系统会提示如下
2.文件名可以不包含后缀名
3.文件的后缀名决定了一个文件的默认打开方式,比如说.txt默认打开方式为记事本,这个默认打开方式可以人为修改,当遇到没有后缀名的文件时,系统会让你选择打开方式
4.文件路径指的是从盘符到该文件所经历的路径中各符号名的集合
例如:c:\code\test.txt
c:\code\ | test | .txt |
文件路径 | 文件名主干 | 文件后缀 |
18.选择题
C语言中关于文件读写函数说法不正确的是:
A.fgetc是适用于所有输入流字符输入函数
B.getchar也是适用于所有流的字符输入函数
C.fputs是适用于所有输出流的文本行输出函数
D.fread是适用于文件输入流的二进制输入函数
答案:B
注:getchar、sacnf函数只能适用于标准输入流,printf函数只能适用于标准输出流
19.判断程序的功能
下面程序的功能是什么?
int main() { long num=0; FILE *fp = NULL; if((fp=fopen("fname.dat","r"))==NULL) { printf("Can’t open the file! "); exit(0): } while(fgetc(fp) != EOF) { num++; } printf("num=%d\n",num); fclose(fp); return 0; }
A.拷贝文件
B.统计文件的字符数
C.统计文件的单词数
D.统计文件的行数
答案:B
注:
1.exit(0): exit是退出的意思,exit函数只要一执行,程序就结束;与return 0是有区别的,比如在函数中如果是return 0那么程序会退出该函数从主函数中函数调用下一行继续执行,在函数中如果是exit(0)那么程序直接结束不会再返回主函数
20.选择题
以下关于头文件,说法正确的是
A.#include<filename.h>,编译器寻找头文件时,会从当前编译的源文件所在的目录去找
B.#include“filename.h”,编译器寻找头文件时,会从通过编译选项指定的库目录去找
C.多个源文件同时用到的全局整数变量,它的声明和定义都放在头文件中,是好的编程习惯
D.在大型项目开发中,把所有自定义的数据类型、函数声明都放在一个头文件中,各个源文件都只需要包含这个头文件即可,省去了要写很多#include语句的麻烦,是好的编程习惯
答案:D
注:
1.选项c是错误的,多个源文件同时用到的全局整数变量,它的声明和定义都放在头文件中,因为每个源文件都要包含头文件,那么进行预编译,每一个源文件里面都会有定义这个全局变量的代码,在链接的时候会引起冲突,如下图所示
21.交换奇偶位
内容:
写一个宏,可以将一个整数的二进制位的奇数位和偶数位交换。
代码:
#include<stdio.h>
#define SWAP(x) (((x&0xaaaaaaaa)>>1) + ((x&0x55555555)<<1))
int main()
{
int a = 11;
printf("%d\n", SWAP(a));
return 0;
}
注:
1.第一步:把这个整数的二进制位所有偶数位保留,所有奇数位置0
(与上10101010101010101010101010101010,这个数十六进制就是0xaaaaaaaa)
第二步:把这个整数的二进制位所有奇数位保留,所有偶数位置0
(与上01010101010101010101010101010101,这个数十六进制就是0x55555555)
第三步:将偶数位保留,奇数位置0的结果向右移动一位,这样偶数位的二进制数跑到了奇数位
将奇数位保留,偶数位置0的结果向左移动一位,这样奇数位的二进制数跑到了偶数位
第四步:将第三步两个移位后结果值加在一起
22.offsetof函数宏实现
写一个宏,计算结构体中某变量相对于首地址的偏移,并给出说明
考察:
offsetof
宏的实现
参数:
structName:结构体类型名
memberName:结构体成员们
返回:
size_t:结构体成员的偏移量
注:
1.函数是不可能传类型的,所以offsetof函数只能用宏来实现
2.使用offsetof函数必须引用stddef.h头文件
代码:
#include<stdio.h>
#include <stddef.h>
struct S
{
char c;
int a;
double d;
};
#define OFFSETOF(s_name, m_name) (int)&(((s_name*)0)->m_name)
int main()
{
printf("%d\n", OFFSETOF(struct S, c));
printf("%d\n", OFFSETOF(struct S, a));
printf("%d\n", OFFSETOF(struct S, d));
return 0;
}
注:
1.结构体在内存创建空间,假如结构体的地址为0x1000,那么第一个成员变量c的地址也为0x1000,其偏移量为0;第二个成员变量a的地址为0x1004,用a的地址减去第一个成员变量地址(结构体的地址)就是第二个成员变量的偏移量,如果我们把结构体地址变为0,那么第二个成员的地址就是其偏移量,以此类推
2.(s_name*)0表示将数值0强制转换成结构体指针类型,那么0此时就代表0地址,结构体的地址就置为了0;&(((s_name*)0)->m_name)就找到了结构体成员的地址,偏移量应该是一个整型,因此再强制转换成整型即可
3.0地址处是不能访问的,我们这里面没有访问,我们只是假设0地址处放了个结构体变量,只是改变了其类型,并没有真的去放,使用的时候我们也只是去取地址,没有访问那块空间的数据,因此也不存在越界访问
23.代码运行结果
下面代码的运行结果为:
运行结果:
注:
1.循环运行7-3-3-3=-2
-2的原码:10000000 00000000 00000000 00000010
-2的反码:11111111 11111111 11111111 11111101
-2的补码:11111111 11111111 11111111 11111110
i=-2,变量i里面的数据为11111110,因为i为无符号字符型,所以为254,254=84*3+2,因此此时变量i的值依次为7,4,1,254,251 ...... 5,2
2. 2-3=-1
-1的补码:11111111 11111111 11111111 11111111
i=-1,变量i里面的数据为11111111,因为i为无符号字符型,所以为255,255=85*3,因此此时变量i的值依次为7,4,1,254,251 ...... 5,2,255,252 . ..... 6,3,0
3.从254到2总共(254-2)3=85个数字,255到0总共86个数字,因为0的时候判断为假不会进入循环体进行++j,因此要减一,总共85+86+3-1=173
24.代码运行结果
以下程序运行时,若输入1abcedf2df<回车>输出结果是?
运行结果:
25.选择题
以下哪个选项一定可以将flag的第二个bit置0
答案:A
注:
1.2的二进制序列:00000000 00000000 00000000 00000010
~2的二进制序列:11111111 11111111 11111111 11111101
flag&=~2:会将flag的第二个bit置0
26.选择题
下面代码在#pragma pack(4)和#pragma pack(8)的情况下,结构体的大小分别是
答案:C
27.选择题
下面代码运行的结果为
答案:D
28.选择题
下列C程序执行后,c输出的结果为()(32位)
答案:A
注:
1.
int a=-3:
-3的原码:10000000 00000000 00000000 00000011
-3的反码:11111111 11111111 11111111 11111100
-3的补码:11111111 11111111 11111111 11111101
a变量中的数据为11111111 11111111 11111111 11111101
unsigned int b=2:
2的补码:00000000 00000000 00000000 00000010
2.long c=a+b,c中的数据为11111111 11111111 11111111 11111111,c中数据的原码为-1,因此打印出来的值为-1
3.%ld是打印长整型
29.选择题
设有定义char *p[ ]={"Shanghai","Beijing","Hongkong"};则结果为j字符的表达式是()
答案:B
注:
1.*p[1]+3:p[1]为字符串"Beijing"的地址,即首元素B的地址,*p[1]拿到了字符'B',*p[1]+3得到了字符'E'
2.*(p[1]+3):p[1]为字符串"Beijing"的地址,即首元素B的地址,p[1]+3指向了字符'j'的地址,*(p[1]+3)得到了字符'j'
3.*(p[3]+1):越界访问了
4.p[3][1]:越界访问了
30.选择题
执行下面函数后,i的值为()
答案:C
31.选择题
在int[ ][4]={{1},{3,2},{4,5,6},{0}};中,p[1][2]的值是()
答案:B
32.选择题
在下面代码中,fun(21)的运行结果是()
答案:A
注:
1.a^=(1<<5)-1:
1的二进制序列:00000000 00000000 00000000 00000001
(1<<5)-1的二进制序列:00000000 00000000 00000000 00011111
21的二进制序列:00000000 00000000 00000000 00010101
a^=(1<<5)-1的二进制序列:00000000 00000000 00000000 00001010 该二进制十进制为10
33.选择题
下列关于c/c++的宏定义,不正确的是()
答案:B
注:
1.在c语言中const修饰的变量是一个常变量,而在c++中const修饰的变量就是彻彻底底的常量,而宏定义的因为没有类型所以不够严谨,所以鼓励用const修饰(如下代码所示,c++中下面代码是正确的,而在c中下面代码是错误的)
34.选择题
下面关于指针的描述不正确的是()
答案:A
35.选择题
由多个源文件组成的c程序,经过编辑、预处理、编译、链接等阶段会生成最终的可执行程序。下面哪个阶段可以发现被调用的函数未定义
答案:C
36.选择题
#define N 3+1
#define Y(n) ((N+1)*n)
则执行语句z=2*(N+Y(5+1))后,z的值为()
答案:A
37.选择题
char a; int b; flat c; double d;
则表达式a*b+d-c值的类型为()
答案:D
38.Fibonacci数列
代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include<math.h>
int main()
{
int n = 0;
int a = 0;
int b = 1;
int c = a + b;
scanf("%d", &n);
while (1)
{
if (n == b)
{
printf("%d\n", 0);
break;
}
else if (n < b)
{
if (abs(a - n) < abs(b - n))
{
printf("%d\n", abs(a - n));
break;
}
else
{
printf("%d\n", abs(b - n));
break;
}
}
a = b;
b = c;
c = a + b;
}
return 0;
}
39.替换空格
代码链接: 替换空格__牛客网 (nowcoder.com)
代码:(接口型试题)
class Solution {
public:
void replaceSpace(char* str, int length) {
int spacecnt = 0;
char* cur = str;
while (*cur)
{
if (*cur == ' ')
spacecnt++;
cur++;
}
int newlen = length + spacecnt * 2;
int end1 = length - 1;
int end2 = newlen - 1;
while (end1 != end2)
{
if (str[end1] != ' ')
{
str[end2--] = str[end1--];
}
else
{
str[end2--] = '0';
str[end2--] = '2';
str[end2--] = '%';
end1--;
}
}
}
};