?大小端与传参
   
假设在一个 32 位 little endian 的机器上运行下面的程序,结果是多少?
#include <stdio.h>
int main(){
	long long a = 1, b = 2, c = 3;
	printf("%d %d %d\n", a, b, c);
	return 0;
}
    A 1,2,3
    
    B 1,0,2
    
    C 1,3,2
    
    D 3,2,1
   
正确答案:B
这题的考点就是大小端字节序与函数传参顺序
关于大小端问题就是数据在内存中的存储顺序
大端模式(大端字节序):数据的
低字节
保存在内存的
高地址
中,
高字节
保存在
低地址
中
小端模式(小端字节序):
低位
存
低地址
,
高位
存
高地址
下图这就是标准的小端存储
还有一个就是函数传参顺序,调用printf函数需要压栈建立函数栈帧,函数传参是从右向左的,下面就可以看到,不管a,b,c是谁先定义,都只与传参顺序有关。栈底是高地址,栈顶是低地址
    
    a,b,c都是long long类型8字节,而%d只会获取4字节
   
    
    
    ?类型范围
   
如下代码输出的是
char a=101;
int sum=200;
a+=27;sum+=a;
printf("%d\n",sum);
    A: 327
    
    B: 99
    
    C: 328
    
    D: 72
   
正确答案:D
这题的考点就是类型的范围,char类型是8位,也就是-128~127
所以a+=27后a的值为-128
    
    
    ?逻辑判断
   
以下程序的输出结果是
#include <iostream>
int main() 
{
	int x = 3, y = 3;
	switch (x % 2) {
	case 1:
		switch (y) {
		case 0:cout << "first";
		case 1:cout << "second"; break;
		default: cout << "hello";
		}
	case 2:cout << "third";
	}
}
    A second third
    
    B hello
    
    C first second
    
    D hellothird
   
正确答案:D
这题的考点就是switch case语句的理解,当进入case语句没有break时,就会继续按顺序执行,还有break与continue,continue只会跳出当前循环,然后判断是否满足下一次的循环条件
#include <stdio.h>
int main()
{
	int a = 1, b = 2, c = 3, d = 0;
	if (a == 1 && b++ == 2)
		if (b != 2 || c-- != 3)
			printf("%d,%d,%d\n", a, b, c);
		else
			printf("%d,%d,%d\n", a, b, c);
	else
		printf("%d,%d,%d\n", a, b, c);
	return 0;
}
    下面程序输出的是
    
    A 1, 2, 3
    
    B 1, 3, 2
    
    C 3, 2, 1
    
    D 1, 3, 3
   
正确答案:D
这题的考点就是逻辑语句的短路原则
if(表达式一 || 表达式二)当表达式一为真时,就不会执行表达式二
if(表达式一 &&表达式二) 当表达式一为假 时,就不会执行表达式二
所以b != 2位真后就不会执行后面的
比如要拿栈顶的元素与val比较时,只有栈不为空时才能取栈底元素
if (!st.empty() && st.top() == val)
    
    
    ?进制数与格式化输出
   
#include<iostream>
using namespace std;
int main()
{
	int m = 0123, n = 123;
	printf("%o %o\n", m, n);
	return 0;
}
    程序运行后的输出结果是()
    
    A 0123 0173
    
    B 0123 173
    
    C 123 173
    
    D 173 173
   
正确答案:C
这题就是C语言常见进制的表示形式以及打印格式化数据的方式
二进制: 101b
八进制:0123 printf打印时 %o
十进制: 101 printf打印时 %d
十六进制:0x123 printf打印时 %x
m是八进制,所以直接打印123
以下程序的运行结果是()
int main()
{
	printf("%s , %5.3s\n", "computer", "computer");
	return 0;
}
    A computer, puter
    
    B computer,   com
    
    C computer,   computer
    
    D computer,   compu.ter
   
正确答案:B
这题考点与上面类似,也是打印格式化的数据
%m.ns
,m表示宽度,n表示打印字符的个数,右对齐,不足补空格,当n大于m时直接打印n个字符。-m就是左对齐,还有%04d右对齐打印,宽度为4,不足补0
    
    
    ?计算次数
   
求函数返回值,输入x = 9999
int func(int x) {
	int count = 0;
	while (x)
	{
		count++;
		x = x & (x - 1);
	}
	return count;
}
    A:8
    
    B:9
    
    C:10
    
    D:12
   
正确答案:A
这题的考点就是计算一个数中1的个数,x=x&(x-1)会不断将x中的1变为0,到最后所有位都为0时循环也就结束了,9999转化为2进制有8个1
同样的还有计算一个数中0的个数
while (x + 1)
{
	x = x | (x + 1);//计算0的个数
	++count;
}
#include<stdio.h>
int cnt = 0;
int fib(int n)
{
	cnt++;
	if (n == 0)
		return 1;
	else if (n == 1)
		return 2;
	else
		return fib(n - 1) + fib(n - 2);
}
int main()
{
	fib(8);
	printf("%d", cnt);
}
    下列程序执行后, 输出的结果为()
    
    A 41
    
    B 67
    
    C 109
    
    D 177
   
正确答案:B
这题的考点就是计算函数调用的次数,实际上就是计算斐波那契的次数,因为fib(8)最后递推到fib(0)和fib(1),利用递归的思想,我们可以直接回归到f(0)开始计算
fib(0) 1
fib(1) 1
fib(2) 1+fib(1)+fib(0) = 3
fib(3) 1+fib(2)+fib(1) = 5
fib(4) 1+fib(3)+fib(2) = 9
fib(5) 1+fib(4)+fib(3) = 15
fib(6) 1+fiib(5)+fib(4) = 25
fib(7) 1+fib(6)+fib(5) = 41
fib(8) 1+fib(7)+fib(6) = 67
    
    
    ?常量指针与指针常量
   
请声明一个指针,其所指向的内存地址不能改变,但内存中的值可以被改变。
A const int const *x = &y;
B int * const x = &y;
C const int *x = &y;
D int const *x = &y;
E const int * const x = &y;
正确答案:B
这题的考点就是常量指针与指针常量的认识。
指针常量
:指针本身是一个常量,指针的指向不能改变,但指针所指向的值可以发生改变,可以通过解引用改变指针所指向空间的值
常量指针
:指向常量的指针,不能通过解引用改变指针所指向的空间的值,但指针的指向可以发生改变
区分:const与*的相对位置
const在*左边修饰的是指针所指的空间,所以是常量指针,const在*右边修饰的是指针,所以是指针常量
    
    
    ?字符指针与字符数组
   
下面叙述错误的是()
char acX[] = "abc";
char acY[] = { 'a','b','c' };
char* szX = "abc";
char* szY = "abc";
    A acX与acY的内容可以修改
    
    B szX与szY指向同一个地址
    
    C acX占用的内存空间比acY占用的大
    
    D szX的内容修改后,szY的内容也会被更改
   
正确答案: D
这题考点和上面类似,判断的是字符数组与字符指针的区别,字符数组是从常量区将字符串拷贝到数组,数组中存放的字符串是可以修改的,而字符指针是指向在常量区的常量字符串,不可修改,szX与szY指向的都是那个常量字符串,所以指向的是同一个地址
C选项,因为acY里面没有\0,而acX会带\0,所以正确
    
    
    ?指针与数组
   
下面程序打印的结果是
#include <stdio.h>
int main()
{
	char p1[15] = "abcd", *p2 = "ABCD", str[50] = "xyz";
	strcpy(str + 2, strcat(p1 + 2, p2 + 1));
	printf("%s", str);
}
    A xyabcAB
    
    B abcABz
    
    C ABabcz
    
    D xycdBCD
    
    E 运行出错
   
正确答案:D
这题的考点就是对字符函数stcpy和strcat的认识,拷贝和追加的目的地空间都要足够大,不然程序就会崩溃运行出错。strcat会返回追加后的目的地址,也就是p1+2
假设函数原型和变量说明如下,则调用合法的是( )
void f(int **p);
int a[4]={1,2,3,4};
int b[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
int *q[3]={b[0],b[1],b[2]};
    A: f(a);
    
    B: f(b);
    
    C: f(q);
    
    D: f(&a);
   
正确答案:C
这题的考点就是对指针和数组的掌握
A选项:数组名是首元素地址,应该用int* p接收
B选项:数组名是首元素地址,也就是一维数组的地址,应该用int(*p)[ ]接收
C选项:q是一个指针数组,数组ing是首元素地址,也就是b[o]的地址,b[o]是一个一维数组,但数组传参会退化成指针,所以是一个一级指针的地址,可以用int** p接收
D选项:&数组名,应该用int(*p)[ ]接收
#include<iosteam.h>
int main() 
{
	int n[][3] = { 10,20,30,40,50,60 };
	int(*p)[3];
	p = n;
	cout << p[0][0] << "," << *(p[0] + 1) << "," << (*p)[2] << endl;
}
    下面程序的输出结果是
    
    A 10, 30, 50
    
    B 10, 20, 30
    
    C 20, 40, 60
    
    D 10, 30, 60
   
正确答案:B
这题的考点同样是对数组与指针的掌握情况n是一个2行3列的二维数组,p是一个数组指针,指向的是一个有3个元素的int型数组
    数组 a 的定义为: int a[3][4]; 下面哪个不能表示 a[1][1] ( )
    
    A: *(&a[0][0]+5)
    
    B: *(*(a+1)+1)
    
    C: *(&a[1]+1)
    
    D: *(a[1]+1)
   
正确答案:C
C选项实际表示的是a[2][0]
    void (*s[5])(int) 表示意思为( )
    
    A: 函数指针 B: 函数指针数组 C: 数组指针函数 D: 语法错误
   
正确答案:B
s先和[ ]结合,所以是一个数组有5个元素,元素类型是void(*)(int)函数指针,所以s是一个函数指针数组
    
    
    ?内存对齐
   
下面两个结构体
struct One
{
	double d;
	char c;
	int i;
};
struct Two
{
	char c;
	double d;
	int i;
};
    在#pragma pack(4)和#pragma pack(8)的情况下,结构体的大小分别是
    
    A 16 24, 16 24
    
    B 16 20, 16 20
    
    C 16 16, 16 24
    
    D 16 16, 24 24
   
正确答案: C
这题的考点就是内存对齐问题,在#pragma pack(4)的情况下,最大对齐数是4,在#pragma pack(8)的情况下,最大对齐数是8,所以在计算struct(Two)时,本来是20但要是对大对齐数的整数倍,所以就变成了24了
在32位cpu上选择缺省对齐的情况下,有如下结构体定义:
struct A
{
	unsigned a : 19;
	unsigned b : 11;
	unsigned c : 4;
	unsigned d : 29;
	char index;
}
    则sizeof(A)的值为
    
    A 9
    
    B 12
    
    C 16
    
    D 20
   
正确答案:C
这题考察的是对位段的认识,位段的成员可以是
int
、
unsigned int
、
signed int
或者是
cha
r 类型的整形家族,位段的成员名后边有一个冒号和一个数字。每次开辟
4字节
或
1字节
冒号后面接的是所需要的的比特位
    
    
    ?动态内存分配
   
关于内存管理,以下有误的是( )(不定项选择)
    A: malloc在分配内存空间大小的时候是以字节为单位
    
    B: 如果原有空间地址后面还有足够的空闲空间用来分配,则在原有空间后直接增加新的空间,使得增加新空间后的空间总大小
    
    是:newSize
    
    C: 如果原有空间地址后面没有足够的空闲空间用来分配,那么从堆中另外找一块newsize大小的内存,并把先前内存空间中的数
    
    据复制到新的newSize大小的空间中,然后将之前空间释放
    
    D: free函数的作用是释放内存,内存释放是标记删除,会修改当前空间的所属状态,并且会清除空间内容
    
    E: 可以通过内存分配函数malloc(size_t)直接申请物理内存
   
正确答案:DE
free函数,作用是释放内存,内存释放是标记删除, 只会修改当前空间的所属状态,并不会清除空间内容
free释放的内存不一定直接还给操作系统,可能要到进程结束才释放。malloc不能直接申请物理内存,它申请的是虚拟内存
以上就是C语言的基础选择提了,如果这些题都做对了,那你的C语言基础还是很扎实的,希望我的文章对你有所帮助,欢迎?点赞 ,?评论,?关注,⭐️收藏
     
   
 








