多少位编译器,表示一个指针占据多少位
16位 int 2个字节
2^10 =1024
转义字符
c语言
0、符号优先级
结合方向,+=、=结合方向是从右到左
a+=1,等价于a=a+1,先计算出右边a+1的值,然后赋给左边,这就叫做从右向左结合
1、print函数
printf
(
"s[]=%6.9s\n", s); 表示输出的时候不少于6位,但不超过9位字符
2、逗号表达式
2、
(a = 5, b = 2, a > b ? a++ : b++, a + b) 逗号表达式计算的是最后一个逗号的结果
sizeof 与strlen
sizeof 是计算字节包括字符串的\0,strlen不包括
3、printf(输出)与scanf(输入)的区别
printf("%3.2f\n", i);//3是输出宽度,2是保留的小数点数(这就是精度)
scanf 只能控制宽度不能控制精度
scanf("%d%d", &i, &j);
scanf("%d", &i);
输入两个要区分两个输入,1上面限制条件 2、输入到时候两个数字之间加上ent 或者空格,输完使用end结束
4、数组
数组的长度可以是变量
5、c++相关字节大小
空类的字节是1个字节、
函数的字节是一个
虚函数存在的话是4(32位,64位是8字节)
sizeof(void*)4字节sizeof(void)错误或者1字节
static 不属于类成员,是类对象共享 0 字节
virtual 4字节(32位)
6、二维数组
对于二维数组啊a[3][4],a[0]和a都表示首元素地址,
a[0]是a[0][0]的地址,
a[1]表示第二行首元素的地址、a[2]表示第三行手元素地址,a[1] +1,表示第二行开始跳过一个元素的地址
a:第0行的地址;a+i:第i行的地址 *(a+i):第i行0列地址 *(a+i)+j 表示&a[i][j]
&a表示数组的地址,&a +1 表示跳过整个二维数组,此处跳过12个int的大小
7、指针+变量的地址计算
设有指针变量为 double *p,则在32位机器上p+1是将指针p的指向向后移动8个字节(增加的是double大小)
8、参数传递的时候改变值
改变非指针的值,需要一重指针,改变一重指针的值,需要传入二级指针
9、异或
ans ^= i % 3这是异或 1
参与运算的两个值,如果两个相应位相同,则结果为0,否则为1。即:0^0=0, 1^0=1, 0^1=1, 1^1=0
10、字符常量与字符串改变,常量指针
8、字符常量可以改变,可以参加数值运算,参加整数运算时根据ASCll码转换成int值运算
字符串常量不能修改,要改变字符串,需要使用字符串形式而不是使用字符串常量
const char *str_const = "Hello, World!";字符串常量,指针是一个指针常量不能改变指针指向
后面str_const [0] =1 错误,不能使用常量指针赋值
const char *str = "Hello"; str[0] = 'h'; // 非法:尝试修改字符串常量的内容
// 字符串 char str[] = "Hello, World!";
指针常量:指向地址不能改变,数组名: char *s =string s指向字符串首地址不能改变
字符串指针与字符数组
char* s = "string"
const char* p="abcdef"
字符串存放在静态区,字符串指针是一个常量指针,不能修改其指向内容
char chr[]="abc";
char chr1[]={"abc"};
char chr2[]={'a','b','c','\0'};
,数组名本身是常量指针(数组名是一个常量不能改变),arr[0] = 'S'; // 将第一个字符改为大写 'S'
合法
11、ASCll码
9、ascll码值
a:97 b:98
A:65
12、
10、输出字符地址或是字符值
13、执行与编译
内存分配是在程序执行的过程这个实现,编译只是对代码进行翻译
14、NULL 地址
空地址指的是地址为0的空间
15、%x格式
13、
printf (
"x = %x"
, i);
输出的是16进制
16、print函数
14、//用printf输出的话,
//如果是用 %d 的话,符号这个["",]后面要写 值 ;=>一个整数=>一个就是值
//如果是用 %c 的话,符号这个["",]后面要写值;=>一个字符整数=>一个就是值
//如果是用 %s 的话,符号这个["",]后面要写地址=>一串字符串=>一串就是地址((地址,地址的值)
printf (
"x = %x"
, i);
输出的是16进制
count 输入地址的话,也会打印出值
17、strcpy函数与strcat、memcpy
字符拼接
char *strcat(char *dest, const char *src);
.strcat(p,r)表示p字符串后面拼接r字符串。
strcat 将两个值拷贝
字符覆盖char * strcpy ( char * destination, const char * source );
strcpy(q,b) 将b内容拷贝给q,地址拷贝,只能复制字符串strcpy在使用中赋值是将所有的字符串均复制过去,strcpy(p+2,q),p+2表示p中字符保留2个数。
void *memcpy(void *dest, const void *src, size_t n);
memcpy 可以复制任何的内容,字符数组、整型、结构体等
memcpy(a+2,b,sizeof(b)) 表示b中的字符从a数组第三个开始覆盖memcpy(a,b,sizeof(b)) 表示b中的字符从a数组第一个开始覆盖
18、含有结构体的成员变量的结构体对齐
注意A中的最大结构体是内部的int变量,而不是整个16字节结构体,我们看的是内置类型
题目说的几字节对齐说的是
19、关于fopen
fopen()文件顺利打开后,返回指向该流的文件指针,如果文件打开失败,则返回NULL,并将错误代码存储在errno中。 fclose()成功关闭可返回0,错误返回EOF并把错误存储在errno中
20、static
全局变量在所有源文件升效
静态全局变量只能在当前源文件生效
静态函数变量只能在当前源文件生效
static int 定义只执行一次
21、a[]与a的写法
19、关于数组的形参与实参
形参一般写a[],相当于指针,数组里面的参数没有意义,可以不写
实参一般是a,相当于指针
20、数组名是一个地址常量
22、自动推导类型
decltype和auto都可以用来推断类型,但是二者有几处明显的差异:
23、函数指针数组
int (*s[10])(int)
右边的int是代表了返回值类型
(*s[i])表示这是一个指针数组
24、c++的一些知识
C++中没有限定private、public、protected的书写次序数据成员类型不可以是register,
25、对于一个表达式来说,只对决定整个表达式值所需的最少数组的子表达式进行运算
z=(x||(y-=x)” 因为x已经决定了最终的结果,所以右边的不会执行
26、函数定义的参数格式
double fun(int, int),只要写数据类型就可以,后面的变量可有可无
27、strlen
strlen() 查找到“\0”就结束
strlen("\n\0") = 1
\a 、\\ 、\0这种算一个字符
28、c++中可以使用函数嵌套调用但是不能再定义的时候嵌套
29、静态成员函数
静态成员函数没有this指针,需要通过类参数访问成员对象
30、字符的赋值
需要加上'q',,直接加上q会转成ASCLL值进行计算
31、地址指向NULL
指针本身本来就不是存储单元,只是指向存储单元的地址,地址为空,只是没有指向有意义的内存,指向了0x00000000~0x0000ffff这段无意义的内存
这个时候不能直直接对这个区域赋值,要先将指针指向有意义的地方,才能通过指针给空间赋值
32、switch语句
defalut是没有任何case匹配·的是时候才能去执行的,
要是没遇到break,就会向下执行到break
switch()括号中的是整形也就是int,字符型
switch (expression) {
case constant1:
// 当 expression 等于 constant1 时执行的代码
break;
case constant2:
// 当 expression 等于 constant2 时执行的代码
break;
// ...
case constantN:
// 当 expression 等于 constantN 时执行的代码
break;
default:
// 当 expression 不等于任何 constant 时执行的代码
}
33、字符常量
1、‘a’ 单个字符
2、转义字符 ‘\032’
34、数组名与指针的长度(64位操作系统)
str[] =
"Hello" sizeof(str) 6
指针长度 8
void
func(
char
str_arg[
100
]){
cout << sizeof(str_arg) << endl;
这里的长度是形参长度是形参的长度是指针,长度是8
35、数组名是常量不可以修改
36、空定义
#define S345:
37、
将字符串赋值给指针的意思是指针指向这个字符串
w < x ? w : y < z ? y : z == w<x?w:(y<z?y:z)
*++c = *(++c)
38、链表
节点想要与下一个节点相连接,需要将自己的地址存放到下一个节点的空间中
指针是一个地址,指针指向地址代表的空间
39、联合体unio
在任意时刻,union中只能有一个数据成员可以有值。当给联合中某个成员赋值之后,该联合中的其它成员就变成未定义状态了;
联合体是共有一块物理内存,不是共有一个值
40、指针移动的使用友\n
41、内联函数
1、内联函数不能太复杂,不然编译器就会视为普通函数
2、内联函数不能声明可能抛出的异常
42、优先级问题
== 优先级大于 =
三目运算符是从后面开始
43、宏定义函数
#define MOVE(a,b) \
{ \
int a_target = (a) & 0xFFF;\
int b_target = (b) & ~(0xFFF << 3);\
(b) = (b_target) | (a_target << 3);\
}
44、位运算的应用
清零与保存我们想要的位
保留我们想要的位 a & 1 = a
清零我们想要的位 a & 0 = 0
45、优先级
++的优先级比*高
46、getchar 函数
getchar():从键盘中获取一个字符
不管你输入字符串有多长,每次只能获取一个字符型变量;\n 也会被获得
47 /n 与\r
\r 回车 本行开头
\n 换行
48、c语言文件打开
rr(read):读
w(write):写
a(append):追加
b(banary):二进制文件
+:读和写
49、strcpy与strcat
strcpy 将/0一起赋给
strcat 插在后面
50、c语言优先级
51、不能重载的运算符
类属关系运算符"."、
成员指针运算符".*"、作用域运算符"::"、sizeof运算符和三目运算符"?:
52、scanf键盘输入问题
空格 ENT不会读取
53、文件读取
54、memcpy与strcpy拷贝函数,strcat
strncpy(str1,str2,2);作用是将str2中最前面2个字符复制到str1中,取代str1中原有的最前面2个字符。
// 字符串拼接
int src[] = {1, 2, 3, 4, 5};int dest[5]; memcpy(dest, src, sizeof(src))
dest[] = {1,2,3,4,5}
strcat(dest, src); // 将src追加到dest后面
55、*p++与*++p
一般来说单目运算符都是从右往左的,但是当++在变量左边的时候,++变成最低优先级
56、合法的标识符、字符常量、字符串常量
1、合法标识符
- 标识符只能由字母,数字和下划线组成。
- 标识符不能以数字开头。
2、合发常量:
十进制 :10
八进制 :017(以0开头,不能出现8,9)
十六进制:0xA1(以0x开头3、合法字符、字符串常量
57、语言中的指针和p, p+1, *(p+1), *P+1, &p[0] 的含义
p 指针
p +1 这将导致 p 指向下一个相邻的内存位置
*(p+1) 这是一个解引用操作,它将指针 p 增加一个单位后的地址处的值取出
*p +1 首先解引用指针 p,然后将结果加一&p[0] 这是取地址操作,它返回指针 p 指向的内存位置的地址。
58、type 重新命名符号类型,define
后面加上_t 表示都是重新定义的
typedef signed char int8_t;
typedef short int int16_t;
typedef int int32_t;
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
typedef struct NUM { int a; int b; }DATA,*PTRDATA;
DATA等同于struct NUM
*PTRDATA 等同于指向struct Num的指针
59、#if...#endif的用法总结参考
#ifdef 标识符
程序段1
#else
程序段2
#endif
如果标识符被定义了,执行程序1,否则执行程序段2
- `#if`格式:
- 当`#if`后面的表达式为真时,编译`#if`与`#elif`之间的代码段;
- 如果表达式不成立,则编译`#elif`与`#else`之间的代码段;
- 如果所有条件都不成立,则编译`#else`与`#endif`之间的代码段。
- `#else`和`#endif`部分是可选的。3
`#ifdef`格式:
- 如果宏标识符已经被定义,则编译`#ifdef`与`#else`之间的代码段;
- 如果宏未被定义,则编译`#else`与`#endif`之间的代码段。
`#ifndef`格式:
- 如果宏标识符未被定义,则编译`#ifndef`与`#else`之间的代码段;
- 如果宏已经被定义,则编译`#else`与`#endif`之间的代码段。
例如,如果宏`MAX`被定义,则代码会在`#elif`条件成立时被编译。条件编译结束后,通常需要在最后添加`#endif`以确保语法正确
#if 表达式
程序段1
#else
程序段2
#endif
如果表达式为真,执行程序段1,否则程序段2
define
#定义 标识符 内容
#define name stuff
#define MAX 100
MAX就表示100
由于预先对标识符进行了定义,在程序的预处理阶段, 编译器会将所有定义的标识符替换成相应的内容并生成 .i 文件
60、c语言中的浮点型
1.2e2 表示 1.2×10的2次方 注意e后面不能为小数,e前面只能是10进制
61、
(m=a>b)&&(n=c>d) 从左边开始,只要左边一旦为0,则直接结束,右边不需要进行
a<b?a:c<d?c:d 三目运算符,从后面开始a<b?a:(c<d?c:d) ,赋值运算符、也是一样的运算顺序
62 指针与数组名
数组名表示的是数组的首地址
sizeof(数组名) 表示数组的字节大小
si则of(指针) 表示指针的大小
63、想要通过改变形参的值达到改变实参
改变变量的值,要用指针。
改变指针的值,要用指针的指针
64、scanf输入格式
%d%d 输入的时候使用空格、tab ent区分
%d,%d 摄入的时候使用,分开
65、++ 与*运算顺序
记住从后往前运行就可以 ++*a、*a++
66、指针常量与常量指针
指针常量——指针类型的常量 指针指向不能变 .数组名是一个指针常量,指针里面存放的是首元素地址
常量指针——指向“常量的指针 指针指向1内容不能变
int const * p; //常量指针
const int * p; //常量指针
int * const p; //指针常量常量指针=常量(const)+指针(int *a)
//注意:可改变对象,不可改变大小//指针常量=指针(int *)+常量(const a2)
//注意:不可改变对象,可改变大小
67、数组指针、指针数组
int *p1[5]; 指针数组
int (*p2)[5]; 数组指针
int *p2[5]
首先,对于语句“int*p1[5]”,因为“[]”的优先级要比“*”要高,所以 p1 先与“[]”结合,构成一个数组的定义,数组名为 p1,而“int*”修饰的是数组的内容,即数组的每个元素。也就是说,该数组包含 5 个指向 int 类型数据的指针,如图 1 所示,因此,它是一个指针数组
于语句“int(*p2)[5]”,“()”的优先级比“[]”高,“*”号和 p2 构成一个指针的定义,指针变量名为 p2,而 int 修饰的是数组的内容,即数组的每个元素。也就是说,p2 是一个指针,它指向一个包含 5 个 int 类型数据的数组,如图 2 所示。很显然,它是一个数组指针,数组在这里并没有名字,是个匿名数组
68、new 与malloc
int *p=new int(6); 创建一个空间存放6
int* ptr=new int[100];//分配100个int的内存空间
char *point = (char *) malloc(100); 创建一个空间,大小为100
/p = (int *) malloc(10 * sizeof(int))分配100个int的内存空间
用free之前需要检查需要释放的指针是否为空
delete[] mew[]匹配
69、if elseif ,if
这个后面可以选择接一个else,表示上面都没有满足执行这个,也可以不接,表示什么都不执行
70、不同数据类型进行运行
其实基本原则就是尽可能保存数据,int > float >double
C语言经典知识
指针、引用、值传递
数组指针、指针数组、字符指针
需要明确一个优先级顺序:()>[]>*
数组指针 是一个指针,指向一个数组的指针
(*p)[n]:根据优先级,先看括号内,则p是一个指针,这个指针指向一个一维数组,数组长度为n
指针数组 是一个数组,一个存放指针的数组
*p[n]:根据优先级,先看[],则p是一个数组,再结合*,这个数组的元素是指针类型,共n个元素,这是“指针的数组”,即指针数组。
字符指针,存放字符串首元素地址,不能通过指针改变常量字符串
数组指针
c语言简单代码
位运算·
1、计算出一个数中二进制中1的个数
1、与 1想与 判断最后一位是不是1
2、将这个数左移
2、使用联合体判断大小端
typedef union {
int a;
char b;
}UN;
int main(){
UN u;
u.a = 1;
if(u.b == 1) printf("小端存储\n");
else printf("大端存储\n");
return 0;
}
c++
1、子类继承 属性变化
private 在子类任何继承下都是private
2、友元函数
一个类的私有数据成员通常只能由类的函数成员来访问,而友元函数可以访问类的私有数据成员,也能访问其保护成员
3、if else的配对
与它上面最近的未与else配对 的if
4、构造函数
构造函数可以重载但是不能是虚函数
构造函数执行顺序是先父类后子类
5、lambda 表达式
auto f = [] (int a,int b) -> int {return a+b} //定义一个匿名函数 [] 捕获列表为空 调用匿名函数 cout << f(1,2) << endl;
6、成员变量初始化
在构造函数中需要初始化列表初始化的有如下三种情况
1.带有const修饰的类成员 ,如const int a ;
2.引用成员数据,如 int& p;
3.带有引用的类变量,如: class A { private: int &a; }; class B{ private: A c; }
这里的c需要用初始化列表进行初始化
作者:风走了,雨停了
链接:牛客网公司真题_免费模拟题库_企业面试|笔试真题
来源:牛客网
7、fork复制问题
虚拟地址一样,但是对应的物理地址不同,c语言都是虚拟地址
8、不能重载的运算符
类属关系运算符"."、
成员指针运算符".*"、作用域运算符"::"、sizeof运算符和三目运算符"?:
9、static成员变量
静态成员是类共享,静态只能访问静态,普通可以访问静态
静态成员函数没有this指针,需要通过类参数访问成员对象
静态成员必须在类外初始化
静态成员
10、构造函数
1、无参构造函数
2、有参构造
3、有默认参数的构造函数
11、初始化列表
12、空指针
p=NULL;和p=0;或p='\0';是等价的
13、运算符重载
operator+
++
牛客面经
1
linux设备树解析是什么时候
构建内核的时候,将设备树源文件dtbs编程成二进制dtb文件
2
linux多线程:在一个多线程访问某个外设驱动时,怎么防止其他线程访问
原子、加锁、信号量
内联函数的缺点是什么
优点:函数调用的开销减少了
缺点:
增加了代码的体积,加多了编译时间*(这个也不一定,函数调用变少编译时间变少,但是内联函数增加了很多代码编译时间也会变长),代码重复
多线程下怎么喂狗
这个涉及到多个线程对共享资源的访问,涉及到了线程的同步需要加锁
3
gdp运行在什么态, 调试的使用,step、next,finsh的区别
step 单步调试进入函数,next 不进入函数
finish 跳出函数
linux 内核启动流程
第一阶段:执行initrd文件系统中的某个文件,完成加载驱动模块等任务
第二阶段:执行根文件系统中的/sbin/init进程
uboot启动流程
内核如何传递启动参数
在uboot引导阶段,对参数bootargs参数进行设置
设备树DTS、DTB
驱动开发字符设备驱动开发流程
module_init 函数底层原理
module_init()是一个宏定义,这个函数在模块加载的时候被调用。这个宏通过将初始化函数的地址注册到内核数据结构中,在模块加载时候由内核调用这些初始化函数、这使得内核可以在模块加载时执行所需的初始化任务,为模块提供正确的环境的资源
C语言的inline 和define函数区别
#define只是简单的替换,没有函数调用的开销,但可能导致代码膨胀,没有检查类型,
inline 函数是真正的函数,有函数调用的优点,需要编译器支持和遵循,
c++类和c语言函数调用有什么区别
c++和c语言函数代码存储有什么区别
static 关键字、voliate关键字
函数调用的时候参数如何传递,如果参数很多怎么传递
参数很多的时候,将参数打包成结构体,进行传递
linux中断中的下半部软中断与tasklet的区别
软中断与tasklet都是下半部中断
软中断使用全局软中断向量,软中断中可以同时执行多个软中断函数同时运行,但是他们在同一个上下文中按顺序执行,可能会导致其他软中断延时处理
tasklet :每个cpu都有自己的tasklet队列,可以并行处理
大小端
小端模式:低位数据放在低地址,高位数据存放在高位数据
怎么判断是小端还是大端
使用一个共有体
结构体对齐
1、起始地址是数据大小的整数倍
2、整个结构体大小要是最大成员类型的整数倍
讲下GIc中断的状态
中断控制器GIC:控制器对中断源进行管理,当对应的中断源有效的时候,gic根据该中断源的管理,决定是否将该中断信号发送给cpu,如果多个中断源有效,那么gic还会选择中断优先级高的发送给cpu,待cpu中断处理之后,就会访问gic表示已经处理了,gic会取消中断源
gic控制器的四种状态
inactivate:中断处于无效状态
pending:中断处于有效状态,但是cpu没有响应该中断
activate:cpu在响应中断
activate and pending:cpu在响应中断,但是该中断源又有发送中断过来
MMU,多级页表,页表存储位置
进程切换过程
1、上下文保存:当操作系统决定切换到另一个进程时,首先要保存当前运行进程的上下文信息,包括程序计数器(pc)、寄存器内容、进程状态以及其他数据
2、切换到内核模型:
3、选择新进程:操作系统从就绪列表中选择一个新的进程
4、执行结束之后,回到之前的进程恢复上下文,继续执行
进程间通信
互斥锁与自旋转区别与应用场景
互斥锁:阻塞的会睡眠,自旋锁不会睡眠
中断中使用自旋锁,临界保护时间长的使用互斥锁
socket套接字
6
spi协议有几根线,如果缺少了一根会怎么样
GPIO模式
shell 脚本中#bin/bash 什么意思
并告诉系统要使用哪个解释器来执行这个脚本,bin/bash是解释器的路径
7
tcp建立连接之后,如果没有收到服务端的消息,客户端会做什么
超时重传,要是时间过长35就会使用超时重传断开连接
建立tcp连接的几种状态
11种状态