【C学习笔记】一
阅读原文时间:2023年07月10日阅读:1

一、运算符优先级

逻辑非>算术运算符>关系运算符>逻辑运算符>赋值运算符>逗号运算符

逻辑运算符>条件运算符>赋值运算符

对于if的执行语句,如果是一条语句那么花括号可以省略,如果是多条语句那么花括号一定不能省略。

二、打印格式

%d:按照十进制整型打印

%6d:按照十进制整型数打印,至少6个字符宽

%f:按照浮点数打印

%6f:按照浮点数打印,至少6个字符宽

%.2f:按照浮点数打印,小数点后有两位小数

%6.2f:按照浮点数打印,至少6个字符宽。小数点后有2位小数

%o:表示八进制

%x:表示十六进制

%c:表示字符

%s:表示字符串

%%:表示百分号本身

三、符号常量

#define  名字 替换文本

#define maxSize 100

四、标识符

C标识符用来标识变量、函数、或任何其他用户自定义项目的名称,一个标识符以字母A-Z或a-z或下划线_开始,后跟零个或多个字母、下划线和数字(0-9)。

C标识符内不允许出现标点字符,比如@ ¥ %等。

五、关键字

auto  

break

case

char

const

continue

default

do

double

else

enum

extern

float

for  

goto

if

int

long

register

return

short

signed

sizeof

static

struct

switch

typedef

unsigned

union

void

volatile

while

_Bool

_Complex

_Imaginary

inline

restrict

_Alignas

_Alignof

_Atomic

_Generic

_Norteturn

_Static_assert

_Thread_local

六、数据类型

1、基本类型:整数类型和浮点类型

整数类型:

char  

1字节

-128-127 或0-255

unsigned  char

1z字节

0-255

signed  char

1字节

-128-127

int 

2或4

-32,768 到 32,767 或 -2,147,483,648 到 2,147,483,647

unsigned int

2或4

0 到 65,535 或 0 到 4,294,967,295

short

2

-32,768 到 32,767

unsigned short

2

0 到 65,535

long

4

-2,147,483,648 到 2,147,483,647

unsigned long

4

0 到 4,294,967,295

浮点类型:

float

4字节

1.2E-38 到 3.4E+38

6位小数

double

8字节

2.3E-308 到 1.7E+308

15位小数

long double

16字节

3.4E-4932 到 1.1E+4932

19位小数

2、枚举类型

3、void类型:void

4、派生类型:指针类型  数组类型  结构类型   共用体类型  函数类型

数组+结构=聚合类型

七、C中的变量声明

变量声明向编译器保证变量以指定的类型和名称存在,这样编译器在不需要知道变量完整细节的情况下也能继续进行下一步的编译。变量声明只在编译时有她的意义,在程序连接时编译器需要实际的变量声明。

声明分2中:

1、需要建立存储空间,eg:int a在声明的时候就已经建立了存储空间

2.另一种是不需要建立存储空间的,通过使用extern管家你再声明变量名而不定义它。

除非有extern关键字,否则都是变量的定义。

八、整型常量

整型常量可以是十进制、八进制或者十六进制的常量。前缀知道基数:0x或0X表示十六进制,0表示八进制,不带前缀则默认表示十进制。

整数常量也可以带一个后缀,后缀是U和L的组合,U表示无符号整数,L表示长整数,猴嘴可以是大写,也可以是小写,U和L的顺序任意。

九、字符常量

\\

\字符

\'

'字符

\"

"

\?

?

\a

警报铃声

\b

退格键

\f

换页符

\n

换行符

\r

回车

\t

水平制表符

\v

垂直制表符

\ooo

一到三位的八进制数

\xhh

一个或多个数字的十六进制数

十、定义常量

1、使用#define预处理器      #define  LENGTH 10

2、使用const关键字       const  int LENGTH =10;

十一、C存储类

1、auto

auto存储类是所有局部变量默认的存储类

{

int mount;

auto int month;

}

该实例定义了两个带有相同存储类的变量,auto只能用在函数内,即auto只能修饰局部变量。

2、register存储类

register存储类用于定义存储在寄存器中而不是RAM中的局部变量,这意味着变量的最大尺寸等于寄存器的大小,且不能对他应用医院的&运算符

{

register  int miles;}

寄存器只能用于需要快速访问的变量,比如计数器,是否存储在寄存器中,取决于硬件和实现的限制。

3、static存储类

static存储类指示编译器在程序的生命周期内保持局部变量的存在,而不需要在每次它进入和离开作用域时进行创建和销毁,因此,使用static修饰局部变量可以在函数调用之间保持局部变量的值。

static修饰符也可以应用于全局变量,当static修饰全局变量时,会使变量的作用域限制在声明他的文件内。全局声明的一个static变量或方法可以被任何函数或方法调用,只要这些方法出现在跟static变量或方法同一个文件中。

#include

/* 函数声明 */
void func1(void);

static int count=; /* 全局变量 - static 是默认的 */

int main()
{
while (count--) {
func1();
}
return ;
}

void func1(void)
{
/* 'thingy' 是 'func1' 的局部变量 - 只初始化一次
* 每次调用函数 'func1' 'thingy' 值不会被重置。
*/
static int thingy=;
thingy++;
printf(" thingy 为 %d , count 为 %d\n", thingy, count);
}

count作为全局变量可以在函数内使用,thingy使用static修饰后,不会在每次调用时重置。

4、extern存储类

extern存储类用于提供一个全局变量的音乐,全局变量对所有的程序文件都是克俭的,当您使用extern时,对于无法初始化的变量,会把变量名指向一个之前定义过的存储位置。

当有多个文件且定义了一个可以在其他文件中使用的全局变量或函数时,可以在其他文件中使用extern来得到已定义的变量或函数的音乐。也就是extern是用来在另一个文件中声明一个全局变量或函数

extern修饰符通常用于当有两个或多个文件共享相同的全局变量或函数的时候。

十二、C运算符

1、算术运算符

+  - *  /  %  ++  --

2、关系运算符

==   !=  >   <   >=    <=

3、逻辑运算符

&&  ||   |

4、位运算符

|  &   ^     ~  <<   >>

5、赋值运算符

=  += -=  *=  /*  %=  <<=  >>=  &=  ^=  |=

6、杂项运算符

sizeof()   &  *  ?:

sizeof

返回变量的大小sizeof(a)将返回4,其中a是整数

&

返回变量的地址  &a;将给出变量的实际地址

*

指向一个变量  *a将指向一个变量

?:

如果条件为真?则值为X:否则值为Y

#include

int main()
{
int a = ;
short b;
double c;
int* ptr;

/\* sizeof 运算符实例 \*/  
printf("Line 1 - 变量 a 的大小 = %lu\\n", sizeof(a) );  
printf("Line 2 - 变量 b 的大小 = %lu\\n", sizeof(b) );  
printf("Line 3 - 变量 c 的大小 = %lu\\n", sizeof(c) );

/\* & 和 \* 运算符实例 \*/  
ptr = &a;    /\* 'ptr' 现在包含 'a' 的地址 \*/  
printf("a 的值是 %d\\n", a);  
printf("\*ptr 是 %d\\n", \*ptr);

/\* 三元运算符实例 \*/  
a = ;  
b = (a == ) ? : ;  
printf( "b 的值是 %d\\n", b );

b = (a == ) ? : ;  
printf( "b 的值是 %d\\n", b );  

}

Line 1 - 变量 a 的大小 = 4
Line 2 - 变量 b 的大小 = 2
Line 3 - 变量 c 的大小 = 8
a 的值是 4
*ptr 是 4
b 的值是 30
b 的值是 20

十二、C中运算符优先级

类别 

运算符 

结合性 

后缀 

() [] -> . ++ - -  

从左到右 

一元 

+ - ! ~ ++ - - (type)* & sizeof 

从右到左 

乘除 

* / % 

从左到右 

加减 

+ - 

从左到右 

移位 

<< >> 

从左到右 

关系 

< <= > >= 

从左到右 

相等 

== != 

从左到右 

位与 AND 

从左到右 

位异或 XOR 

从左到右 

位或 OR 

从左到右 

逻辑与 AND 

&& 

从左到右 

逻辑或 OR 

|| 

从左到右 

条件 

?: 

从右到左 

赋值 

= += -= *= /= %=>>= <<= &= ^= |= 

从右到左 

逗号 

从左到右 

十三、C作用域规则
1、在函数或块内部的局部变量
2、在所有函数外部的全局变量
3、在形式参数的函数参数定义中

十四、指针
在定义的时候 *p表示p是指针变量,而不是普通变量
在使用的时候 *p表示取p保存的地址编号对应的空间的内容

指针变量两种类型:自身的类型 指向的类型
自身的类型:在指针变量定义的时候 将变量名涂黑,剩下啥类型,指针变量就是啥类型(int *p =NULL) 所以他的类型就是 int *
指向的类型:在指针变量定义的时候,将变量名和离他最近的一个*一起涂黑 剩下啥类型就是啥类型(int *p = NULL) 指向的类型是 int
指针变量指向的类型的作用决定了指针变量所取空间内容的宽度,决定了指针变量+1跳过的单位跨度

void test01() {
int num = 0x01020304; //4个字节
//在linux或者windows中是倒着存储的
int *p1 = #//4个字节

 printf("\*p1 = %#x\\n", \*p1);//0x01020304

 short \*p2 = &num;//2个字节  
 printf("\*p2 = %#x\\n", \*p2);//0x0304

 char \*p3 = &num;  
 printf("\*p3 = %#x\\n", \*p3);//0x04  

}

void test02() {
int num = 0x01020304;
short *p4 = #
p4 = p4 + ;//取后面2个字节 定义指针为short类型,+1 因为short为2个字节 所以跳过了2个字节
printf("*p4 = %#x\n", *p4);//0x1020

}

指针数组vs数组指针:
指针数组:指针数组可以说成是“指针的数组”,首先这个变量是一个数组,其次,“指针”修饰这个数组,意思是说这个数组的所有元素都是指针类型。
数组指针:数组指针可以说成是数组的指针,首先这个变量是一个指针,其次,数组修饰这个指针,意思是说这个指针存放着一个数组的首地址,或者说这个指针指向一个数组的首地址。

十五、C中字符串操作函数

strcpy(s1,s2)

复制字符串s2到字符串s1

strcat(s1,s2)

连接字符串s2到字符串s1的末尾

strlen(s1)

返回字符串s1的长度

strcmp(s1,s2)

如果s1和s2是相同的则返回0,如果s1s2则返回大于0

strchr(s1,ch)

返回一个指针,指向字符串s1中字符ch的第一次出现的位置

strstr(s1,s2)

返回一个指针,指向字符串s1中字符串s2的第一次出现的位置

十六、结构体
1、定义

struct Books
{
char title[];
char author[];
char subject[];
int book_id;
};

2、访问结果成员

使用成员访问运算符(.)

void printBook(struct Books book);

void main() {
//printf("title : %s\nauthor: %s\nsubject: %s\nbook_id: %d\n", book.title, book.author, book.subject, book.book_id);
struct Books Book1;
struct Books Book2;
/* Book1 详述 */
strcpy(Book1.title, "C Programming");
strcpy(Book1.author, "Nuha Ali");
strcpy(Book1.subject, "C Programming Tutorial");
Book1.book_id = ;

 /\* Book2 详述 \*/  
 strcpy(Book2.title, "Telecom Billing");  
 strcpy(Book2.author, "Zara Ali");  
 strcpy(Book2.subject, "Telecom Billing Tutorial");  
 Book2.book\_id = ;  
 /\* 输出 Book1 信息 \*/  
 printBook(Book1);

 /\* 输出 Book2 信息 \*/  
 printBook(Book2);

}

void printBook(struct Books book) {
printf("Book title : %s\n", book.title);
printf("Book author : %s\n", book.author);
printf("Book subject : %s\n", book.subject);
printf("Book book_id : %d\n", book.book_id);
}

结构体中成员变量分配的空间是按照成员变量中占用空间最大的来作为分配单元,通用成员变量的存储空间也是不能跨分配单元的,如果当前的空间不足,则会存储到下一个分配单元中。

#include

typedef struct
{
unsigned char a;
unsigned int b;
unsigned char c;
} debug_size1_t;
typedef struct
{
unsigned char a;
unsigned char b;
unsigned int c;
} debug_size2_t;

int main(void)
{
printf("debug_size1_t size=%lu,debug_size2_t size=%lu\r\n", sizeof(debug_size1_t), sizeof(debug_size2_t));
return ;
}

debug_size1_t size=12,debug_size2_t size=8

结构体占用存储空间,以32位机为例

  • 1.debug_size1_t 存储空间分布为a(1byte)+空闲(3byte)+b(4byte)+c(1byte)+空闲(3byte)=12(byte)。
  • 1.debug_size2_t 存储空间分布为a(1byte)+b(1byte)+空闲(2byte)+c(4byte)=8(byte)。

十七、typedef  vs #define

typedef仅限于为类型定义符号名称,#define不仅可以为类型定义别名,也能为数值定义别名,比如可以定义1为ON

typedef是由编译器执行解释的,#define语句是由预编译期进行处理的。

十八、C预处理器

#define

定义宏

#include

包含一个源代码文件

#undef

取消已定义的宏

#indef

如果宏已经定义,则返回真

#ifndef

如果宏没有定义,则返回真

#if

如果给定条件为真,则编译下面代码

#else

#if的替代方案

#elif

如果前面的 #if 给定条件不为真,当前条件为真,则编译下面代码

#endif

结束一个 #if……#else 条件编译块

#error

当遇到标准错误时,输出错误消息

#pragma

使用标准化方法,向编译器发布特殊的命令到编译器中