C语言
- 1. C语言基础
- 1.1 数据类型和占位符
- 1.2 异或
- 1.3 关键字
- 1.4 const
- 1.5 extern
- 1.6 typedef
- 1.7 static
- 1.8 左值和右值
- 1.9 位进行操作赋值
- 2. C指针
- 3. 二维数组和指针
- 4. 函数传递二维数组
- 4.1 形参给出第二维的长度。
- 4.2 形参声明为指向数组的指针。
- 4.3 形参声明为指针的指针。
- 5. 二级指针传参数
- 5.1 二级指针传参数,没有改变原始值
- 5.2 二级指针传参数,改变原始值
- 6 数组指针(也称行指针)
- 7 指针数组
- 8 指针变量
- 9 函数指针&指针函数
- 9.1 指针函数
- 9.2 函数指针
- 10 三维数组的传递
- 11 计算公式最大值最小值和中间值
1. C语言基础
1.1 数据类型和占位符
1.2 异或
原则:1和1取0,0和0 取0,1和0 取1.
作用:交换两个整数的值而不必用第三个参数
a = 9;
b = 11;
a=a^b; 1001^1011=0010
b=b^a; 1011^0010=1001
a=a^b; 0010^1001=1011
1.3 关键字
设置表格对齐方式:
关键字 | 描述 |
---|---|
__asm | 用于内嵌汇编代码和直接访问底层硬件 |
__inline | 用于内联函数,以减少函数调用的开销 |
attribute | 用于定义变量或函数的属性,例如对齐方式、可见性、优化等级等 |
__packed | 用于取消结构体成员的对齐,以节省内存空间 |
__irq, __fiq | 用于定义中断服务函数的类型,以区分普通函数和中断函数 |
register | 用于将变量声明为寄存器变量,以提高访问速度 |
volatile | 告诉编译器该变量可能会被意外修改,从而避免编译器对该变量进行优化 |
__weak, __strong | 用于声明弱引用和强引用变量,在链接时进行符号重定向 |
__packed, attribute((aligned(n))) | 用于控制结构体和变量的对齐方式 |
ARM_ARCH_XX | 用于条件编译,根据处理器的不同选择不同的代码路径 |
1.4 const
请看下面三种定义:
const char p; const 修饰的是p 所以是p值不能更改。
char const p; const 修饰的是p 所以是p值不能更改。
char * const p; const 修饰的是p 所以是p指针不能更改。
1.5 extern
1.6 typedef
作用是为一种数据类型定义一个新的名字。对于以上两种结构体定义形式,
typedef都可以为其创建别名。
1. 先定义结构体类型,再定义结构体变量
struct student{
char no[20]; //学号
char name[20]; //姓名
char sex[5]; //性别
int age; //年龄
};
struct student stu1,stu2;
//此时stu1,stu2为student结构体变量
2. 定义结构体类型的同时定义结构体变量。
struct student{
char no[20]; //学号
char name[20]; //姓名
char sex[5]; //性别
int age; //年龄
} stu1,stu2;
此时还可以继续定义student结构体变量如:
struct student stu3;
1. 先定义结构体类型,再定义结构体变量
struct{
char no[20]; //学号
char name[20]; //姓名
char sex[5]; //性别
int age; //年龄
} stu1,stu2;
1.7 static
1.8 左值和右值
1.9 位进行操作赋值
可以对 u16Bit;数据类型中的每个位进行操作赋值,u16Bit.b1 = 1;。
typedef struct{
union{
struct {
uint8_t b0:1;
uint8_t b1:1;
uint8_t b2:1;
uint8_t b3:1;
uint8_t b4:1;
uint8_t b5:1;
uint8_t b6:1;
uint8_t b7:1;
uint8_t b8:1;
uint8_t b9:1;
uint8_t b10:1;
uint8_t b11:1;
uint8_t b12:1;
uint8_t b13:1;
uint8_t b14:1;
uint8_t b15:1;
};
uint16_t byte;
};
}u16Bit;
/*********************************定义uint32_t*******************************/
typedef struct {
uint32_t b0:1;
}u200Bit;
u200Bit u200bit_t;
u200bit_t.b0=1;//赋值
qDebug() << "sizeof(u200Bit)=" << sizeof(u200Bit) << u200bit_t.b0 << endl; //sizeof(u200Bit)= 4 1
/*********************************定义uint16_t*******************************/
typedef struct {
uint16_t b0:1;
}u200Bit;
u200Bit u200bit_t;
u200bit_t.b0=1;//赋值
qDebug() << "sizeof(u200Bit)=" << sizeof(u200Bit) << u200bit_t.b0 << endl; //sizeof(u200Bit)= 2 1
/*********************************定义uint8_t*******************************/
typedef struct {
uint8_t b0:1;
}u200Bit;
u200Bit u200bit_t;
u200bit_t.b0=1; //赋值
qDebug() << "sizeof(u200Bit)=" << sizeof(u200Bit) << u200bit_t.b0 << endl;//sizeof(u200Bit)= 1 1
2. C指针
main()
{
int a[5]={1,2,3,4,5};
int *ptr=(int *)(&a+1);
printf("%d,%d",*(a+1),*(ptr-1));
}
-
&a + 1: 取数组a 的首地址,该地址的值加上sizeof(a) 的值,即&a + 5*sizeof(int),也就是下一个数组的首地址,显然当前指针已经越过了数组的界限。
(int *)(&a+1): 则是把上一步计算出来的地址,强制转换为int * 类型,赋值给ptr。 -
*(a+1): a,&a 的值是一样的,但意思不一样,a 是数组首元素的首地址,也就是a[0]的首地址,&a 是数组的首地址,a+1 是数组下一元素的首地址,即a[1]的首地址,&a+1 是下一个数组的首地址。所以输出 (ptr-1): 因为ptr 是指向a[5],并且ptr 是int * 类型,所以(ptr-1) 是指向a[4] ,输出5。
3. 二维数组和指针
4. 函数传递二维数组
4.1 形参给出第二维的长度。
4.2 形参声明为指向数组的指针。
#include <stdio.h>
void func(int n, char (*str)[5] )
{
int i;
for(i = 0; i < n; i++)
printf("\nstr[%d] = %s\n", i, str[i]);
}
void main()
{
char* p[3];
char str[][5] = {"abc","def","ghi"};
func(3, str);
}
4.3 形参声明为指针的指针。
#include <stdio.h>
void func(int n, char **str)
{
int i;
for(i = 0; i < n; i++)
printf("\nstr[%d] = %s\n", i, str[i]);
}
void main()
{
char* p[3];
char str[][5] = {"abc","def","ghi"};
p[0] = &str[0][0];
p[1] = str[1];
p[2] = str[2];
func(3, p);
}
char* arg[] = {
"abc",
"cde",
"efg",
};
//这种写法和上面的等价
char* b[3];
b[0] = arg[0];
b[1] = arg[1];
b[2] = arg[2];
int array[][3] = {
{1, 2, 3},
{2, 3, 4},
{3, 4, 5},
};
int* a[3];
a[0] = array[0];
a[1] = array[1];
a[2] = array[2];
5. 二级指针传参数
5.1 二级指针传参数,没有改变原始值
uis@ubuntu:~/text$ gcc zhizheng.c
uis@ubuntu:~/text$
uis@ubuntu:~/text$ ./a.out
&a=0x7ffe43789e08,&p=0x7ffe43789e0c
pp=0x7ffe43789e08,kk=0x7ffe43789e0c---&pp=0x7ffe43789e10,&kk=0x7ffe43789e18
x=0x7ffe43789e10,y=0x7ffe43789e18---&x=0x7ffe43789dd8,&y=0x7ffe43789dd0,--- *x=0x7ffe43789e08,*y=0x7ffe43789e0c
x=0x7ffe43789e10,y=0x7ffe43789e18---&x=0x7ffe43789dd8,&y=0x7ffe43789dd0,--- *x=0x7ffe43789e08,*y=0x7ffe43789e0c
x=0x7ffe43789e10,y=0x7ffe43789e18---&x=0x7ffe43789dd8,&y=0x7ffe43789dd0,--- *x=0x7ffe43789e0c,*y=0x7ffe43789e0c
x=0x7ffe43789e10,y=0x7ffe43789e18---&x=0x7ffe43789dd8,&y=0x7ffe43789dd0,--- *x=0x7ffe43789e0c,*y=0x7ffe43789e08
a = 20 b = 10, a=10,b=20
5.2 二级指针传参数,改变原始值
uis@ubuntu:~/text$ gcc zhizheng2.c
uis@ubuntu:~/text$
uis@ubuntu:~/text$ ./a.out
&a=0x7ffc22703778,&p=0x7ffc2270377c
pp=0x7ffc22703778,kk=0x7ffc2270377c---&pp=0x7ffc22703780,&kk=0x7ffc22703788
x=0x7ffc22703780,y=0x7ffc22703788---&x=0x7ffc22703748,&y=0x7ffc22703740,--- *x=0x7ffc22703778,*y=0x7ffc2270377c
x=0x7ffc22703780,y=0x7ffc22703788---&x=0x7ffc22703748,&y=0x7ffc22703740,--- *x=0x7ffc22703778,*y=0x7ffc2270377c
x=0x7ffc22703780,y=0x7ffc22703788---&x=0x7ffc22703748,&y=0x7ffc22703740,--- *x=0x7ffc22703778,*y=0x7ffc2270377c
x=0x7ffc22703780,y=0x7ffc22703788---&x=0x7ffc22703748,&y=0x7ffc22703740,--- *x=0x7ffc22703778,*y=0x7ffc2270377c
a = 20 b = 10, a=20,b=10
6 数组指针(也称行指针)
定义 int (*p)[n];
()优先级高,首先说明p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p的步长。也就是说执行p+1时,p要跨过n个整型数据的长度。
int a[3][4];
int (*p)[4]; //该语句是定义一个数组指针,指向含4个元素的一维数组。
p=a; //将该二维数组的首地址赋给p,也就是a[0]或&a[0][0]
p++; //该语句执行过后,也就是p=p+1;p跨过行a[0][]指向了行a[1][]
所以数组指针也称指向一维数组的指针,亦称行指针。
7 指针数组
定义 int *p[n];
//这里int *p[3] 表示一个一维数组内存放着三个指针变量,分别是p[0]、p[1]、p[2]
[]优先级高,先与p结合成为一个数组,再由int*说明这是一个整型指针数组,它有n个指针类型的数组元素。这里执行p+1时,则p指向下一个数组元素,这样赋值是错误的:p=a;因为p是个不可知的表示,只存在p[0]、p[1]、p[2]...p[n-1],而且它们分别是指针变量可以用来存放变量地址。但可以这样 *p=a; 这里*p表示指针数组第一个元素的值,a的首地址的值。
如要将二维数组赋给一指针数组:
int *p[3];
int a[3][4];
p++; //该语句表示p数组指向下一个数组元素。注:此数组每一个元素都是一个指针
for(i=0;i<3;i++)
p[i]=a[i]
这里int *p[3] 表示一个一维数组内存放着三个指针变量,分别是p[0]、p[1]、p[2]
所以要分别赋值。
8 指针变量
int *p;
*p = NULL;
同样,我们可以在编译器上调试这两行代码。第一行代码,定义了一个指针变量 p,其指向
的内存里面保存的是 int 类型的数据;但是这时候变量 p 本身的值是多少不得而知,也就是
说现在变量 p 保存的有可能是一个非法的地址。第二行代码,给*p 赋值为 NULL,即给 p
指向的内存赋值为 NULL;但是由于 p 指向的内存可能是非法的,所以调试的时候编译器可
能会报告一个内存访问错误。这样的话,我们可以把上面的代码改写改写,使 p 指向一块合
法的内存:
int i = 10;
int *p = &i;
*p = NULL;
在编译器上调试一下,我们发现 p 指向的内存由原来的 10 变为 0 了;而 p 本身的值, 即内
存地址并没有改变
9 函数指针&指针函数
9.1 指针函数
9.2 函数指针
10 三维数组的传递
11 计算公式最大值最小值和中间值
最大值
#define MAX(a, b) (((a) > (b) ) ? (a) : (b))
最小值
#define MIN(a, b) (((a) < (b) ) ? (a) : (b))
中间值
#define MID(a,b,c) a>b?(a>c?(b>c?b:c):(a)):(a>c?(a):(b>c?c:b))