C++常见难点笔试面试题
跨行加⭐⭐⭐⭐⭐
main()
{
//例子[1]
int a[5]={1,2,3,4,5};
int *ptr=(int *)(&a+1);//&a相当于变成了行指针,加1则变成了下一行首地址
printf("%d,%d,%d",*(a+1),*(ptr-1));
//例子[2]
int * ptr1 = (int *)( (int)a + 1);
int * ptr2 = (int *)( (int)a + 4);
printf("%d,%d\n", ptr[-1],*ptr2);
}
例子一
1. *(a+1)就是a[1],执行结果是2
因为a是int*类型,a+1步长为4
2.*(ptr-1)就是a[4],结果为5
首先我们得到的是&a的地址,而&a是一个含有5个int类型的数组,所以&a+1的步长就是a数组整个的大小,加到a数组的末尾后面,
(int *)(&a+1)这一句话,把它转换成int *类型的指针,步长又为4了,后面给它-1,即*(ptr-1) 相当于减了一个int* 的步长,结果为5
例子二
首先看里面的语句 (int)a + 1 、(int)a + 4
这个意思是我们把a的地址得到,然后把a的地址+1和+4,
那么ptr1肯定是一个乱的值,因为取的是不对的地址
而ptr2得到的是数组第二个元素的地址,再转换成(int *)类型
这样我们又可以进行后续的+-操作进行指针的引用了。
如何写出可重入的函数?⭐⭐⭐⭐⭐
满足下列条件的函数多数是不可重入的:也可以这样理解,重入即表示重复进入,首先它意味着这个函数可以被中断,其次意味着它除了使用自己栈上的变量以外不依赖于任何环境(包括 static),这样的函数就是purecode(纯代码)可重入,可以允许有该函数的多个副本在运行,由于它们使用的是分离的栈,所以不会互相干扰。如果确实需要访问全局变量(包括 static),一定要注意实施互斥手段。可重入函数在并行运行环境中非常重要,但是一般要为访问全局变量付出一些性能代价。
(1)函数体内使用了静态的数据结构;
(2)函数体内调用了malloc()或者free()函数;
(3)函数体内调用了标准I/O函数。
pragma pack(n)的作用
总长度可以被n整除,成员变量对其位置可以被min(n,自身大小)整除
#pragma pack(1)
struct node {
char f;
double e;
short a;
};
sizeof是1+8+2=11
#pragma pack(4)
struct node {
char f;
double e;
short a;
};
sizeof是16
struct node {
char f;
double e;
short a;
};
sizeof是24
中断是嵌入式系统中重要的组成部分
中断是嵌入式系统中重要的组成部分,这导致了很多编译开发商提供一种扩展—让标准C支持中断。
具代表性的是,产生了一个新的关键字__interrupt。下面的代码就使用了__interrupt关键字去定义了一个中断服务子程序(ISR),请评论一下这段代码的。
__interrupt void compute_area (void)
{
double area = PI * radius * radius;
printf(" Area = %f", area);
return area;
}
ISR不可能有参数和返回值的!
ISR尽量不要使用浮点数处理程序,浮点数的处理程序一般来说是不可重入的,而且是消耗大量CPU时间的!!
printf函数一般也是不可重入的,UART属于低速设备,printf函数同样面临大量消耗CPU时间的问题!
typedef 和#define
typedef 在C语言中频繁用以声明一个已经存在的数据类型的同义字。也可以用预处理器做类似的事。
例如,思考一下下面的例子:
#define dPS struct s *
typedef struct s * tPS;
以上两种情况的意图都是要定义dPS 和 tPS 作为一个指向结构s指针。哪种方法更好呢?(如果有的话)为什么?
这是一个非常微妙的问题,任何人答对这个问题(正当的原因)是应当被恭喜的。答案是:typedef更好。思考下面的例子:
dPS p1,p2;
tPS p3,p4;
第一个扩展为
struct s * p1, p2;
上面的代码定义p1为一个指向结构的指,p2为一个实际的结构,这也许不是你想要的。第二个例子正确地定义了p3 和p4 两个指针。
RAM和ROM
ROM是只读存储器,掉电不丢失
RAM是读写存储器,掉电丢失
SRAM:CPU的缓存就是SRAM,静态的随机存取存储器,加电情况下,不需要刷新,数据不会丢失
DRAM,动态随机存取存储器最为常见的系统内存,需要不断刷新,才能保存数据
关键字static的作用是什么
static用来修饰一个局部的变量的时候,
生命域是全局的
作用域是局部的
static用来修饰一个模块内的(某一个C的源程序文件)全局变量的时候
生命域不变
作用域减小,只在本模块内有效
static用来修饰一个函数的时候
作用域减小,只在本模块内有效
void GetMemory(char *p)
{
p = (char *)malloc(100);
}
void Test(void)
{
char *str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}
请问运行Test函数会有什么样的结果?
答:程序崩溃。因为GetMemory并不能传递动态内存,Test函数中的 str一直都是 NULL。strcpy(str, "hello world");将使程序崩溃。
char *GetMemory(void)
{
char p[] = "hello world";
return p;
}
void Test(void)
{
char *str = NULL;
str = GetMemory();
printf(str);
}
请问运行Test函数会有什么样的结果?
答:可能是乱码。因为GetMemory返回的是指向“栈内存”的指针,该指针的地址不是 NULL,
但其原现的内容已经被清除,新内容不可知。