【C语言】

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 数据类型和占位符

【C语言】_第1张图片
【C语言】_第2张图片

1.2 异或

原则:110000101.
作用:交换两个整数的值而不必用第三个参数
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

【C语言】_第3张图片

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

【C语言】_第4张图片

1.8 左值和右值

【C语言】_第5张图片

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。

【C语言】_第6张图片

3. 二维数组和指针

【C语言】_第7张图片

4. 函数传递二维数组

4.1 形参给出第二维的长度。

【C语言】_第8张图片
【C语言】_第9张图片

4.2 形参声明为指向数组的指针。

#include 
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 
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);
}

【C语言】_第10张图片
【C语言】_第11张图片
【C语言】_第12张图片
【C语言】_第13张图片
【C语言】_第14张图片

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];

【C语言】_第15张图片

5. 二级指针传参数

5.1 二级指针传参数,没有改变原始值

【C语言】_第16张图片

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 二级指针传参数,改变原始值

【C语言】_第17张图片

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 函数指针&指针函数

【C语言】_第18张图片

9.1 指针函数

【C语言】_第19张图片
【C语言】_第20张图片

9.2 函数指针

【C语言】_第21张图片

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))

你可能感兴趣的:(#,C,c语言)