看微信里“程序猿”推荐文章--“
做错过的C语言题目”,很多不确定的,更有没见多的。 其他一些C语言易错题库:
语言的歧义,
C语言的谜题。
第一个宏应用:
var1 = var2
var2 = var1
第二个宏:
#include <stdio.h>
#define f(a,b) a##b
#define g(a) #a
#define h(a) g(a)
int main()
{
printf("%sn", h(f(1,2)));
printf("%sn", g(f(1,2)));
return 0;
}
宏定义替换的次序:如果该宏为带#号的宏定义,则直接替换字符串,无需再嵌套替换,如果该宏不是带#的宏,则先替换括号内部的宏定义,然后替换外部的。
结果:12和f(1,2)
第三个宏:定义一个宏,求一个结构体struct中某个变量相对于struct的偏移量
#define OFFSET(struc, member) ((unsigned int)&((struc *)0)->member)
(struc*)0 //表示将常量0强制转化为struc *型指针所指向的地址,
((struc*)0)- >e 表示在0地址处的结构体struc的成员e
&(((struc*)0)- >e)//表示取结构体指针(struc*)0的成员e的地址, 因为该结构体的首地址为0,所以其实就是得到了成员e距离结构体首地址的偏移量.
指针题:
定义一个指针如int *p; 要记住说p指向了一个int型存储空间, 指的是 p保存的是该存储空间的地址,*p的操作是指将取p保存地址的值;
#incude <stdio.h>
void main()
{
int a[5]={1,2,3,4,5};
int *ptr=(int *)(&a+1);
printf("%d,%d",*(a+1),*(ptr-1));
}
a表示第一个元素的地址,&a表示数组结构的地址。ptr指向的是整个a数组后的第一个存储空间,所以ptr-1表示的是a数组到最后一个元素的地址。
结果 2,5
假如我们的a的地址是:0Xbfe2e100, 而且是32位机,那么这个程序会输出什么
#include <stdio.h>
int main()
{
int a[5];
printf("%xn", a);
printf("%xn", a+1);
printf("%xn", &a);
printf("%xn", &a+1);
return 0;
}
结果:0Xbfe2e100,0Xbfe2e104,0Xbfe2e100,0Xbfe2e114
每一个字节对应一个地址,而不是每个比特对应一个地址
char str1[] = "abc";
char str2[] = "abc";
const char str3[] = "abc";
const char str4[] = "abc";
const char *str5 = "abc";
const char *str6 = "abc";
char *str7 = "abc";
char *str8 = "abc";
cout << ( str1 == str2 ) << endl;
cout << ( str3 == str4 ) << endl;
cout << ( str5 == str6 ) << endl;
cout << ( str7 == str8 ) << endl;
答:0 0 1 1。
析:虽然都是常量,但是数组有空间,指针没空间。str1和str2都是单独开启一个空间存储“abc”串,但str5和str6保存的都是串“abc”的地址,所以 str5 == str6
不同类型的变量在一块运行的转化原则:有符号要向无符号的方向转化
编译器解析关键字是从左向右的,尽量包含更多的字符组成关键字
typedef union {long i; int k[5]; char c;} DATE;
struct data { int cat; DATE cow; double dog;} too;
DATE max;
printf("%d",sizeof(struct date)+sizeof(max));
答:32系统为52,64位系统64
32位和64位系统中基本数据字节长度(另一篇文章有)和存储对齐。 共用体的大小按最长变量算,结构的大小是各变量长的总和。 32位系统默认是4字节也就是32位对齐,不足则补齐,64位系统默认是8字节。
32位系统中,DATE的大小是按int k[5]的20字节,正好对齐,too的大小是4+20+8,所以总和是52;
64位系统中,DATE的大小同样按int k[5]的20字节,但还要8字节对齐,所以另外添4字节,too结构体中每个变量都要按8字节对齐,所以是8+24+8=40,总和64.
#include <stdio.h>
int main()
{
int i = 1;
sizeof(i++);
printf("%dn", i);
return 0;
}
答:1
分析:正因为 sizeof是编译期求值的,所以如果它跟着表达式,那么表达式是不会在运行时计算的,只是根本表达式的类型得到它占用的空间。
第一个宏应用:
#include <stdio.h>
#define STRCPY(a, b) strcpy(a ## _p, #b)
int main()
{
char var1_p[20];
char var2_p[30];
strcpy(var1_p, "aaaa";
strcpy(var2_p, "bbbb";
STRCPY(var1, var2);
STRCPY(var2, var1);
printf("var1 = %s/n", var1_p);
printf("var2 = %s/n", var2_p);
return 0;
}
宏中 #把宏参数变为一个字符串,用##把两个宏参数贴合在一起,均在预处理时就完成字符串的替换。所以STRCPY(var1, var2); 编译好后是strcpy(var1_p, "var2");
所以结果是var1 = var2
var2 = var1
第二个宏:
#include <stdio.h>
#define f(a,b) a##b
#define g(a) #a
#define h(a) g(a)
int main()
{
printf("%sn", h(f(1,2)));
printf("%sn", g(f(1,2)));
return 0;
}
宏定义替换的次序:如果该宏为带#号的宏定义,则直接替换字符串,无需再嵌套替换,如果该宏不是带#的宏,则先替换括号内部的宏定义,然后替换外部的。
结果:12和f(1,2)
第三个宏:定义一个宏,求一个结构体struct中某个变量相对于struct的偏移量
#define OFFSET(struc, member) ((unsigned int)&((struc *)0)->member)
(struc*)0 //表示将常量0强制转化为struc *型指针所指向的地址,
((struc*)0)- >e 表示在0地址处的结构体struc的成员e
&(((struc*)0)- >e)//表示取结构体指针(struc*)0的成员e的地址, 因为该结构体的首地址为0,所以其实就是得到了成员e距离结构体首地址的偏移量.
指针题:
定义一个指针如int *p; 要记住说p指向了一个int型存储空间, 指的是 p保存的是该存储空间的地址,*p的操作是指将取p保存地址的值;
#incude <stdio.h>
void main()
{
int a[5]={1,2,3,4,5};
int *ptr=(int *)(&a+1);
printf("%d,%d",*(a+1),*(ptr-1));
}
a表示第一个元素的地址,&a表示数组结构的地址。ptr指向的是整个a数组后的第一个存储空间,所以ptr-1表示的是a数组到最后一个元素的地址。
结果 2,5
假如我们的a的地址是:0Xbfe2e100, 而且是32位机,那么这个程序会输出什么
#include <stdio.h>
int main()
{
int a[5];
printf("%xn", a);
printf("%xn", a+1);
printf("%xn", &a);
printf("%xn", &a+1);
return 0;
}
结果:0Xbfe2e100,0Xbfe2e104,0Xbfe2e100,0Xbfe2e114
每一个字节对应一个地址,而不是每个比特对应一个地址
char str1[] = "abc";
char str2[] = "abc";
const char str3[] = "abc";
const char str4[] = "abc";
const char *str5 = "abc";
const char *str6 = "abc";
char *str7 = "abc";
char *str8 = "abc";
cout << ( str1 == str2 ) << endl;
cout << ( str3 == str4 ) << endl;
cout << ( str5 == str6 ) << endl;
cout << ( str7 == str8 ) << endl;
答:0 0 1 1。
析:虽然都是常量,但是数组有空间,指针没空间。str1和str2都是单独开启一个空间存储“abc”串,但str5和str6保存的都是串“abc”的地址,所以 str5 == str6
不同类型的变量在一块运行的转化原则:有符号要向无符号的方向转化
编译器解析关键字是从左向右的,尽量包含更多的字符组成关键字
typedef union {long i; int k[5]; char c;} DATE;
struct data { int cat; DATE cow; double dog;} too;
DATE max;
printf("%d",sizeof(struct date)+sizeof(max));
答:32系统为52,64位系统64
32位和64位系统中基本数据字节长度(另一篇文章有)和存储对齐。 共用体的大小按最长变量算,结构的大小是各变量长的总和。 32位系统默认是4字节也就是32位对齐,不足则补齐,64位系统默认是8字节。
32位系统中,DATE的大小是按int k[5]的20字节,正好对齐,too的大小是4+20+8,所以总和是52;
64位系统中,DATE的大小同样按int k[5]的20字节,但还要8字节对齐,所以另外添4字节,too结构体中每个变量都要按8字节对齐,所以是8+24+8=40,总和64.
#include <stdio.h>
int main()
{
int i = 1;
sizeof(i++);
printf("%dn", i);
return 0;
}
答:1
分析:正因为 sizeof是编译期求值的,所以如果它跟着表达式,那么表达式是不会在运行时计算的,只是根本表达式的类型得到它占用的空间。