目录
选择题
题目1——数据在内存的存储
程序输出是?
#include <stdio.h>
int main()
{
unsigned char i = 7;
int j = 0;
for (; i > 0; i -= 3)
{
++j;
}
printf("%d\n", j);
return 0;
}
错误答案:3
正确答案:173
注意:i是unsigned char类型的i,是无符号类型,则i不可能是负数。
i为7、4、1、(-2)
当-2放到i里时,i会把-2当成正数。
-2的原码:10000000 00000000 00000000 00000010
-2的反码:11111111 11111111 11111111 11111101
-2的补码:11111111 11111111 11111111 11111110
-2的补码放到i里,则发生截断,存放的是11111110这8个比特位,即i是254。
254 / 3 = 84……2
所以i从254开始 -3:254、251、248、……5、2、(-1)
循环停下的条件:i是无符号整数,则最小是0,即00000000。
-1放进i里就是:11111111,即i是255
255 / 3 = 85
即255、252、249……6、3、0
综上i的变化是:
7、4、1、254、251、248……5、2、255、252、249……6、3、0
总共变化3 + 84 +1 + 85 = 173(加上余数为2的那次)
题目2——函数、ASCII码表应用
以下程序运行时,若输入1abcedf2df<回车>输出结果是?
#include <stdio.h>
int main()
{
char a = 0, ch;
while ((ch = getchar()) != '\n')
{
if (a % 2 != 0 && (ch >= 'a' && ch <= 'z'))
ch = ch - 'a' + 'A';
a++;
putchar(ch);
}
printf("\n");
return 0;
}
解题:
//输入:1abcedf2df
#include <stdio.h>
int main()
{
char a = 0, ch;//a = 0 1 2 3 4 5 6 7 8 9 10
while ((ch = getchar()) != '\n')//读到的输入的字符:1abcedf2df
{
if (a % 2 != 0 && (ch >= 'a' && ch <= 'z'))
ch = ch - 'a' + 'A';
// -97 + 65
// ch = ch - 32——变成对应的大写字母
a++;
putchar(ch);//打印:1AbCeDf2dF
}
printf("\n");
return 0;
}
重在考察:
getchar()和putchar()的用法。
大写字母和小写字母的ASCII码值相差32;
小写字母转换为大写字母的方法就是将小写字母的ASCII码值减去32。
题目3——数据在内存的存储
以下哪个选项可以将flag的第二个bit置0?
A、flag &= ~2
B、flag |=2
C、flag ^=2
D、flag >>=2
解题:
这里flag是任何的二进制序列。第二个bit是指倒数第二个位置。
A、-2的原码:10000000 00000000 00000000 00000010
-2的原码:11111111 11111111 11111111 11111101
-2的补码:11111111 11111111 11111111 11111110
~2:对2进行按位取反:
11111111 11111111 11111111 11111101
无论flag的二进制位上第二个bit是1还是0,与此时的0按位与都是0。(对于flag的其他位&1都是让它们保留下来)
正确答案:A
题目4——数据在内存的存储、整型提升
下列程序执行后c输出结果为()(32位)
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = -3;
unsigned int b = 2;
long c = a + b;
printf("%1d\n", c);
return 0;
}
解题:
放在内存中计算:
-3的原码:10000000 00000000 00000000 00000011
-3的反码:11111111 11111111 11111111 11111100
-3的补码:11111111 11111111 11111111 11111101
2的原码:00000000 00000000 00000000 00000010
2的反码:11111111 11111111 11111111 11111101
2的补码:11111111 11111111 11111111 11111110
-3+2:
11111111 11111111 11111111 11111111——补码,整型
因为在32环境,long是4个字节,则完全放得下一个整型
是以补码的形式放到c中的,即c中存放的值就是:11111111 11111111 11111111 11111111
最后打印的是long类型的整型,是有符号的整型!
所以把补码11111111 11111111 11111111 11111111计算到原码打印出来就是-1。
因为a和b都是整型,不用发生整型提升!
整型提升是针对char类型、short类型,不够一个整型大小的变量进行计算的时候才发生整型提升。
这里没有考虑整型提升和算术转换。这里算术转换没有意义,-3放进a里,-3和2进行相加的时候,肯定会把int a进行强转,算术转换为unsigned int,但只是看它的类型不同了,但里面放的还是-3的补码。a变成无符号数,是认为a内存里放的是无符号数,但是值不变,进行加的时候还是那个二进制序列在加。
题目5——指针
设有定义char*p[] = {"shanghai","Beijing","HongKong"};则结果为j字符的表达式是()
A、*p[1] + 3
B、*(p[1] + 3)
C、(p[3] + 1)
D、p[3] [1]
解题:
是3个字符串的首字符地址存到p数组中。
正确图解:
*p[1] = B,B+3=E,A选项的答案是E;是B的ASCII码值+3变成E了。
下标到2,C、D选项均错。
题目6——函数调用
执行如下程序,i的值为?
int f(int x){
return ((x > 2) ? x * f(x - 1) : 3);
}
int i;
i = f(f(2));
解题:
正确的调整后放在VS编译中的位置,函数调用:
#include <stdio.h>
int f(int x)
{
return ((x > 2) ? x * f(x - 1) : 3);
}
int main()
{
int i;
i = f(f(2));
return 0;
}
答案:9
题目7——二维数组
在int p[][4] = {{1},{3,2},{4,5,6},{0}}中,p[1][2]的值是?
解题:
一行是4列,并未指定行,行是通过初始化决定的。则二维数组的内容:
1 0 0 0
3 2 0 0
4 5 6 0
0 0 0 0
答案:0。
题目8——操作符
int fun(int a){
a^=(1<<5)-1;
return a;
}
fun(21)运行结果是?
解题:
#include <stdio.h>
int fun(int a){
a ^= (1 << 5) - 1;
return a;
}
int main()
{
printf("%d\n", fun(21));
return 0;
}
看:a ^= (1 << 5) - 1;
首先:把1向左移动5位,
然后对于 ^= 和 - 需要考虑运算符优先级的问题!
(赋值的运算符在一般情况下会相对低)算 - 后算 ^=
1 << 5 后的结果是:00100000
答案:10
题目9——整型提升与算术转换
char a; int b; float c; double d;则表达式a*b+d-c值的类型为()
a和b进行计算时:a的类型是char类型,与整型b计算时,a肯定会发生整型提升,因为它没有达到一个整型类型,即a和b计算的结果是整型;a*b+d,整型和double类型的d进行计算,则a*b的值需要转换为double类型的值,这是算术转换,即a*b+d算出的结果是double类型的值;a*b+d这个double类型的值与float类型的值进行相减的时候,则c会转换为double类型的值。即最终的结果是double类型的值。
答案:double
编程题
题目1——斐波那契数问题
Fibonacci数列是这样定义的:
F[0] = 0
F[1]=1
for each i >=22 :F[i]=F[i-1]+F[i-2]
因此,Fibonacci数列就形如:0,1,1,2,3,5,8,13..,在Fibonacci数列中的数我们称为Fibonacci数。给你一个N,你想让其变为一个Fibonacci数,每一步你可以把当前数字X变为X-1或者X+1,现在给你一个数N求最少需要多少步可以变为Fibonacci数。
输入描述:
输入为一个正整数N(1 <=N <= 1,000,000)
输出描述:
输出一个最小的步数变为Fibonacci数
解题:
题目的意思是给定一个数,可以这个数+1或这个数-1,让这个数接近一个斐波那契数。
斐波那契数列:0 1 1 2 3 5 8 13 21 34 55……
如给定一个数是6,6靠近5,6-1就变成5了,即向左只要一步就可以变成斐波那契数,向右则需要两步才变成斐波那契数,则最短需要一步即可。
如给定一个数是25,则肯定靠近21而不是靠近34
可以得知,看给定的数落在哪两个斐波那契数中间,需要知道给定的数靠近哪一个斐波那契数,即看给定的数和左右两个数差的绝对值谁小,打印的结果就是小的那个绝对值就是最终的步数。
则需要求两个斐波那契数,看给定的N和这两个斐波那契数的关系。
题目中N的范围过于大,用递归的方法求斐波那契数的效率太差了。
#include <stdio.h>
#include <math.h>
int main()
{
int n = 0;
scanf("%d", &n);
//生成斐波那契数
int a = 0;
int b = 1;
int c = a + b;//此时已经算出一组斐波那契数了
while (1)
{
//看n和a、b、c的关系,如果发现n和b相等,则肯定靠近b,0步就可以变成斐波那契数
if (n == b)
{
printf("%d\n", 0);
break;
}
else if (n < b)
{
//则n在a和b这个范围之间,需要判断n是距离a近,还是距离b近,fab是求绝对值的函数
if (abs(a-n) < abs(b-n))
{
printf("%d\n", abs(a-n));
break;
}
else
{
printf("%d\n", abs(b - n));
break;
}
}
//n>b,则n在后面,即重新生成一组斐波那契数
a = b;
b = c;
c = a + b;
}
return 0;
}
//算(产生)一组斐波那契数,就判断一次;继续产生,判断……
即思路是:不断的生成一组斐波那契数,看给定的N是否在这一组斐波那契数范围之间,还是在这一组斐波那契数的后面。
abs()函数:
int abs( int n );
题目2——空格字符替换
请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
解题:
空格的ASCII码值是20——这是有应用场景的。
已知的接口型:
class Solution {
public:
void replaceSpace(char *str,int length) {
}
};
replaceSpace()函数中,str指向的就是被替换的字符串We Are Happy,length指的是这个字符串的长度。最终的字符串还放到str中。
这个接口完成的任务是:把传进来的str中的length个字符处理成We%20Are%20Happy。
思路:
看字符串中We Are Happy中一共有多少空格,发现有2个;
一个空格是一个字符,一个空格要变成%20,%20是3个字符,即遇到一个一个空格会使整个字符串增加两个长度,所以两个空格会使字符串总长度增加4
y移、p移、p移、a移、h移,不移空格,而是在此处先放0,然后放2,放%,此时处理完空格了,移e,移r,移A,遇到空格,放0,然后放2,放%,再移e,移W。
这里是在原来字符串的后面加4个空格,这里是接口型题就假设它传过来的字符串足够长。
在牛客网提交的代码:
class Solution {
public:
void replaceSpace(char* str, int length) {
int spacecent = 0;
char* cur = str;
while (*cur)//遍历一遍字符串We Are Happy找空格的个数
{
if (*cur == ' ')
{
spacecent++;
}
cur++;
}
int newlen = length + spacecent * 2;//新的字符串长度
int end1 = length - 1;
int end2 = newlen - 1;
//倒着往前遍历字符串
//end1每次-1;
//end2每次也 - 1,遇到空格时 - 2
//最终end1与end2相等。
//用下标的方法
//字符串在内存中是连续存放的,可以理解为数组
while (end1 != end2)
{
if (str[end1] != ' ')
{
str[end2--] = str[end1--];
}
else
{
/*遇到空格时,放0,--向前走,放2,--向前走,放% ,--向前走
当走到e(We中的e)时就没必要移了*/
str[end2--] = '0';
str[end2--] = '2';
str[end2--] = '%';
end1--;
}
}
}
};
不用打印,这个函数只负责替换空格。
在一定程度上是在猜测题目参数的意义。
寄个知识小卡片:
1. “%2d”表示前面空1个空格。
“%ld”表示打印一个长整型,是long类型。(是字母l)
“%lld”表示打印一个长整型,是long long类型。(是字母l)
2. 宏并不是一种好的写法,它没有类型检查,不够严谨,所以通常不建议使用宏。
在C++中,const定义的变量是彻彻底底的常量,所以多用const修饰的常量。
在C语言中const修饰的是常变量。
3. free()函数在释放掉一个指针内容后,指针变量的值不会自己变为NULL,是我们主动把它置为NULL。