下面哪个不是关键字:
A.int
B.struct
C.define
D.continue
答案解析:
C语言关键字:C语言定义的,具有特定含义、专门用于特殊用途的C语言标识符,也称为保留字
define不是关键字,是编译器实现的,用来定义宏的预处理指令,不是C语言中的内容。
int、struct和continue都是C语言中包含的关键字
因此:选择C
BC113-小乐乐定闹钟
BC113-小乐乐定闹钟
#include <stdio.h> int main() { int h = 0; int m = 0; int k = 0; scanf("%d:%d %d", &h, &m, &k); h = ((m+k)/60+h)%24; m = (m+k)%60; printf("%02d:%02d\n", h, m); return 0; }
BC16-字符转ASCII码
BC16-字符转ASCII码
#include <stdio.h> int main() { char ch = 0; scanf("%c", &ch); printf("%d\n",ch); return 0; }
下面代码执行的结果是:
A.1 2 3 4 5 6 7 8 9 10
B.5 5 5 5 5 5 5 5 5 5
C.死循环的打印5
D.0 1 2 3 4 5 6 7 8 9
答案解析:
上述代码本来的想法应该是:循环10次,每次循环时如果i==5则打印i的结果。
但if语句中表达式的==写成了赋值,相当于每次循环尽量都是将i的值设置成了5,5为真,因此每次都会打印5
i每次修改成5打印后,i的值永远不会等于10,因此造成死循环
故:死循环的打印5
因此:选择C
关于if语句说法正确是
A.if语句后面只能跟一条语句
B.if语句中0表示假,1表示真
C.if语句是一种分支语句,可以实现单分支,也可以实现多分支
D.else语句总是和它的对齐的if语句匹配
A:错误,if之后可以跟多条语句,跟多条语句时需要使用{}括起来
B:错误,0表示假,非零表示真
C:正确
D:不一定,要看具体的代码,如果代码不规范,可能没有对齐
下面代码的执行结果是什么
#include <stdio.h> int main() { int x = 3; int y = 3; switch (x % 2) { case 1: switch (y) { case 0: printf("first"); case 1: printf("second"); break; default: printf("hello"); } case 2: printf("third"); } return 0; }
A.secondthird
B.hello
C.firstsecond
D.hellothird
答案解析:
switch语句时多分支的选择语句,switch中表达式结果命中那个case,就执行该case子项,如果case子项后没有跟break语句,则继续往下执行。
关于该题解析,请看以下注解:
#include <stdio.h> int main() { int x = 3; int y = 3; switch (x % 2) { // x%2的结果为1,因此执行case1 case 1: switch (y) // y是3,因此会执行case3,而case3不存在,那只能执行default { case 0: printf("first"); case 1: printf("second"); break; default: printf("hello"); // 打印hello,打印完之后,内部switch结束,此时外部case1结束 } // 因为外部case1之后没有添加break语句,所以继续执行case2 case 2: // 打印third printf("third"); // 外部switch结束 } return 0; }
即:先在内部switch的default位置打印hello,紧接着在外部case2中打印third
因此:选择D
关于指针说法正确的是:
A.sizeof(char*)大小一定是1
B.指针变量是个变量,用来存放地址
C.指针变量的大小都是4个字节
D.指针不是变量
答案解析:本题主要考察指针的相关特性
A:错误,指针是一种复合数据类型,指针变量内容是一个地址,因此一个指针可以表示该系统的整个地址集合,
故按照32位编译代码,指针占4个字节,按照64位编译代码,指针占8个字节(注意:不是64位系统一定占8个字 节,关键是要按照64位方式编译)
B:正确
C:错误,参考A选项解释
D:错误,该条描述比较模糊 指针可以认为是一种数据类型,也可以认为是定义出来的指针变量
因此,选择B
关于switch说法不正确的是:
A.switch语句中的default子句可以放在任意位置
B.switch语句中case后的表达式只能是整形常量表达式
C.switch语句中case子句必须在default子句之前
D.switch语句中case表达式不要求顺序
答案解析:
A:正确,可以放在任意位置,但是一般建议最好还是放在最后
B:正确,case语句后一般放整形结果的常量表达式或者枚举类型,枚举类型也可以看成是一个特殊的常量
C:错误,没有规定case必须在default之前,一般case最好放在default之前
D:正确,但一般还是按照次序来
因此:选择C
打印3的倍数的数
写一个代码打印1-100之间所有3的倍数的数字
/* 解题思路: 1. 3的倍数一定能够被3整除,因此i%3==0表达式成立时,则i一定是3的倍数 2. 要输出1~100之间的3的倍数,那只需要从1~100循环100次即可,每次拿到i之后,用i%3==0检测 如果成立:i是3的倍数,输出 如果不成立:i不是3的倍数 */ #include <stdio.h> int main() { int i = 0; for(i=1; i<=100; i++) { if(i%3==0) { printf("%d ", i); } } return 0; }
从大到小输出
写代码将三个整数数按从大到小输出。
例如:
输入:2 3 1
输出:3 2 1
/* 思路: 该题比较简单,参考代码 */ #include <stdio.h> int main() { int a = 2; int b = 3; int c = 1; scanf("%d%d%d",&a, &b,&c); if(a<b) { int tmp = a; a = b; b = tmp; } if(a<c) { int tmp = a; a = c; c = tmp; } if(b<c) { int tmp = b; b = c; c = tmp; } printf("a=%d b=%d c=%d\n", a, b, c); return 0; }
打印素数
写一个代码:打印100~200之间的素数
/* 思路: 素数:即质数,除了1和自己之外,再没有其他的约数,则该数据为素数,具体方式如下 */ //方法一:试除法 int main() { int i = 0; int count = 0; // 外层循环用来获取100~200之间的所有数据,100肯定不是素数,因此i从101开始 for(i=101; i<=200; i++) { //判断i是否为素数:用[2, i)之间的每个数据去被i除,只要有一个可以被整除,则不是素数 int j = 0; for(j=2; j<i; j++) { if(i%j == 0) { break; } } // 上述循环结束之后,如果j和i相等,说明[2, i)之间的所有数据都不能被i整除,则i为素数 if(j==i) { count++; printf("%d ", i); } } printf("\ncount = %d\n", count); return 0; } //上述方法的缺陷:超过i一半的数据,肯定不是i的倍数,上述进行了许多没有意义的运算,因此可以采用如下 // 方式进行优化 // 方法二:每拿到一个数据,只需要检测其:[2, i/2]区间内是否有元素可以被2i整除即可,可以说明i不是素数 int main() { int i = 0;// int count = 0; for(i=101; i<=200; i++) { //判断i是否为素数 //2->i-1 int j = 0; for(j=2; j<=i/2; j++) { if(i%j == 0) { break; } } //... if(j>i/2) { count++; printf("%d ", i); } } printf("\ncount = %d\n", count); return 0; } /* 方法二还是包含了一些重复的数据,再优化: 如果i能够被[2, sqrt(i)]之间的任意数据整除,则i不是素数 原因:如果 m 能被 2 ~ m-1 之间任一整数整除,其二个因子必定有一个小于或等于sqrt(m),另一个大于或等于 sqrt(m)。 */ int main() { int i = 0; int count = 0; for(i=101; i<=200; i++) { //判断i是否为素数 //2->i-1 int j = 0; for(j=2; j<=sqrt(i); j++) { if(i%j == 0) { break; } } //... if(j>sqrt(i)) { count++; printf("%d ", i); } } printf("\ncount = %d\n", count); return 0; } //方法4 /* 继续对方法三优化,只要i不被[2, sqrt(i)]之间的任何数据整除,则i是素数,但是实际在操作时i不用从101逐渐递增到200,因为出了2和3之外,不会有两个连续相邻的数据同时为素数 */ int main() { int i = 0; int count = 0; for(i=101; i<=200; i+=2) { //判断i是否为素数 //2->i-1 int j = 0; for(j=2; j<=sqrt(i); j++) { if(i%j == 0) { break; } } //... if(j>sqrt(i)) { count++; printf("%d ", i); } } printf("\ncount = %d\n", count); return 0; }
打印闰年
打印1000年到2000年之间的闰年
/* 思路: 要求1000年到2000年之间的闰年,只需要知道求解闰年的方法即可。 闰年的条件:如果N能够被4整除,并且不能被100整除,则是闰年 或者:N能被400整除,也是闰年 即:4年一润并且百年不润,每400年再润一次 */ #include <stdio.h> int main() { int year = 0; for(year=1000; year<=2000; year++) { //判断year是否为闰年 if(year%4==0) // 如果year能够被4整除,year可能为闰年 { if(year%100!=0) // 如果year不能内100整除,则一定是闰年 { printf("%d ", year); } } if(year%400 == 0) // 每400年再润一次 { printf("%d ", year); } } return 0; } // //介绍一下这种的简单写法 // int main() { int year = 0; for(year=1000; year<=2000; year++) { if(((year%4==0)&&(year%100!=0))||(year%400==0)) { printf("%d ", year); } } return 0; }
最大公约数
给定两个数,求这两个数的最大公约数
例如:
输入:20 40
输出:20
/* 最大公约数:即两个数据中公共约数的最大者。 求解的方式比较多,暴力穷举、辗转相除法、更相减损法、Stein算法算法 此处主要介绍:辗转相除法 思路: 例子:18和24的最大公约数 第一次:a = 18 b = 24 c = a%b = 18%24 = 18 循环中:a = 24 b=18 第二次:a = 24 b = 18 c = a%b = 24%18 = 6 循环中:a = 18 b = 6 第三次:a = 18 b = 6 c=a%b = 18%6 = 0 循环结束 此时b中的内容即为两个数中的最大公约数。 */ int main() { int a = 18; int b = 24; int c = 0; while(c=a%b) { a = b; b = c; } printf("%d\n", b); return 0; }
下面哪个是位操作符:
A.&
B.&&
C.||
D.!
答案解析:
A. & 是按位与操作符,正确
B. && 是逻辑与,不是按位与,错误
C. || 是逻辑或,错误
D. ! 是逻辑反操作符,错误
下面代码的结果是:
#include <stdio.h> int main() { int a, b, c; a = 5; c = ++a; b = ++c, c++, ++a, a++; b += a++ + c; printf("a = %d b = %d c = %d\n:", a, b, c); return 0; }
A.a = 8 b = 23 c = 8
B.a = 9 b= 23 c = 8
C.a = 9 b = 25 c = 8
D.a = 9 b = 24 c = 8
答案解析:
++运算符:分为前置++和后置++,
前置++:先加1,后使用,即先使用变量中内容,然后给结果加1
后置++:先使用变量中内容,整个表达式结束时,给变量加1
逗号表达式,取最后一个表达式的值。
#include <stdio.h> int main() { int a, b, c; a = 5; c = ++a;// ++a:加给a+1,结果为6,用加完之后的结果给c赋值,因此:a = 6 c = 6 b = ++c, c++, ++a, a++; // 逗号表达式的优先级,最低,这里先算b=++c, b得到的是++c后的结果,b是7 // b=++c 和后边的构成逗号表达式,依次从左向右计算的。 // 表达式结束时,c++和,++a,a++会给a+2,给c加1,此时c:8,a:8,b:7 b += a++ + c; // a先和c加,结果为16,在加上b的值7,比的结果为23,最后给a加1,a的值为9 printf("a = %d b = %d c = %d\n:", a, b, c); // a:9, b:23, c:8 return 0; }
因此:选择B
交换两个变量(不创建临时变量)
不允许创建临时变量,交换两个整数的内容
#include <stdio.h> int main() { int a = 10; int b = 20; printf("交换前:a = %d b = %d\n", a,b); a = a^b; b = a^b; a = a^b; printf("交换后:a = %d b = %d\n", a,b); return 0; }
统计二进制中1的个数
写一个函数返回参数二进制中 1 的个数。
比如: 15 0000 1111 4 个 1
牛客网的OJ链接
https://www.nowcoder.com/questionTerminal/8ee967e43c2c4ec193b040ea7fbb10b8
/* 方法一: 思路: 循环进行以下操作,直到n被缩减为0: 1. 用该数据模2,检测其是否能够被2整除 2. 可以:则该数据对应二进制比特位的最低位一定是0,否则是1,如果是1给计数加1 3. 如果n不等于0时,继续1 */ int count_one_bit(int n) { int count = 0; while(n) { if(n%2==1) count++; n = n/2; } return count; } /* 上述方法缺陷:进行了大量的取模以及除法运算,取模和除法运算的效率本来就比较低。 方法二思路: 一个int类型的数据,对应的二进制一共有32个比特位,可以采用位运算的方式一位一位的检测,具体如下 */ int count_one_bit(unsigned int n) { int count = 0; int i = 0; for(i=0; i<32; i++) { if(((n>>i)&1) == 1) count++; } return count; } /* 方法二优点:用位操作代替取模和除法运算,效率稍微比较高 缺陷:不论是什么数据,循环都要执行32次 方法三: 思路:采用相邻的两个数据进行按位与运算 举例: 9999:10 0111 0000 1111 第一次循环:n=9999 n=n&(n-1)=9999&9998= 9998 第二次循环:n=9998 n=n&(n-1)=9998&9997= 9996 第三次循环:n=9996 n=n&(n-1)=9996&9995= 9992 第四次循环:n=9992 n=n&(n-1)=9992&9991= 9984 第五次循环:n=9984 n=n&(n-1)=9984&9983= 9728 第六次循环:n=9728 n=n&(n-1)=9728&9727= 9216 第七次循环:n=9216 n=n&(n-1)=9216&9215= 8192 第八次循环:n=8192 n=n&(n-1)=8192&8191= 0 可以观察下:此种方式,数据的二进制比特位中有几个1,循环就循环几次,而且中间采用了位运算,处理起来比较高效 */ int count_one_bit(int n) { int count = 0; while(n) { n = n&(n-1); count++; } return count; }
打印整数二进制的奇数位和偶数位
获取一个整数二进制序列中所有的偶数位和奇数位,分别打印出二进制序列
/* 思路: 1. 提取所有的奇数位,如果该位是1,输出1,是0则输出0 2. 以同样的方式提取偶数位置 检测num中某一位是0还是1的方式: 1. 将num向右移动i位 2. 将移完位之后的结果与1按位与,如果: 结果是0,则第i个比特位是0 结果是非0,则第i个比特位是1 */ void Printbit(int num) { for(int i=31; i>=1; i-=2) { printf("%d ", (num>>i)&1); } printf("\n"); for(int i=30; i>=0; i-=2) { printf("%d ", (num>>i)&1); } printf("\n"); }
求两个数二进制中不同位的个数
编程实现:两个int(32位)整数m和n的二进制表达中,有多少个位(bit)不同?
输入例子:
1999 2299
输出例子:7
牛客网的OJ链接(超链接)
https://www.nowcoder.com/questionTerminal/9c3b8a8d9f1c4ae3b709d04625586225
/* 思路: 1. 先将m和n进行按位异或,此时m和n相同的二进制比特位清零,不同的二进制比特位为1 2. 统计异或完成后结果的二进制比特位中有多少个1即可 */ #include <stdio.h> int calc_diff_bit(int m, int n) { int tmp = m^n; int count = 0; while(tmp) { tmp = tmp&(tmp-1); count++; } return count; } int main() { int m,n; while(scanf("%d %d", &m, &n) == 2) { printf("%d\n", calc_diff_bit(m, n)); } return 0; }
下面代码的结果是
#include <stdio.h> int main() { int i = 1; int ret = (++i)+(++i)+(++i); printf("ret = %d\n", ret); return 0; }
A.10
B.12
C.9
D.程序错误
答案解析:
表达式(++i)+(++i)+(++i),只有操作符的优先级和结合性,没法确定唯一计算路径
所以这个表达式可能因为计算顺序的差异导致结果是不一致的,所以表达式是错误的表达式。
可以在VS和Linux gcc测试,结果可能有差异。
下面代码的结果是:
#include <stdio.h> int i; int main() { i--; if (i > sizeof(i)) { printf(">\n"); } else { printf("<\n"); } return 0; }
A.>
B.<
C.不输出
D.程序有问题
答案解析:
C语言中,0为假,非0即为真。
全局变量,没有给初始值时,编译其会默认将其初始化为0。
i的初始值为0,i–结果-1,i为整形,sizeof(i)求i类型大小是4,按照此分析来看,结果应该选择B,但是sizeof的返回值类型实际为无符号整形,因此编译器会自动将左侧i自动转换为无符号整形的数据,-1对应的无符号整形是一个非常大的数字,超过4或者8,故实际应该选择A
这道题其实很隐蔽,真是虾仁猪心!!!
因此:选择A
关于表达式求值说法不正确的是:
A.表达式求值先看是否存在整形提升或算术转换,再进行计算
B.表达式真正计算的时候先看相邻操作符的优先级决定先算谁
C.相邻操作符的优先级相同的情况下,看操作符的结合性决定计算顺序
D.只要有了优先级和结合性,表达式就能求出唯一值
答案解析:
A:正确
B:正确
C:正确
D: 错误,有了优先级和结核性,表达式也有可能有不同的计算机路径,导致计算结果的差异。
BC100-有序序列合并
#include <stdio.h> int main() { int n = 0; int m = 0; int arr1[100] = {0}; int arr2[100] = {0}; //输入 scanf("%d %d", &n, &m); int i = 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(i == n) { for(; j<m; j++) { printf("%d ", arr2[j]); } } else { for(; i<n; i++) { printf("%d ", arr1[i]); } } return 0; }
BC96-有序序列判断
#include <stdio.h> int main() { int n = 0; int arr[50] = {0}; scanf("%d", &n); int i = 0; int flag1 = 0; int flag2 = 0; for(i=0; i<n; i++) { scanf("%d", &arr[i]); if(i>0) { if(arr[i]>arr[i-1]) flag1 = 1; else if(arr[i]<arr[i-1]) flag2 = 1; } } //flag1 和 flag2 都为1是乱序的 if(flag1+flag2 > 1) printf("unsorted\n"); else printf("sorted\n"); return 0; }
BC54-获得月份天数
#include <stdio.h> int main() { int y = 0; int m = 0; int days[12] = {31,28,31,30,31,30,31,31,30,31,30,31}; while(scanf("%d%d", &y, &m) != EOF) { int day = days[m-1]; if((y%4==0 && y%100!=0) || (y%400==0)) { if(m == 2) day += 1; } printf("%d\n", day); } return 0; }
C程序常见的错误分类不包含:
A.编译错误
B.链接错误
C.栈溢出
D.运行时错误
答案解析:
栈溢出是运行时错误的一种,因此C程序为将栈溢出单独列出,栈溢出包含在运行时错误中。
因此:选择C
C语言中哪一种形式声明了一个指向char类型变量的指针p,p的值不可修改,但p指向的变量值可修改?
A.const char *p
B.char const p
C.charconst p
D.const char *const p
答案解析:
A:错误,const修饰*p,表示p指向的内容不能修改
B:错误,同上
C:正确,const修饰p本身,表示p的指向不能修改,p指向的空间中内容可以修改
D:错误,第一个const表示p指向的内容不能修改,第二个const表示p不能指向其他变量
因此,选择C
以下关于指针的说法,正确的是
A.int *const p与int const *p等价
B.const int *p与int *const p等价
C.const int *p与int const *p等价
D.int *p[10]与int (*p)[10]等价
答案解析:
A:错误,int* const p中,const修饰指针变量p本身,表示p的指向不能改变,
int const *p中,const修饰p指针解引用之后的结果,表示p指向的内容不能改变
因此,不等价
B:错误,同上
C:正确,const都修饰p指针解引用之后的结果,表示p指向的内容不能改变
D:错误,int p[10]定义了一个指针数组,数组中10个元素,每个元素都是int类型的指针
int (*p)[10]定义了一个数组指针,该指针只能指向存储10个整形元素的数组
因此:选择C
BC68-X形图案
#include <stdio.h> int main() { int n = 0; while(scanf("%d", &n) != EOF) { int i = 0; int j = 0; for(i=0; i<n; i++) { for(j=0; j<n; j++) { if(i == j) printf("*"); else if(i+j == n-1)//因为行和列是从0开始的 printf("*"); else printf(" "); } printf("\n"); } } return 0; }
BC60-带空格直角三角形图案
#include <stdio.h> /* int main() { int n = 0; while(scanf("%d", &n) != EOF) { int i = 0; //行数控制 for(i=0; i<n; i++) { //空格 int j = 0; for(j=0; j<n-1-i; j++) { printf(" "); } //* for(j=0; j<=i; j++) { printf("* "); } printf("\n"); } } return 0; } */ int main() { int n = 0; while(scanf("%d", &n) != EOF) { int i = 0; int j = 0; //行数 for(i=0; i<n; i++) { //一行 for(j=0; j<n; j++) { //行和列的和 //这里可以把行数和列数标出来就能看明白 if(i+j<n-1) { printf(" "); } else { printf("* "); } } printf("\n"); } } return 0; }