前些天公司摸底 C 语言考试,得分比较难看,回来发了考试答案,这篇博客把我做错的题目拿出来理一理,补补课。
判断对错:在定义数据结构时,没有特殊理由的话,都定义成四字节对齐;这样做可能浪费几个字节,但是不会出问题。
这道题答案是对的,需要仔细 Google。
以下程序运行 (64 位系统) 后的输出结果是 6 5 8 5
int main()
{
char str1[] = "Hello";
char str2[] = {‘H‘, ‘e‘, ‘l‘, ‘l‘, ‘o‘};
char *p = str1;
printf("%d %d %d %d\n", sizeof(str1), sizeof(str2), sizeof(p), strlen(p));
}
这道题我的答案是 6,5,4,5,原因在于 64 位的指针的长度大小是 8 个字节,而不是一般的 4 个字节。 考点为 字符串数组长度 (+1), 64 位指针长度 (8) 字符串数组 x 包含末尾的’\0’
如下程序, 在 64bit 系统运行输出为 24 4 8 16
struct s1
{
char a;
int b;
short c;
double d;
};
int main(void)
{
printf("%d %d %d %d\n",
sizeof(struct s1), offsetof(struct s1, b), offsetof(struct
s1, c), offsetof(struct s1, d) ) ;
//注: offsetof 为计算偏移量的宏
return 0;
}
我的答案是 48,8,16,32,错误成了 2 倍。主要为结构体对齐规则, 这部分需要强化 一般考生都可以看到 b 按 4 字节对齐,需要填充 忽视 double 也需要 8 字节对齐 double 在 32 位 linux 平台下可能按照 4 字节对齐
如下指针计算, 结果为 4
int *p1 = (int *)0x500;
int *p2 = (int *)0x510;
printf(“%d\n”, (p2 - p1));
我错成了 16,答案应该是 16/4,指针的减法,按照指针类型计算跨越的步长
如下程序, 请问输出多少? -128,128
void main(void)
{
char x = 127;
char a = x + 1;
int b = x + 1;
printf("%d %d", a, b);
}
我的答案是 128,128,整型加法隐式提升到 int 然后运算,所以 x+1 就是 128 溢出出现在赋值运算,第一个溢出了,第二个没有。没有考虑到第一个溢出之后的数据显示问题
如下程序片段, 输出为: 2 7
int *p;
int x[3][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
p = x[0] + 1;
printf("%d %d\n", *p, x[2][0]);
我的答案是 4 7 。x[0] 是对二级指针解引用,类型是指向整型的指针,指向 1,+1 后,指向 x[0][1] 没争议
计算如下定义长度 (64 位系统)
typedef union {
int a;
long b;
char c[6];
}un;
sizeof(un) = 8
我的答案是 48,联合体的内存大小不会算,共用体的占用空间的大小,按照其最大成员算 本题中 long 是 8 字节
请问输出多少
union packet
{
struct packet_bit
{
unsigned char a:2;
unsigned char b:3;
unsigned char c:4;
} bit;
int i;
} data;
int main()
{
data.i = 0;
data.bit.a = 1;
data.bit.b = 2;
data.bit.c = 0xF;
printf("0x%04x\n", data.i);
}
我的答案是 0xf,这道题完全是蒙出来的,考察的是位域的概念,位域结构体,按地址从低到高依次存储 a、b、c 一个规则大家可能都不熟悉: 一个位域必须存储在同一个字节中,不能跨两个字节 所以 a 和 b 储存在一个字节,c 再进来存不下,所以 c 单独存放在一个字节 再就是注意输出格式
如下程序, 请写出打印结果 A b
void fun(char *a, char *b)
{
a = b;
(*a)++;
}
void main()
{
char c1 = ‘A‘, c2 = ‘a‘;
char *p1 = &c1;
char *p2 = &c2;
fun(p1, p2);
printf("%c %c\n", c1, c2);
}
我的结果是 a b, 函数入参是按值传递的,只有通过传递地址才能改变函数外部的值,这里有一个陷阱,使用的地址,实际是从参数 b 传进来的,所以改变的也是参数 b 指向的值 。这道题不该错,因为在 fun 函数里,a 的值已经是 b 了,所以 a 指向的就是 b 指向的地址,因此改变的就是 c2 指向的字母啊
下面函数的输出是 token3 = 4
#define paster( n ) printf( "token" #n " = %d", token##n )
void fun()
{
int token3 = 4;
int tokenn = 3;
paster( 3 );
}
我的答案是 token3 = 3,这是个知识盲点,可以参考 C 语言宏定义 ## 连接符和 #符的使用,# 将本身的字符替换之后再在两边加上双引号,## 是机械单纯得将两个 token 连接在一起
如下程序, 输出为 100008 100001 100004
struct test
{
int a;
int b;
};
int main ()
{
struct test *p = (struct test *)0x100000;
printf("%x %x %x\n", (p+1), (long)p+1, (int *)p +1);
}
我的答案是 0x100008,0x100001,0x11。这道题比较有意思,程序第 8 行已经说明了,p 的值就是 0x100000(也就是说 p 指向的地址是 0x100000),后面 (int *)p,说明了它指向的是 int 类型,那么 + 1 就是在原来的地址上一个 int 的字节数,也就是 0x100004。需要总结的是,指针前面的表明的是这个指针指向的数据类型。
原文:https://www.cnblogs.com/bugxch/p/13833559.html