2020西邮LINUX小组纳新题分析

2.第二题考察宏定义

#define A 2 + 2
#define B 3 + 3
#define C A * B
int main(int argc, char *argv[])
{
printf("%d\n", C);
return 0;
}

C=A*B;此时,C=2+2*3+3=11,而不是4*6

如果在宏定义中给A,B加上括号,则会是另一种结果。

此处还可以去了解#和##在宏中的使用。

#用来将宏参数转换为字符串,也就是在宏参数的开头和末尾添加引号。

##称为连接符,用来将宏参数或其他的串连接起来。

6.考察对字符串指针和字符数组的理解。

int main(int argc, char *argv[])
{
char *str = "Xiyou Linux Group";
printf("%c\n", *str + 1);
return 0;
}

 字符串中的所有字符在内存中是连续排列的,str 指向的是字符串的第 0 个字符;我们通常将第 0  个字符的地址称为字符串的首地址。字符串中每个字符的类型都是char,所以 str 的类型也必须是char *

*str + 1=(*str )+ 1,*优先级大于+;此时取了X,对其加一。

*(str + 1)=首地址加1再取值(str[1]),因此两次输出不同。

为了加深的理解,请继续阅读下面的代码:

#include <stdio.h>
#include <stdlib.h>

int main(){
    char str[20] = {0};
    int i;

    for(i=0; i<10; i++){
        *(str+i) = 97+i;  // 97为字符a的ASCII码值
    }
   
    printf("%s\n", str);
    printf("%s\n", str+2);
    printf("%c\n", str[2]);
    printf("%c\n", (str+2)[2]);
   
    return 0;
}

 运行结果:

abcdefghij
cdefghij
c
e

前面三个 printf() 比较容易理解,str+2 表示指向第 2 个元素,(str+2)[2] 相当于 *(str+2+2),也就是取得第 4 个元素的值。

我们对字符串指针和字符数组进行拓展:

它们都可以使用%s输出整个字符串,都可以使用*[ ]获取单个字符,这两种表示字符串的方式是不是就没有区别了呢?

有!它们最根本的区别是在内存中的存储区域不一样,字符数组存储在全局数据区或栈区,第二种形式的字符串存储在常量区。全局数据区和栈区的字符串(也包括其他数据)有读取和写入的权限,而常量区的字符串(也包括其他数据)只有读取权限,没有写入权限。

10.

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

 结果是1,这个题本身没什么意义,无非是一个强制转化,我们看下面的代码加深理解。

void print(void *x)   /* Pointer Received as void - integer *a=300/ 
{ 
	char e= *(char *)x;  // e=','   Ascii Equivalent of 4 (256+44)  
	int b= *(int *)x;    // b= 300 
	printf("%c \n",e);   // ',' 
 	printf("%d",b);      //300 
} 

11.这个题就是对字符串指针和字符数组的考察

int main(int argc, char *argv[])
{
/*const*/ char a[] = "XiyouLinux\0";
char *b = "XiyouLinux\0";
a[5] = '\0';
// b[5] = '\0';
printf("%s\n", a);
// printf("%s\n",b);
return 0;
}

 在C语言中,字符串总是以'\0'作为结尾,所以'\0'也被称为字符串结束标志,或者字符串结束符。

printf() 输出字符串时,会从第 0 个元素开始往后检索,直到遇见'\0'才停止,然后把'\0'前面的字符全部输出,这就是 printf() 输出字符串的原理。

12.一个C源文件到可执行文件

  1. 1).预处理,产生.ii文件
  2. 2).编译,产生汇编文件(.s文件)
  3. 3).汇编,产生目标文件(.o或.obj文件)
  4. 4).链接,产生可执行文件(.out或.exe文件)

预处理
gcc -E hello.c -o hello.i

  1. 头文件展开 —不检查语法错误,可以展开任意文件
  2. 宏定义—将宏名替换为宏值,不检查语法错误
  3. 替换注释—变成空行
  4. 展开条件编译—根据条件来展开指令

编译
gcc -S hello.i -o hello.s

  1. 将c程序翻译为汇编指令
  2. 逐行检查语法错误–整个编译4步中最耗时间的过程

汇编
gcc -c hello.s -o hello.o

  1. 将汇编指令翻译成对应的二进制编码

链接
gcc hello.o -o hello.exe

  1. 数据段合并
  2. 数据地址回填
  3. 库引入

 c语言:源文件从文本到可执行文件经历的过程_MARSHCW的博客-优快云博客

13.这是一个冒泡排序

void sort(int arr[], int size)
{
int i, j, tmp;
for (i = 0; i < size - 1; i++)
{
for (j = 0; j < size - i - 1; j++)
{
if (arr[j] > arr[j + 1])
{
tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
}

 若在某一趟排序中未发现气泡位置的交换,则说明待排序的无序区中所有气泡均满足轻者在上,重者在下的原则,因此,冒泡排序过程可在此趟排序后终止。为此,在下面给出的算法中,引入一个标签flag,在每趟排序开始前,先将其置为0。若排序过程中发生了交换,则将其置为1。各趟排序结束时检查flag,若未曾发生过交换则终止算法,不再进行下一趟排序。

原文链接:https://blog.youkuaiyun.com/yanxiaolx/article/details/51622286

//冒泡排序优化2
void BubbleSort3(int* arr, size_t size)
{
	assert(arr);
	int i = 0, j = 0;
	int k = size - 1,pos = 0;//pos变量用来标记循环里最后一次交换的位置  
	
	for (i = 0; i < size - 1; i++)//一共要排序size-1次
	{
		//每次遍历标志位都要先置为0,才能判断后面的元素是否发生了交换
		int flag = 0;
 
		for (j = 0; j <k; j++)//选出该趟排序的最大值往后移动
		{
			if (arr[j] > arr[j + 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
				flag = 1;//只要有发生了交换,flag就置为1
				pos = j;//循环里最后一次交换的位置 j赋给pos
			}
		}
 
		k = pos;
		//判断标志位是否为0,如果为0,说明后面的元素已经有序,就直接return
		if (flag == 0)
		{
			return;
		}
	}
 
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值