西邮Linux兴趣小组2017-2019纳新题题解

目录

  • 2017
  • 2018
  • 2019

2017

1. 分析下列程序的输出。

int main(int argc, char *argv[])
{
int t = 4;
printf("%lu\n", sizeof(t--));
printf("%lu\n", sizeof("ab c\nt\012\xa1*2"));
return 0;
}

输出:
4
11
sizeof()返回操作数占用内存空间的大小,int类型是4
字符串"ab c\nt\012\xa12"中一共11个字符,分别是:
‘a’, ‘b’ , ’ ’ , ‘c’ , ‘\n’ , ‘t’ , ‘\012’ , ‘\xa1’ , '
’ , ‘2’ 以及结尾的’\0’

2. 下面代码会输出什么?

int main(int argc, char *argv[])
{
int a = 10, b = 20, c = 30;
printf("%d %d\n", b = b*c, c = c*2) ;
printf("%d\n", printf("%d ", a+b+c));
return 0;
}

输出:
1200 60
1270 5
printf函数计算顺序由编译器具体实现,有可能是从右到左也有可能是从左到右。在gcc下是从右到左,所以先c=c2再b=bc,最后打印的时候还是从左到右。第二行首先打印a+b+c的值1270加上一个空格,printf函数返回一个int类型的数值,代表被输出的字符总数,在这里即5

3. 下面代码使用正确吗?若正确,请说明代码的作用;
若不正确,请指出错误并修改。

void get_str(char *ptr)
{
ptr = (char*)malloc(17);
strcpy(ptr, "Xiyou Linux Group");
}
int main(int argc, char *argv[])
{
char *str = NULL;
get_str(str);
printf("%s\n", str);
}

在函数中对形参进行修改是无效的,当程序运行到该函数时重新分配一块内存,这块内存出了函数会被自动释放掉,对这块内存上面的值做修改是没有用的,应该用二级指针对其进行操作。并且malloc函数的参数最好是size_t类型,17默认为int类型,并且malloc出来的空间忽略了字符串结尾的’\0’,申请的不够大会出现段错误。
应该改为:

void get_str(char **ptr) {
     *ptr = (char*)malloc((sizeof("Xiyou Linux Group"));
     strcpy(*ptr, "Xiyou Linux Group");
}
int main(int argc, char *argv[]) {
     char *str = NULL;
     get_str(&str);
     printf("%s\n", str);
}

4.请解释下面代码的输出结果。

size_t q(size_t b)
{
return b;
}
size_t (*p(char *str))(size_t a)
{
printf("%s\n", str);
return q;
}
int main(int argc, char *argv[])
{
char str[] = "XiyouLinuxGroup";
printf("%lu\n", p(str)(strlen(str)));
return 0;
}

输出:
XiyouLinuxGroup
15

由于()优先级比高,所以p先和()结合表示p是一个函数且形参类型为char,接着p(char*)与结合表示该函数返回值为指针,然后p(char*)和尾部的(size_t a)结合表示指向一个形参为size_t a的函数,最后前面的size_t表示返回值的这个函数的返回值为size_t(是不是很绕口)。
总结一下,size_t (*p(char *str))(size_t a)是一个返回值为指向返回值为size_t且形参为size_t a类型函数的函数指针的函数。
下面来讲p(str)(strlen(str)):
首先圆括号运算符结合方向为从左到右,p(str)表示调用p这个函数并传入
str,打印出XiyouLinux,好了现在返回一个函数名q,也就是相当于q(strlen(str)),那么就会再打印出15。

想在这再介绍一种方法,它就是:
typedef int (*pf)(int *, int);
这样pf xxx就相当于int (xxx)(int,int)
这样是不是很方便呢?

5.static 全 局 变 量 与 普 通 的 全 局 变 量 有 什 么 区 别?
解:
static全局变量只有本源代码的本文件能用,而普通全局变量只要其他文件extern一下,就可以在其他文件使用
static 局部变量和普通局部变量有什么区别?
解:
普通局部变量初始值为随机值,分配在栈区,生存期是该函数运行时间;
static局部变量为0,分配在静态区,生存期从定义到程序结束,只初始化一次
static函数与普通函数有什么区别?
解:
普通函数具有外部性,本源代码的其他文件可以调用(相当于extern过)。
而static过的函数只有所在文件可以调用

6. 下列程序分别输出的是数组中的第几个 0 ?

int main(int argc, char *argv[])
{
int a[][2] = {0, 0, 0, 0, 0, 0, 0, 0};
for(int i = 0; i <= 2; i++)
{
		
printf("%d\n", a[i][i]);
}
return 0;
}

第1,2,7个。
a[0][0]和a[1][1]都比较好理解,那为什么a[2][2]是第七个呢?
因为不管是几维数组,在存储时都是一维线性排列,因此a[2][1]后面是a[3][0]
, 也就是第七个。

7.const 关键字的作用是什么?下面的这几种定义有
区别吗?

const char *p;
char const *p;
char *const p;
const char *const p;

作用:防止变量被修改,定义常变量
前两种:可以改变p的指向但不能通过p修改值
第三种:可以通过p修改值不能改变p指向
最后一种:既不能通过p修改值也不能改变p的指向
区别点就是看const在星号的前面还是后面

8. 说说 #include<> 和 #include" " 有什么区别?为
什么需要使用 #include ?

用<>的话编译器就只找用于标准或系统提供的头文件,而""会先找用户自己的函数(从同一个工程文件)。如果我们确定文件是系统提供的就用<>,提高效率。

使用#include是为了引用本程序以外文件的函数或者宏定义。供本文件调用。

9. 说明下面程序的运行结果。

int main(int argc, char *argv[])
{
    int a, b = 2, c = 5;
    for(a = 1; a < 4; a++)
    {
        switch(a)
        {
            b = 99;
            case 2:
            printf("c is %d\n", c);
            break;
            default:
            printf("a is %d\n", a);
            case 1:
            printf("b is %d\n", b);
            break;
        }
    }
    return 0;
}

输出:
b is 2
c is 5
a is 3
b is 2
关键点是switch语句对比括号中的值和case后的值,跳转对应的分支,顺序执行下面的语句。所以b=99不会被执行,最后一次default的时候执行两次。

10. 下面的代码输出什么 ? 为什么 ?

int main(int argc, char *argv[])
{
unsigned int a = 10;
int b = -20;
if (a + b > 0)
{	
printf("a+b = %d\n", a+b);
}
else
{	
printf("a = %d b = %d\n", a, b);
}
return 0;
}

输出:
a+b = -10
原因是发生了隐式转换,算术运算中,低类型int转换为高类型unsigned int
因为无符号类型舍弃了符号位因此它能表示更大的整数,所以它也就是所谓的高类型。
10的补码是00000000 00000000 00000000 00001010
-20的补码是11111111 11111111 11111111 11101100
二者相加是一个很大的数字(4294967286)自然大于0
而下面以%d解释,计算机又对它进行求原码操作,得到的是-10

11. 以下程序运行结果是什么?

int main(int argc, char *argv[])
{
int nums[5] = {2, 4, 6, 8, 10};
int *ptr = (int *)(&nums+1);
printf("%d, %d\n", *(nums+1), *(ptr-1));
return 0;
}

输出:
4 10
num是指向num[1],基类型为sizeof(int)的指针,加一后指向num[2],再解引用,结果是4。&num+1跳过整个数组,相当于指向num[5],基类型为sizeof(num)的指针,接着(int*)强制转换为基类型为sizeof(int)的指针,减一后相当于&num[4],解引用就得到了10。

12. 对比下面程序在 Linux 和 Windows 上的输出结
果,并思考原因。

int main(int argc, char *argv[])
{
while(1)
{
		
fprintf(stdout, "Group ");
		
fprintf(stderr, "XiyouLinux");
		
getchar();
}
return 0;
}

Linux:每键入一个回车输出XiyouLinuxGroup
Windows:直接输出GroupXiyouLinux,键入回车后输出下一个
这涉及到两个系统下缓冲方式的不同,Windows中两个都默认无缓冲而Linux中stderr无缓冲,stdout行缓冲,Linux下当getchar()键入回车时,stdout才会刷新,输出Group而XiyouLinux可以直接输出

这是查到的资料

了解之后我们来实验一下,Linux系统下如果我们把它换成这样,情况是怎么样的呢?

int main(int argc, char *argv[])
{
    while(1)
    {
        fprintf(stdout,"Group");
        fprintf(stderr,"XiyouLinux");
		system("sleep 1s");
    
    return 0;
}

答案是一开始一直输出XiyouLinux,到后面stdout缓存区满的时候,Group一次性输出。

13.观察程序的运行结果,说明出现这种情况的原因。

int main(int argc,char *argv[])
{
    char str[512];
    for(int i=0; i < 512; ++i){
        str[i] = -1 - i;
    }
    printf("%lu\n",strlen(str));
    return 0;
}

输出:
255
计算机中运算以补码进行, -1 补码为1111 1111 ,,255 补码为1111 1111 ,二者相减为0000 0000,也就是0的补码, 所以在tr[255]上存的就是0,也就是’\0’的ASCII码值。

14. 请修改下面的 swap 函数,使得既可以交换 int 类型的参数,也可以交换 double 类型的参数。

    void swap(int *a, int *b)
    {
        int temp = *a;
        *a = *b;
        *b = temp;
    }

解:

#define swap(a, b)  ((x)=(x)+(y),(y)=(x)-(y),(x)=(x)-(y))

宏定义不对参数类型做检查,利用这一特性得到结果。

void*类型也可以容纳其他类型的指针,因此 另一种方法是多传入一个参数,用memcpy()实现:

void swap(void *a, void *b, size_t size)  
{  
    char buffer[size]; 
    memcpy(buffer, a, size); 
    memcpy(a, b, size);  
    memcpy(b, buffer, size);  
} 

15. 请说出 a 在不同平台上的值,并思考此种方式的
优点。

#ifdef __linux__
int a = 1;
#elif _WIN32
int a = 2;
#elif __APPLE__
int a = 3;
#else
int a = 4;
#endif

Linux: 1
Windows: 2
IOS: 3
其他: 4

好处是便于不同平台的移植,减少预编译后的代码长度

16. 请设计一个程序,通过命令行参数接收一个文件
名 filename.txt( 纯文本文件 ) 和一个整型数字 n,实
现从 filename.txt 中删除第 n 行数据。

请参考:删除文件指定行的十种方法及性能分析

后面几种讲实话我也看不懂emmm

17. 解释程序运行结果。

struct node
{
char a;
short b;
int c;
};
int main(int argc, char *argv[])
{
struct node s;
memset(&s, 0, sizeof(s));
s.a = 3;
s.b = 5;
s.c = 7;
struct node *pt = &s;
printf("%d\n", *(int*)pt);

printf("%lld\n", *(long long *)pt);
return 0;
}

输出:
327683
30065098755
首先是结构体字节对齐,请参考该链接
看完了之后就知道内存中各成员是这么放的:
[char] [0] [short] [short ]
[ int ] [ int] [ int ] [ int ]
又由于是小端模式,存起来就是|03|00|05|00|07|00|00|00|
左边低地址右边高地址
那么四字节读出来就是0x00050003
八字节就是0x0000000700050003
转化为相关的十进制就是上述值

18. 分析下面这段代码,说出最终输出结果。

#define NAME(n) x##n
#define PRINTVAL(y, ...) printf("x"#y":" __VA_ARGS__)
int main(int argc, char *argv[])
{
int NAME(1);
short *NAME(2) = ( short *)&NAME(1);
char *NAME(3) = (char *)&NAME(1);
NAME(1) = 0;
*NAME(2) = -1;
PRINTVAL(1, "%x\n", NAME(1));
PRINTVAL(2, "%x\n", *NAME(2));
PRINTVAL(3, "%x\n", *NAME(3));
return 0;
}

输出:
x1:ffff
x2:ffffffff
x3:ffffffff

##:链接参数
VA_ARGS_:可变宏,代替前面的…
gcc加上-E参数后得到的文本是:

int main(int argc, char *argv[])
{
 int x1;
 short *x2 = ( short *)&x1;
 char *x3 = (char *)&x1;
 x1 = 0;
 *x2 = -1;
 printf("x""1"":" "%x\n", x1);
 printf("x""2"":" "%x\n", *x2);
 printf("x""3"":" "%x\n", *x3);
}

C语言中两个连续的字符串被视作一个字符串,“x”“1"就是"x1”
-1(short来存)的补码是16个1,也就是ffff,前两个字节都放着ff,后两个都放着00,接着用int读的时候还是0x0000ffff,但是用short和char读时,由于是有符号类型,整型提升时自动变成0xffffffff,就出现了这个结果。

19.C 语言从源程序到可执行程序需要经过哪些步骤?
说说这些步骤都具体干了哪些工作。

1.预处理,生成.i的文件
2.将预处理后的文件转换成汇编语言,生成.s文件
3.汇编变为目标代码(机器代码)生成.o的文件
4.连接目标代码,生成可执行程序

2018

1. 分析以下代码段,并解释输出结果和原因。

int main(int argc, char *argv[])
{
	int nums[3][3] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	printf("%d\n", nums[1][-2] );
	printf("%d\n", (-1)[nums][5] );
	printf("%d\n", -1[nums][5] );
}

输出:
2
3
-9
这里有一个语法糖,(-1)[nums][5]相当于num[-1][5]
而-1[nums][5]却不一样,因为减法运算符优先级低,所以它相当于
-num[1][5]。接着运用数组是线性存储,得出结果

2. 分析以下代码段,给出输出结果,并给出自己的理解。

int main(int argc, char *argv[])
{
	int a[3][2] = { 2, 0, 1, 8 };
	char *str = (char *)malloc(sizeof(char) * 20);	
	strcpy(str, "\0101\\xb2");
	printf("%zu\n", sizeof(a));
	printf("%zu %d\n", sizeof(a[1][1] =0), a[1][1]);
	printf("%zu %zu\n", sizeof(str), strlen(str));
}

输出:
24
4 8
8 6
sizeof(a)的操作数是整个数组a,所以结果是3* 2 *4=24
sizeof运算符在编译时就得到结果,当我们求sizeof(a[1][1] = 0)大小时那个=0还没操作,实质求得是a[1][1],也就是4,8的话大家自己理解吧
str本质是指针,64位机器下是8字节,strcpy后,str上存着\010和1和\和x和b和2和’\0’,strlen一下就是6。

3. 参考所给代码,简要地谈一谈你对 static 关键字的理解。

static int a = 2018;
static void func(void)
{
	static int b;
	printf("a = %d, b = %d\n", a++, ++b);
}
int main(int argc, char *argv[])
{
	func( );
	func( );
	func( );
}

输出:
a = 2018, b = 1
a = 2019, b = 2
a = 2020, b = 3

static过的只初始化一次,每次调用的时候不会重新赋值,使用上次运行下来的值,因此它在内存中也是独此一份。

4.下面是一个 C 语言程序从源代码到形成可执行文件的过程,请解释图中的 ABCD 分别表示什么,在每个阶段分别完成了什么工作?

在这里插入图片描述 A.预处理,生成预编译文件(.文件):
gcc –E hello.c –o hello.i
B.编译,生成汇编代码(.s文件):
gcc –S hello.i –o hello.s
C.汇编,生成目标文件(.o文件):
gcc –c hello.s –o hello.o
D.链接,生成可执行文件:
gcc hello.o –o hello

5. 根据所给代码,说明 const 关键字的用法,指出标号为 (1)~(4) 的
代码哪些是错误的。

char y[ ] = "XiyouLinuxGroup",x[ ] = "2018";
char *const p1 = y;
const char *p2 = y;
/* (1) */ p1 = x;
/* (2) */ p2 = x;
/* (3) */ *p1 = 'x';
/* (4) */ *p2 = 'x';

参考2017.7得出答案:

错误:1和4
正确:2和3

6. 猜想下面程序的输出,并谈谈自己的理解。

int main(int argc, char *argv[])
{
	int a[5];
	printf("%p\n", a);
	printf("%p\n", a+1);
	printf("%p\n", &a);
	printf("%p\n", &a+1);
}

具体可以看一下我的另一篇博客:
戳这里!

7. 谈谈你对 main 函数的理解,可以从参数、返回值等角度分析。
以下内容来自百度百科(厚颜无耻)

程序执行总是从main函数开始,如果有有其他函数,则完成对其他函数的调用后再返回到主函数,最后由main函数结束整个程序。在执行程序时,由系统调用main函数 [1] 。main 函数是在程序启动中完成对具有静态存储期的非局部对象的初始化之后被调用的。它是程序在有宿主 (hosted)环境(亦即有操作系统)中所指定的入口点。自立程序(启动加载器,操作系统内核,等等)的入口点则是由实现定义的。
主函数的两个形参形式中的形参,允许从执行环境中传递任意的多字节字符串(它们通常被称为命令行参数),各个指针 argv[1] … argv[argc-1] 指向每个这些字符串的第一个字符。argv[0] 是指向一个表示用于执行该程序自身的名字的空结尾多字节字符串(或者当执行环境不支持时,为空字符串 “”)的开头字符的指针。这些字符串是可以改动的,虽然对它们的改动并不会被传回给执行环境:比如可以用 std::strtok 来使用它们。由 argv 所指向的数组的大小至少为 argc+1,其最后一个元素 argv[argc] 保证为一个空指针。

8. 分析以下函数,给出 f(2018) 的值,推测并验证函数的作用。

int f(unsigned int num)
{
	for (unsigned int i = 0; num; i++)
		num &= (num - 1);
	return i;
}

编译运行然后…‘i’ was not declared in this scope
emmm果断把i声明放for前面了,这里可能学长学姐不小心搞错了。

该函数的作用是:计算某个数值二进制表示时1的数量
推一下:
我们知道某个大于0的二进制数减一都是从后往前数第一个1变成0,然后这个1后面的0全部变成1(如果后面有数字),为啥?我们忽略这个1前面的数字
挑出来那个10…0(假设n个0),减一就变成01…1(n个1)。这两个数做&完了就变成0…0(n+1个0),跟原来相比这个1就没掉了。所以咯…

方便你我他:进制转换工具

9. 分析以下代码段,解释输出的结果。

int main(int argc, char *argv[])
{
	char n[] = { 1, 0, 0, 0 };
	printf("%d\n", *(int *)n);
}

输出:
1
用大小端的知识判断就知道是1啦
参考2017.17

10.分析下列代码段,解释输出的结果。

#define YEAR 2018
#define LEVELONE(x) "XiyouLinux "#x"\n"
#define LEVELTWO(x) LEVELONE(x)
#define MULTIPLY(x,y) x*y

int main(int argc,char *argv[])
{
    int x = MULTIPLY(1 + 2,3);
    printf("%d\n",x);
    printf(LEVELONE(YEAR));
    printf(LEVELTWO(YEAR));
    return 0;
}

输出:
7
XiyouLinux YEAR
XiyouLinux 2018

宏定义是简单的替换,#表示将其变为字符串,然后是宏展开顺序
第一步:首先用实参代替形参,将实参代入宏文本中
第二步:如果实参也是宏,则展开实参
第三步:最后继续处理宏替换后的宏文本,如果仍包含宏,则继续展开
注意:如果在第二步,实参代入宏文本后,实参之前或之后遇到#或##,实参不再展开
最关键的是第二步的理解,宏展开是先展开实参,简单来说就是先只管括号里面的东西,然后层层展开回去
LEVELTWO(YEAR)–>LEVELONE(YEAR)–>LEVELONE(2018)
而上一行的LEVELONE(YEAR)由于展开时前后有#存在,所以不再展开
详细了解请参考:
C语言中的宏展开

11. 以下代码段输出的两个值相等吗?为什么?

struct icd {
	int a;
    char b; 
    double c;
};
struct cdi { 
	char a; 
	double b; 
	int c; 
};
int main(int argc, char *argv[]) 
{ 
	printf("%zu %zu\n",sizeof(struct icd),sizeof(struct cdi)); 
}

输出:
16 24
还是可以参考2017.17中结构体字节对齐知识,看来这题还挺经典的

12. 在以下代码段执行完毕后,文件 Linux.txt 中的内容是什么?

int main(int argc, char *argv[])
{
	FILE *fp = fopen("Linux.txt", "wb");
	long long a = 0x78756e694c;
	fwrite(&a, sizeof(a), 1, fp);
	fclose(fp);
}

Linux^@ ^@ ^@
根据大小端是这么存的:
|4c|69|6e|75|75|00|00|00|
左边低地址右边高地址
他们分别是L i n u x '\0’这六个字符的ASCII码值
vim中空字符显示为^ @

13. 判断以下代码是否存在问题,如果有请找出并做适当的修改。

typedef struct a {
	char *name;
	int num;
} A;
void func(A *a)
{
	a = (A *)malloc(sizeof(A));
	strcpy(a->name, "XiyouLinuxGroup");
	a->num = 2018;
}
int main(int argc, char *argv[])
{
	A *a;
	func(a);
	printf("%s %d\n", a->name, a->num);
}

func函数修改a无效,并且name指针没有初始化,可能指向一块放着不能修改的东西,在这里strcpy是不被允许的。
建议改成这样:

typedef struct a {
	char *name;
	int num;
} A;
A* func()
{
	A *a = (A *)malloc(sizeof(A));
	a->name = "XiyouLinuxGroup";
	a->num = 2018;
	return a
}
int main(int argc, char *argv[])
{
	A *a;
	a = func();
	printf("%s %d\n", a->name, a->num);
}

或者用二级指针。

14.编码题
不使用任何函数,将字符串转化为整型数

int Convert(const char * str)
{
	int len = strlen(str);
	int result = 0;

	for (int i = 0; i < len; i++)
	{
		if (isdigit(str[i]) == 0)
			return 0;
		else
			result = result * 10 + str[i] - '0';
	}

	return result;
}

其实就是atoi()函数的简单实现

15. 编码题
输入一个整型数组,实现一个函数来调整该数组中数字的顺序,使
得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。

void sortnum(int *arr)
{
while(left<right)
  {
	while((left<right)&&(arr[left]%2 == 1))          
	{
		left ++;
	}
	while((left<right)&&(arr[right]%2 == 0))
	{
		right --;
	}
	if(left<right)   
	{
	tmp = arr[left];
	arr[left] = arr[right];
	arr[right] = tmp;
	}
  }
}

2019

1.下面代码段将打印出多少个‘=’?运用相关知识解释该输出。

int main(int argc, char *argv[]) 
{
for (unsigned int i = 3; i >= 0; i--)
putchar('=');
}

无数个(有本事你就证明我说的是不对的)因为无符号数本身就没有负数

2.下列三种交换整数的方式是如何实现交换的?

/*(1)*/ int c = a ; a = b ; b = c;
/*(2)*/ a = a - b ; b = b + a ; a = b -a ;
/*(3)*/ a ^ = b ; b ^ = a ; a ^ = b ;

1:中间值,通过c来传递a和b的值
2:数学运算
3:二进制操作(异或),因为二进制只有0和1,a^b其实就是那个中间值

3.有如下代码段所示的函数f,当我们执行该函数时,会产生什么样的输出结果?在同一程序中多次执行该函数,输出结果是否一致?

void f()
{
	static int a=0;
	int b=0;
	printf("%d,%d",++a,++b);
}

参考2018.3

4.下面程序段的输出是什么?请解释该现象并说出与之相关近可能多的知识;

int main(void)
{
	printf("%d\n",printf("Xiyou Linux Group2%d",printf("")));
}

输出:
Xiyou Linux Group2019
printf函数返回成功打印的字符数,printf("")返回0,
printf(“Xiyou Linux Group2%d”,printf(""))返回19

5.执行下面的代码段,会输出什么?请试着解释其原因,并叙述相关知识;

int main(int argc, char *argv[])
{
	char ch = 255;
	int d = a + 1;
	printf("%d %d",ch,d); 
}

a是什么呢…那么我们就将错就错讲一下ch打出来为什么是-1吧
255是1111 1111,赋值给ch后变成-1(-1补码是八个1)
%d输出时整型提升变成32个1,然后打出来还是-1

6.执行以下代码段,将产生什么样的输出?请对输出加以解释,并手动计算代码中t的值;

int main(int argc, char *argv[])
{
	char x=-2,y=3;
	char t=(++x)|(y++);
	printf("x=%d,y=%d,t=%d\n",x,y,t);
	t=(++x)||(y++);
	printf("x=%d,y=%d,t=%d\n",x,y,t);
}

输出:
x=-1,y=4,t=-1
x=0,y=5,t=1
这题主要考察位运算(对补码进行操作)
-1补码:1111 1111
3补码:不重要,因为是或运算,第一轮下来t直接是8个1
输出来就是-1
下面的||注意左边如果求出来是0那么右边就不用计算了,得到上述结果

7.下面代码段的输出结果是什么?输出该结果的原因是?

#define X a+b
int main()
{
	int a=1,b=1;
	printf("%d\n",X*X);
} 

输出:3
宏是没有感情的替换机器,替换完变成:
a+b*a+b

8.请解释下面代码段中每一句的效果。

int val = 2018;
int *pi = 2019;
 pi = &val;
*pi = 0;

1:定义int型变量并赋值为2018
2:定义int*类型指针并使之指向2019这个地址;
3:把val地址赋值给pi;
4:把0赋值给val

9.执行下列程序段,并输入“Xiyou Linux”,那么程序的输出结果是什么?请解释其原因;

int main()
{
	char *p=(char *)malloc(sizeof(char) * 20),*q=p;
	scanf("%s %s",p,q);
	printf("%s %s\n",p,q);
}

输出:
Linux Linux
指针p和q同时指向malloc出来的这块空间,输出Xiyou时这块空间上是Xiyou,再输入Linux把原来的Xiyou覆盖掉了,打印出来就是两个Linux了。

10.执行下面的程序段,每次执行的输出结果一致吗,整理并解释输出结果;

int main()
{
	int a[4]={2,0,1,9};
	printf("%p %p\n",a,&a);
	printf("%p %p\n",a+1,&a+1);
}

结果同2018.6
不一样,编译器分配内存时每不是固定的,下次运行未必和本次一致。

你可能感兴趣的:(西邮Linux兴趣小组2017-2019纳新题题解)