嵌入式C语言面试必备
const关键词与指针
const意味着只读。修饰指针的三种形式:
- int const *p 等价于const int *p --------指针的指向(p)可改,但是指针指向的内容(*p)不可改;
- int *const p --------- a刚好与上面相反:(*p)可改,(p)不可改;
- int const * const p等价于const int *const p ---------(*p)不可改,(p)不可改;
#include <stdio.h> #include <string.h> int main() { char a[]="Nice to see you!"; char b[]="Second point!"; char c[20]; const char *p1 = a ; // *p1只读 char const *p2 = a; // *p2只读 char * const p3 = a; // p3只读 printf("*p1 = %s\n*p2 = %s\n*p3 = %s\n",p1,p2,p3); p1 = b; p2 = b; *p3 = a[1]; //p3 = b; printf("*p1 = %s\n*p2 = %s\n*p3 = %s\n",p1,p2,p3); return 0; }
sizeof和strlen
- sizeof运算符用于获取括号()里面数据类型或者变量所占用的内存字节数;
- strlen求的是空间中实际的字符的个数,不包括结束符'\0'。
一维数组中的几个关键符号的理解
- buf:两层含义:一是数组名,如:sizeof(buf);二是等价于&buf[0],表示数组第一个元素的首字节地址,是一个地址常量值
- buf[0]:第一个元素的空间,可读写
- &buf[0]:等价于buf,是一个地址常量。
- &buf:表示数组首地址,是一个地址常量。与buf值相等但含义完全不同。&buf+1加1加的是整个数组的空间大小;buf+1加的是数组中一个元素空间大小
//代码运行环境:window7 64bit #include<stdio.h> #include<string.h> int main() { char str[] = " hello"; char *p=str; printf("sizeof(p)= %d\n",sizeof(p)); printf("sizeof(*p)= %d\n",sizeof(*p)); printf("*(p+1)= %c\n",*(p+1)); printf("strlen(p)= %d\n\n",strlen(p)); printf("sizeof(str)= %d\n",sizeof(str)); printf("sizeof(str[0])= %d\n",sizeof(str[0])); printf("strlen(str)= %d\n",strlen(str)); printf("%p\n",p); printf("%p\n",&str[0]); printf("%p\n",str); printf("%p\n",p+1); return 0; }
sizeof(p)= 8 sizeof(*p)= 1 *(p+1)= h strlen(p)= 6 sizeof(str)= 7 sizeof(str[0])= 1 strlen(str)= 6 000000000022FE40 000000000022FE40 000000000022FE40 000000000022FE41 -------------------------------- Process exited after 0.2643 seconds with return value 0 请按任意键继续. . .
函数指针:
一个函数:int func(void)
其函数指针为:int (*p)(void);
定义一个函数指针指向strcpy函数,并验证函数指针定义是否匹配
#include <stdio.h> #include <string.h> int main() { char a[20]; char* (*p)(char *,const char *); p= strcpy; p(a,"nice to see you!"); printf("a[20] = %s\n",a); return 0; }
a[20] = nice to see you! -------------------------------- Process exited after 0.03327 seconds with return value 0 请按任意键继续. . .
typedef和#define宏的区别
与typedef不同,#define是单纯的替换,替换发生在预编译阶段,可以把#define的每个参数当做一堆字母,#define只是简单的一堆字母用另一堆字母替换,词义的分析不在它的范围;
格式:
typedef char * tpchar; #define dpchar char *
typedef行和原型行只差一个typedef,而#define语句两个参数与typedef顺序相反
typedef char * tpchar; #define dpchar char * dpchar p1,p2; // char *p1,p2; tpchar p1,p2; // char *p1,*p2;
typedef与struct
通常结构体在使用时都是先定义结构体类型,再用结构体类型去定义变量(必须带上struct)
struct node{ int age; char name[10]; }; struct node n;
但配合typedef使用时,不需要在定义结构体变量时添加struct
typedef struct node{
int age;
char name[10];
} Node;
Node n;
typedef与数组、函数指针
普通定义:char t[80]
运用typedef:
typedef char line[80]; line t;
函数指针普通定义;int (*fp)(int,int)
运用typedef:
typedef int (*func_ptr)(int,int); func_ptr fp;
typedef与const
typedef int *PINT; const PINT p2;相当于int *const p2, 等价于typedef int *PINT;PINT const p2;
指针的指向的地址p2不可改变
typedef const int *PINT;PINT p3;相当于 const int *p3
指针指向的内容*p2不可改变
注:
typedef就是给类型取个别名,如上定义就是给一个函数指针类型取了个别名func_prt。
typedef在语法上是一个存储类的关键字(如:auto,extern,static,register),而一个变量只能被一种存储类的关键字修饰。
野指针:
所谓野指针就是指针指向一个不确定的地址空间,或者地址空间确定,但引用空间的结果却不可预知。
两个小例子:
eg1: //指针p是一个局部变量,未初始化,没有后续赋值,所以p指向的内存空间不确定,结果未知。 int main(void) { int *p; *p = 10; return 0; } eg2: //p虽然指向了一个确定地址空间,但是这个空间是否存在,读写权限是否满足程序的访问要求,都未知,所以结果未知。 int main(void) { int *p = 0x12345678; *p = 10; return 0; }
数组指针访问二维数组:
#include <stdio.h> int main() { int a[2][4] = {{4,5,6,7},{8,9,0,1}}; int (*p)[4] = NULL; int *p1=NULL,*p2=NULL; p1 = a[0]; p2 = a[1]; p = a; printf("a[0][0] = %d\n",**p); printf("a[0][0] = %d\n",*(*p+1)); printf("a[1][3] = %d\n",*(*(p+1)+3)); printf("=============\n"); //a[i][j] <==>*(*(p+i)+j) printf("a[0][0] = %d\n",*p1); printf("a[0][1] = %d\n",*(p1+1)); printf("a[1][3] = %d\n",*(p2+3)); return 0; }
a[0][0] = 4 a[0][0] = 5 a[1][3] = 1 ============= a[0][0] = 4 a[0][1] = 5 a[1][3] = 1 -------------------------------- Process exited after 0.08917 seconds with return value 0 请按任意键继续. . .
对于二维数组a[2][4]而言:a等价于&a[0],a[0] 等价于&a[0][0],故a等价于&&a[0][0]。
结构体字节对齐
先介绍一个概念——偏移量,结构体中的偏移量就是结构体成员和结构体变量的地址之差,
比如说第一个结构体成员的偏移量就是0,第二个结构成员的偏移量就是第一个结构体成员
的大小,假如第一个成员的是int b;那么第二个结构体成员变量的偏移量就是4,
计算结构体大小的规则:
1.每一个成员的偏移量都必须是该成员的倍数。
2.结构体的大小必须是该结构体字节数最大成员的倍数。
手动对齐:
#pragma用于告诉编译器,程序员希望自定义对齐方式。
常用的手动设置字节对齐的命令:
1、 #pragma pack(),这种就是设置为1字节对齐或者说是设置为不对齐或取消对齐
2、#pragma pack(4),表示手动设置为4字节对齐
使用方法:在需要自定义对齐方式的开头运用命令:#pragma pack(n) ,结尾运用命令:#pragma pack()
GCC中也可以使用推荐的对齐指令:
_attribute_((packed)):取消对齐
_attribute_((aligned(n))) :n字节对齐
#include <stdio.h> struct num{ char a[10]; double b; int c; char d; }s1; int main() { printf("sizeof(s1) = %d\n",sizeof(s1)); return 0; }
sizeof(s1) = 32 -------------------------------- Process exited after 0.05793 seconds with return value 0 请按任意键继续. . .
#include <stdio.h> #pragma pack(1) struct num{ char a[10]; double b; int c; char d; }s1; #pragma pack() int main() { printf("sizeof(s1) = %d\n",sizeof(s1)); return 0; }
sizeof(s1) = 23 -------------------------------- Process exited after 0.02397 seconds with return value 0 请按任意键继续. . .
#include <stdio.h> #pragma pack(2) struct num{ char a[10]; double b; int c; char d; }s1; #pragma pack() int main() { printf("sizeof(s1) = %d\n",sizeof(s1)); return 0; }
sizeof(s1) = 24 -------------------------------- Process exited after 0.3388 seconds with return value 0 请按任意键继续. . .
#include <stdio.h> #pragma pack(4) struct num{ char a[10]; double b; int c; char d; }s1; #pragma pack() int main() { printf("sizeof(s1) = %d\n",sizeof(s1)); return 0; }
sizeof(s1) = 28 -------------------------------- Process exited after 0.02381 seconds with return value 0 请按任意键继续. . .