题目涉及部分内容:
- 结构体与结构体指针
- 指针,数组
- 宏定义与指针函数
- 函数
- 字符串数组
- 可变长参数函数
- 程序的输出是什么?
#include <stdio.h>
#include <setjmp.h>
#include <conio.h>
#include <stdlib.h>
int main(){
volatile int b = 3;
if(setjmp(buf) != 0){
printf("%d\n",b);
system("pause");
exit(0);
}
b = 5;
longjmp(buf,1);
system("pause");
return 0;
}
结果:5
该setjmp
函数存储“非本地goto
”的上下文信息,返回0
。该longjmp
函数将控制转移到已setjmp
初始化的调用buf
,并且从这一点继续执行,就好像setjmp
返回了1
。
【注意】:之后被修改的非易失性自动变量setjmp
变得不确定longjmp
。没有volatile
限定词,这个程序的行为将是不确定的。这个规则允许更好的代码优化。
- 程序的输出是什么?
int main(){
struct node {
int a;
int b;
int c;
}
struct node s = {3,5,6};
struct node *pt = &s;
printf("%d\n",*(int*)pt);
system("pause");
return 0;
}
结果:3
结构体成员按顺序排列在内存中。指针强制类型转换为其中某个成员的类型,即指向了结构体中的一个成员,提领之后为该结构体成员变量的值。
- 程序的输出是什么?
int main(){
int a[5] = {1,2,3,4,5};
int *ptr = (int*)(&a + 1);
printf("%d %d\n,*(a+1),*(ptr-1));
system("pause");
return 0;
}
结果:2 5
数组a
为拥有5
个元素的整型,对变量名加减隐式退化为对指针的操作,a+1
访问到了数组下标为1
的元素。
&a
就有成为了一个数组指针。因此&a + 1
产生的指针越过了一个5
个数组元素大小的数组,刚好跳过了a
数组。此时对此指向的ptr
指针进行强制类型转换,它现在的“步距”相当于一个数组成员,使ptr
减一指向正好回到了a
数组的最后一个元素。
【注意】:一般来说,不能使用非空指针的值不指向有效的对象。但是,指向数组末尾的指针是一个例外。这使ptr
合法的初始化,即使它不能被解除引用。
- 程序的输出是什么?
void foo(int [][3]);
int main(){
int a[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
foo(a);
printf("%d\n",a[2][1]);
system("pause");
return 0;
}
void foo(int b[][3]){
++b;
b[1][1] = 9;
}
结果:9
在中foo
,b有指向数组[3]
的类型指针int
,并在增量后指向数组a[1]()
。所以b[1]
有类型数组[3] int
,它表示数组a[2]()
。在值上下文中,b[1]“decay”
成一个指向a[2][0](7)
的指针,所以b[1][1]
表示a[2][1]
,其值从8
变为9
。
- 程序的输出是什么?
int main(){
int a,b,c,d;
a = 3;
b = 5;
c = a,b;
d = (a,b);
printf("c = %d ",c);
printf("d = %d\n",d);
system("pause");
return 0;
}
结果:c=3 d=5
逗号运算符(逗号表达式)评估两个操作数并生成第二个值。它的优先级低于赋值。因此c = a, b
相当于c = a
,而d = (a, b)
相当于d = b
。
- 程序的输出是什么?
#include <stdarg.h>
int ripple(int n,...){
int i,j,k;
va_list p;
k = 0;
j = 1;
va_start(p,n);
for(;j < n;++j){
i = va_arg(p,int);
for(;i;i &= i - 1){
++k;
}
}
va_end(p);
return k;
}
int main(){
printf("%d\n",ripple(3,5,7));
return 0;
}
结果:5
该va_arg
宏产生的“传递参数…”一个可变参数函数的一部分。在ripple
它将被调用两次,i
首先设置为5
,然后到7
。
表达式i &= i - 1
重置最右边的1
位i
。例如,如果i
是6
(二进制110
),i & i - 1
则是4
(二进制100
)。内部for
循环执行到i0
,所以k
增加了1
位的数量i
。
5
(二进制101
)和二进制111
(二进制)中有两个1
位,所以ripple
返回5
。
- 程序的输出是什么?
void f(char**);
int main(){
char *argv[] = {"ab", "cd", "ef"r "gh", "ij", "kl"};
f(argv);
return O;
}
void f (char **p){
char *t;
t =(p += sizeof (int)) [-1] ;
printf("%s\n", t) ;
}
结果:cd
在f
,p
最初指向指针数组中的第一个char*
("ab"
)argv
。添加sizeof(int)= 2
,p
使其指向第三个char*
("ef"
),之后p[-1]
表示第二个char*
("cd"
)。
temp
是什么类型?
typedef int(*test)(float *,float *);
test temp;
结果:指向函数的指针
(取两个指针float
参数并返回int
)
该typedef
声明为一个类型创建一个同义词,然后可以用它来声明该类型的对象。注意这个类型的新名字出现在一个变量名的位置上,好像你正在声明一个变量。与#define
指令的语法相比,这可以使其看起来倒退。
- 程序的输出是什么?
void e(int);
int main(){
int a = 3;
e(a);
putchar('\n');
return 0;
}
void e(int n){
if(n > 0){
e(--n);
printf("%d ",n);
e(--n);
}
}
结果:0 1 2 0
在伪代码中:
e(0), e(-1) -> {}
e(1) -> -> {{}, print 0, {}} ->
e(2) -> -> {, print 1, {}} ->
e(3) -> -> {, print 2, } ->
- 程序的输出是什么?
int main(){
int a[][3] = {1,2,3,4,5,6};
int (*ptr)[3] = a;
printf("%d %d ",(*ptr)[1],(*ptr)[2]);
++ptr;
printf("%d %d ",(*ptr)[1],(*ptr)[2]);
sysetm("pause");
return 0;
}
结果:2 3 5 6
a
有数组[3]
的类型,数组[2] int
,ptr
最初指向第一个数组[3]()
。增量后,它指向第二个数组[3]()
。当然,*ptr
表示ptr
正好指向的数组[3]
。