C编译器html

gcc -> ccnode

虽然咱们称gcc是C语言的编译器,但使用gcc编译C语言源代码文件不只仅是编译的过程,而是要经历四个相互关联的步骤∶预处理(也称预编译)->编译->汇编->连接.linux

1.从一个.c文件编译成可执行文件须要经历4个阶段ios

预处理器c++

编译器程序员

汇编器编程

连接器数组

2.预处理时须要哪些操做bash

文件包含数据结构

宏定义

条件编译

gcc

gcc 文件名 编译.c程序

gcc hello.c

什么也没有提示 证实程序没有问题(语法),编译经过

并不表明程序执行彻底正确

报出警告 会生成可执行文件,有可能执行成功

报出错误100%程序有问题,不会生成可执行文件

gcc -Wall 1.c

W 警告

all 全部

gcc -o hello hello.c

指定编译以后生成的可执行文件的名字

编译生成 二进制可执行文件a.out

执行./a.out

代码实例

#include

/*

#include 文件包含

在C语言中以#开头是预处理的内容

预处理阶段包括 文件包含 宏定义 条件编译

stdio.h 头文件(.h结尾)标准的输入输出

<...> 默认从/usr/include找头文件

"..." 默认从本地目录中找头文件

*/

int main(void)//void 空

{

printf("hello world!");

/*

printf是一个功能函数(打印输出的函数 终端中)

在C语言中双引号引发来的表示为 字符串

在C语言中单引号引发来的表示为 字符

字符串 是由 一个一个字符组成的

默认字符串最后有尾0 '\0'

"hello" = 'h' + 'e' + 'l' + 'l' + 'o' + '\0'

*/

return 0;

/*

return 也属于跳转语句,默认函数中碰到return函数就结束了

return以后的值会返回给调用者

返回值

1.返回的是结算结果

2.返回函数执行状态

0 函数正常结束

正值 函数有异常

负值 函数有错误

*/

}

/*

main函数(主函数)

当执行程序时是从主函数进入,从上往下逐条逐条执行,程序结束时从主函数退出

1.函数的声明

函数的返回值类型 函数名(参数);//形参

2.函数的实现

函数的返回值类型 函数名(参数)//形参

{

函数功能;

}

3.函数的调用

函数名(参数);//实参

*/

printf打印之转义字符(见C截图)

注意虽然在写转义字符时是 \ + X,可是是一个字符

转义字符 意义ASCII码值(十进制)

\a 响铃(BEL) 007

\b 退格(BS),将当前位置移到前一列008

\f 换页(FF),将当前位置移到下页开头012

\n 换行(LF),将当前位置移到下一行开头010

\r 回车(CR),将当前位置移到本行开头013

\t 水平制表(HT)(跳到下一个TAB位置)009

\v 垂直制表(VT) 011

\\ 表明一个反斜线字符''\' 092

\' 表明一个单引号(撇号)字符039

\" 表明一个双引号字符034

\? 表明一个问号063

\0 空字符(NULL) 000

\ddd 1到3位八进制数所表明的任意字符 三位八进制

\xhh 1到2位十六进制所表明的任意字符 二位十六进制

printf打印之标准化输出格式(见C截图)

字符 对应数据类型 含义

d / i int 接受整数值并将它表示为有符号的十进制整数,i是老式写法

o unsigned int 无符号8进制整数(不输出前缀0)

u unsigned int 无符号10进制整数

x / X unsigned int 无符号16进制整数,x对应的是abcdef,X对应的是ABCDEF(不输出前缀0x)

f(lf) float(double) 单精度浮点数用f,双精度浮点数用lf(尤为scanf不能混用)

e / E double 科学计数法表示的数,此处"e"的大小写表明在输出时用的“e”的大小写

g / G double 使用以上两种中最短的形式,大小写的使用同%e和%E

c char 字符型。能够把输入的数字按照ASCII码相应转换为对应的字符

s / S char * 字符串。输出字符串中的字符直至字符串中的空字符

(字符串以'\0‘结尾,这个'\0'即空字符)

p void * 以16进制形式输出指针

n int * 到此字符以前为止,一共输出的字符个数,不输出文本

% 无输入 不进行转换,输出字符‘%’(百分号)自己

m 无 打印errno值对应的出错内容,(例: printf("%m\n"); )

注:%g、%G在小数点位数四位或指数大于等于精度时用%e、%E,不然用%f。

---------------------

标准化输出格式

是由 % + * 组成,不是字符

% 是占位符号

%.2f 输出小数点后两位变量

%.1f 输出小数点后一位

%3d 输出的十进制数字最少占用3个字符位置

%03d 空出的补0

/*

标准化输出格式

标准化输出格式不是字符

是由一个%加上某一个东西组成

% 是占位符

%p

后面加地址,打印出的就是地址

后面加变量名,打印出的是变量在内存中怎么存的(有多是补码也有多是源码,看寄存器)

*/

#include

int main(void)

{

char c = -128;

printf("c = %p\n", c);

/*

c = -13

内存中存的数据是补码

原1 0 0 0 1 1 0 1

补1 1 1 1 0 0 1 1

1 1 1 1 0 0 1 1

*/

return 0;

}

变量

1.变量是用来存储数据(在内存中进行存储)

2.变量的定义

数据类型 变量名;

int a;

1> 数据类型分类

整型 有/无符号short int long

实型 有符号float double

字符型 有/无符号char

2> 测试本身所用机器的类型所占字节数

sizeof()是一个运算符,单位是字节

sizeof(变量名/数据类型)

1字节= 8位

3> 变量名的要求

1) 变量名是区分大小写的

2) 变量名不能与C语言的关键字重复

3) 变量名能够由数字 字母 下划线组成,可是不能以数字开头

4) 变量名尽可能见名生义

4> 在使用变量时须要注意的点

1) 先定义再使用

2) 便于编译时检查错误,不一样类型的变量有不一样的运算要求

3) 定义变量以后,类型肯定了,未来所占用的存储空间就肯定了

3.变量的赋值

变量名= 数值;

a = 1000;

在复制时,赋值运算符须要把右边的项通过计算复制给左边的项(左值)

4.变量的初始化

数据类型 变量名= 数值;

int a = 1000;

char

char存储形式,1字节8位

有符号类型的char能够存储的数的范围是(-128~127)

char c = 13;//0000 1101

XYYY YYYY

第7位 为最高位,是符号位

第6~0位 为数据位

char c = 127;//1111 1111

char c = -128;//1000 0000

*)float

float存储形式,4字节32位

第31位 符号位0表明正数,1表明负数

第30~23位 阶位 转化成规格化的二进制以后与127作和

第22~0位 尾数

例:

3.2

正的因此最高位符号位为0

3 转化成二进制为11

0.2 小数部分乘2取整,而后从前日后读

0.2 * 2 = 0.4 0

0.4 * 2 = 0.8 0

0.8 * 2 = 1.6 1

0.6 * 2 = 1.2 1

0.2 * 2 = 0.4 0

11.001100110011...

而后将11.001100110011...的小数点向左移至小数点前只有一个1,即左移1位.

阶码就是1+127 = 128  即:1000 0000

尾数:由于小数点前必为1,因此记录小数点后面的数便可100110011001...

0100 0000 0100 1100 1100 1100 1100 1100

引入scanf概念

int a = 0;

int b = 0;

scanf("%d-%d", &a, &b);//接收键盘上录入的数值

/*

1. scanf中只写标准化输出格式就能够了,不要写其余的

2. scanf中后面的变量必需要加&(取地址)

3. scanf中的双引号内不要写'\n'

*/

printf("a = %d\nb = %d\n", a, b);//打印到屏幕上

return 0;

运算符

1.算术运算符:* - + / %

2.关系运算符:> < == != >= <=

3.逻辑运算符:! && ||

4.位运算符:<< >> ~ | ^ &(异或相同为0,不一样为1)

5.赋值运算符:= += -= *= /= %= >>= <<= &= |= ^=

6.条件运算符:?:    max = (a > b) ? a : b

8.指针运算符:*和&

* 取值

& 取地址

是可逆的

9.求字节数运算符:sizeof()

sizeof() 放变量/数据类型

10.强制类型转换运算符:(类型)

11.份量运算符:. -> (结构体)

结构体

共用体

12.下标运算符:[ ]

int arr[5]; // 5个成员

arr[0] ~ arr[4]// 1.数组名+下标

13.自增自减运算符:++ --

// 6 / 2 * (2 + 1)   不一样的编译器结果可能不一样1或9因此最好多用括号

14.其余:如函数调用运算符:()

注意:条件运算符是C语言中唯一一个三目(三元)运算符

原码、补码

凡是位运算都须要把操做数变成补码形式 左移右移时,正数补零,负数补一

操做数为正数,那么补码是它的自己(原码=补码)

操做数为负数,不管原码转补码 仍是 补码转原码,都是符号位不变,其余位按位取反再加1

/*

char a = 13;    ~a;

二进制(原码)

0   0   0   0   1   1   0   1

由于是个正数,因此补码=原码

补码(取反操做以前)

0   0   0   0   1   1   0   1

~

1   1   1   1   0   0   1   0

补码(取反操做以后)

1   1   1   1   0   0   1   0

反码

1   1   1   1   0   0   0   1

原码

1   0   0   0   1   1   1   0

char a = -13;   ~a;

原码

1   0   0   0   1   1   0   1

反码

1   1   1   1   0   0   1   0

补码(取反以前)

1   1   1   1   0   0   1   1

~a

0   0   0   0   1   1   0   0

补码(取反以后)

0   0   0   0   1   1   0   0

原码

0   0   0   0   1   1   0   0

*/

#include

int main(void)

{

char c = 3;//00000011

printf("c = %d\n", c);

c = c << 7;//10000000

printf("c = %d\n", c);

return 0;

}

#include

int main(void)

{

char c = -13;

printf("c = %d\n", c);

c = c >> 2;

printf("c = %d\n", c);

return 0;

}

/*

char c = -13;

c = c >> 2;

c = -4;

c = -13

原1 0 0 0 1 1 0 1

补1 1 1 1 0 0 1 1

c = c >> 2

补1 1 1 1 1 1 0 0

原1 0 0 0 0 1 0 0

c = -4

*/

#include

int main(void)

{

unsigned char c = 13;//00001101

printf("c = %d\n", c);

c = ~c; //11110010

printf("c = %d\n", c);

return 0;

}

/*

c = 13

原0 0 0 0 1 1 0 1

补0 0 0 0 1 1 0 1

~c

补1 1 1 1 0 0 1 0

原1 0 0 0 1 1 1 0

c = -14

*/

位运算符:

<< >> ~ | ^ &(异或相同为0,不一样为1)

<< 按位左移

至关于乘法

char c = 3; c << 4 等价于c * 2的4次方

>> 按位右移

至关于除法

char c = 13; c >> 2 等价于c除以2的2次方(取商)

00001101 00000011

& 按位与 清零

全1才是1,有0就是0

| 按位或 置1

全0才是0,有1就是1

~ 按位取反

0变成1,1变成0

^ 按位异或

相同为0,不一样为1

#include

程序实例:

int main(void)

{

char a = 13;//00001101

char b = 10;//00001010

char c = 0;

printf("c = %d\n", c);

c = a ^ b; //c = 1101 ^ 1010 = 0111

printf("c = %d\n", c);

return 0;

}

条件运算符:

? :

惟一的一个三目运算符

part.1 ? part.2 : part.3;

判断 part.1 的内容 若是part.1为真,会执行part.2的内容

若是 part.1 为假,会执行part.3的内容

#include

int main(void)

{

int a, b;

scanf("%d-%d", &a, &b);

a > b ? printf("a大于b\n") : printf("a小于等于b\n");

return 0;

}

分支语句

if

int main()

{

语句1;

if(条件) //真假

{

语句2;

}

语句3;

}

语句1-->判断if条件(真)-->语句2-->语句3-->结束

|

假-->语句3-->结束

if...else

int main(void)

{

语句1

if(条件)

{

语句2

}

else

{

语句3

}

语句4

}

语句1-->条件判断(真)-->语句2-->语句4

|

假-->语句3-->语句4

if...else if...else if...

int main(void)

{

语句1

if(条件1)

{

语句2

}

else if(条件2)

{

语句3

}

else

{

语句4

}

语句5

}

语句1-->判断条件1(真)-->语句2-->语句5

|

假-->判断条件2(真)-->语句3-->语句5

|

假-->语句4-->语句5

//比较两个值是否相等必定要用==

//if 里的大括号必定不要丢

switch

语句1

switch(变量)

{

case 条件1 ://条件是整常量 能够是 数字 或者 字符

语句2

break;

case 条件2 :

语句3

break;

default:

语句4

break;

}

语句5

语句1->(变量匹配)条件1(真)->语句2->break->语句5

|

假->条件2(真)->语句3->break->语句5

|

假->语句4->break->语句5

注意:

switch里加break,

匹配完条件->执行完语句->直接跳出switch

若是不加break

匹配条件->执行语句->顺序往下执行

若是case里加return

执行到return语句直接退出程序

***************

break(能够在switch和循环中用)

跳出switch

break 和return区别

break 是跳出switch体

return是跳出这个函数

(main函数也是函数,若是main()函数里

执行到return,表明程序的结束)

循环语句

for(循环的初始化;循环控制部分;循环的修改部分)

{

循环主体;

}

for

循环初始部分……为循环变量附初值

循环控制部分……按照循环条件控制循环正常进行

循环的修改部分……循环执行中,循环变量按照必定规律变化

循环体(工做部分)……要屡次循环的代码部分

#include

int main(void)

{

int i = 0;//循环变量

int sum = 0;

for(i = 0; i <= 100; i++)

//i = 0循环的初始部分为循环变量赋初值

//i <= 100循环的控制部分,控制循环的进行

//i++循环的修改部分,修改循环变量

//sum += i循环体,循环的主体

{

sum += i;

}

printf("sum = %d\n", sum);

return 0;

}

其余形态

(1)

for(a = 0, b = 0; a != 3 && b != 3; a++, b++)

{

}

(2)

for(; ;)

{

须要循环的部分;

}

//死循环

(3)

for(a = 0; a < 10; a++)

{

for(b = 0; b < 10; b++)

{

}

}

随机函数

rand()//产生随机数

srand()//随机种子

int a = 0;

int b = 0;

srand(time(NULL));

//rand()     产生随机数

//srand()     随机种子

//time(NULL) 时间

//NULL       空

for(a = 0; a < 10; a++) //随机取出10个(50~100之内的数)

{

b = rand() % 50 + 50;

//rand() % 50      [0~49]范围

//rand() % 50 + 50   [50~99]范围

printf("b = %d\n", b);

}break

用来产生随机数的函数是rand();

若是产生100之内的随机数rand() % 100; [0 ~ 99]

若是产生3位的随机数rand() % 900; [0 ~ 899]

rand() % 900 + 100; [100 ~ 999]

若是产生-50 ~ 50随机数rand() % 100 - 50;

随机种子

随机种子的函数srand();

当在调用srand函数时须要把可变的因子放到srand参数中

可变的因子

获取时间的秒数time();

当调用时参数能够传NULL

time(NULL);

获取进程ID getpid();

当调用时,getpid的返回值当作可变因子便可

注意 :

1.随机种子函数只须要调用一次就够了

把随机种子的函数调用放到变量定义以后便可

跳转语句

goto

使用goto作循环

注意 :

1.goto使用灵活,能够轻易改变代码结构

2.goto 须要加标志(标志的命名要求与变量命名要求一致)

3.同名的标志不能重复出现

4.goto不能跨函数使用

5.标志名能够和变量名重复

#include

int main(void)

{

int flag = 100;

printf("world\n");

goto flag;

flag:

printf("hello\n");

return 0;

}

指针

1.指针是用来作什么的?

1>变量是用来存储数据的(数据会存储在内存当中)

2>指针是用来存储地址的(地址会存储在内存当中,以十六进制的形式展示给程序员)

2.指针的定义

type * name ;

数据类型 变量名;

int a ;

int * p ;

定义了int *类型的指针p; p是指针名int *是类型

1>由数字字母下划线组成,不能一数字开头

2>区分大小写

3>不能与C语言关键字重复

3.经过sizeof来测试

指针不管何种类型在当前机器中都占了8个字节

由于指针存的是地址,在64位系统中一个地址占64位,因此是8个字节

4.指针的赋值

变量名= 数值 ;

a = 100 ;

p = &a ;

5.指针的初始化

数据类型 变量名= 数值;

int a = 100 ;

int * p = &a ;

int * q = NULL ; NULL的ASCII是0x0,至关于给 指针q赋值0,*p并不为0,p指针没有实际的指向,*p是不存在的;

6.指针运算符

& 取地址的运算符

* 取值的运算符*后面必须是地址(或者能够表示为地址的东西)

7.指针的运算

指针支持加减法运算

指针

p + 1

p += 1

p++

偏移了几个字节和数据类型有关int * 偏移了4个字节;char *偏移了1个字节

不一样数据类型的指针在作加减法运算时,所偏移的字节数不一样,和指针自己要保存的变量的数据类型有关。

8.特性

1>不管何种类型的指针,所占字节数相同(和硬件/造做系统位数有关)

2>指针能够作加减法运算。

3>指针是用来操做变量的。

9.特殊指针

1>空类型的指针(无准确类型的指针/万能指针)

void *p; 强制类型转换

2>空指针(编译器不检查空指针)

指向空的指针

int *p = NULL;

3>野指针(编译器也不检查野指针//空指针会提示段错误,野指针段错误都不会报)

没有对象的指针就是野指针

防止使用野指针

释放完空间以后给指针指向空,让他变成空指针。

程序实例

#include

int main(void)

{

int a;

int *p; //p是指针

a = 100;

p = &a;

printf("a = %d\n", a);

printf("&a = %p\n", &a); ///打印地址

printf("p = %p\n", p); ///打印地址里存的值

printf("*p = %d\n", *p);

printf("===============================\n");

scanf("%d", p);

printf("a = %d\n", a);

printf("&a = %p\n", &a);

printf("p = %p\n", p);

printf("*p = %d\n", *p);

printf("===============================\n");

return 0;

}

野指针实例

#include

#include

int main(void)

{

/*

int *p = NULL;

*p = 100;

printf("*p = %d\n", *p);

*/

int *p = NULL;

p = malloc(sizeof(int)); //在堆内存空间中开辟了4个字节的空间,把首地址返回给指针p

*p = 100;

printf("p = %p\n", p);

printf("*p = %d\n", *p);

free(p);

p = NULL; //防止使用野指针

printf("p = %p\n", p);

*p = 200; /使用野指针

printf("*p = %d\n", *p); //会打印出正确结果

printf("p = %p\n", p); //会打印出正确结果

return 0;

}

二级指针

二级指针用来操做一级指针

1.二级指针是用来存储一级指针的地址

2.二级指针的定义

数据类型 变量名;

int a ;

int * p ;

int ** pp ;

名a p pp

值100 0x1000 0x2000

a &a &a

*p p pp

**pp **pp

址0x1000 0x2000 0x3000

&a &p &pp

p pp

*pp

一级指针是用来操做变量的

二级指针是用来操做地址的

函数指针

把代码中重复使用的功能封装成函数,未来直接调用

指针是用来操做变量的

当函数调用时,传变量名作不到修改变量,能够传遍量的地址,用指针接收

调用函数时传参方式

值传递 若是只是使用参数的值,用值传递

地址传递 若是想要改变参数的值,用地址传递

return 返回值

返回值

计算的结果

函数执行的状态

0 完美运行

正数 表明函数执行异常

负数 表明函数执行错误

数组(arrary)

1.什么是数组

相同类型变量的集合

数组是由一个一个成员组成的,每一个成员的类型都是相同的

2.数组的定义

数据类型 数组名[成员个数] ;

int arr [5] ;

数组中一共有5个成员,分别是:arr[0],arr[1]...arr[4]

每一个成员都是int类型

注意:数组在定义时[] 中写的是成员个数,

当使用数组时可使用数组名 + 下标的方式来访问,下标是从0开始的

3.数组的使用

从某种意义上来说, * 取值运算符[]下标运算符 是相等的

int arr[6] = {11,22,33,44,55,66};

想要取出值为44的成员

1>数组名+下标arr[3];

2>数组名+偏移量*(arr + 3);

3>指针+偏移量*(p + 3);

4>指针+下标p[3];

5>下标+数组名3[arr]; //老版本经常使用

4.数组的特性

1>sizeof(数组名) =整个数组的大小

sizeof(数组名) / sizeof(一个成员大小) =数组成员个数

int arr[4];

sizeof(arr[0]) = 4;

sizeof(arr) = 16;

sizeof(arr) / sizeof(arr[0]) = 4; //数组成员个数

2>数组中每一个成员占用相同大小的空间,而且地址是连续的

能够经过某个成员的地址进行地址偏移,找到其余的成员

3>一维数组的数组名至关因而数组首成员的地址

4>数组名不是指针

指针能够自增,但数组名不行arr++ error p++

指针是能够自增运算或者保存变量的地址的,但

数组名作不了自增运算也保存不了变量的地址

5.数组的初始化

数据类型 数组名[成员个数] = {数值,数值...} ;

int arr [5] = {11,12,13,14,15};

int arr [5] = {0}; //数组中每一个成员都是0

int arr [5] = {11}; //只有第一个成员是11,其余成员都是0

int arr [5] = {,22,44,66,}; //error,逗号处报错

int i = 5;

int arr [i] = {11,22,33,44,55}; //不一样平台不一样标准会有不同的结果,有的会报错。尽可能不要这么使用

int arr [] = {11,22,33,44,55}; //会把后面的数值个数看成成员个数

&arr[0] 描述的是数组首成员的地址

arr 描述的是数组首成员的地址

&arr 描述的是整个数组的地址

注意:

1.若是在封装函数时不想要经过函数的形参修改实参的值

能够在声明函数时在形参的类型前面加const关键字修饰

2.在函数声明时或者函数实现的形参中出现数组的写法都是指针

形参是用来接收实参的值,实参是一个地址,形参只能用指针来接收

3.数组不要越界使用,编译器是不检查数组越界的(定义几个成员,就用几个成员,不要多用)

程序实例

#include

void print(const int *, int);

void change(int arr[5], int);

void print(const int *p, int num)

{

int i;

for(i = 0; i < num; i++)

{

printf("p[%d] = %d\n", i, p[i]);

}

}

void change(int arr[5], int num)

{

int i;

arr++;

arr--;

printf("sizeof(arr) = %ld\n", sizeof(arr));

for(i = 0; i < num; i++)

{

scanf("%d", arr + i);

}

}

int main(void)

{

int arr[5] = {0};

print(arr, sizeof(arr) / sizeof(*arr)); //经过print函数打印数组中每一个成员的值

change(arr, sizeof(arr) / sizeof(*arr)); //经过change函数录入数组中每一个成员的值

print(arr, sizeof(arr) / sizeof(*arr));

return 0;

}

字符数组和字符指针

1.含义

字符数组:是用来存储多个数据(字符)

字符指针:是用来存储地址的

2.定义

char arr[10];

char *p;

3.初始化

char arr[5] = {‘h’, 'e', 'l', 'l', 'o'};

//这让的数组打印不能使用%s打印,由于%s只有在碰到‘\0’时才会结束

char arr[5] = {11, 22, 33, 44, 55};

char arr[5] = {0}; //全部成员都是0

char arr[5] = {'0'};    //只有第一个成员的值是48,其余成员都是0

char arr[5] = {'\0'}; //全部成员都是0

--------------------------------------------------------------

char arr[10] = "hello";

char *p = NULL;     //指针指向空

char *p = "guojing";     //指针p保存的是“guojing”这个 字符串常量的首地址

char arr[10] = "yangguo"; //数组中每一个成员保存字符串中的每一个字符

把'y'保存到arr[0]中

把'a'保存到arr[1]中

...

把'\0'保存到arr[7]中

把'\0'保存到arr[8]中

把'0'保存到arr[9]中

4.操做

char arr[10] = {0};

char *p = NULL;

arr = "guojing"; //字符数组不能操做,编译器会报错

p = “guojing”; //字符指针能够操做,保存了“guojing”字符串常量的首地址

arr[2] = 'A'; //字符数组能够操做,经过数组名+下标改为员的值。将数组2号空间保存的‘a’修改成‘A’

p[2] = 'A'; //字符指针不能操做,由于p保存的是 字符串常量 的首地址

当指针和数组产生关系,指针表示的是数组的首地址,就能够完成上面的操做

5.注意

1>当经过scanf("%c")的方式给字符数组录入字符时须要注意回车,

由于回车会被看成换行符,保存到数组中

2>当经过scanf("%s")的方式个字符数组录入字符时 空格 至关于 尾0

指针保存的字符串地址地址在常量区,const修饰的变量不在常量区

变量、数组...在栈区

6.程序实例

#include

#include

int main(void)

{

char arr[10] = "yangguo";

printf("arr = %s\n", arr);

arr[2] = 'A';

printf("arr = %s\n", arr);

/*

char *p = "yangguo"; //字符指针保存了字符串常量的首地址

printf("p = %s\n", p); //经过字符指针访问字符串常量

p[2] = 'A'; //经过字符指针想要修改字符串常量中的数据(段错误)

printf("p = %s\n", p);

*/

return 0;

}

string一族函数

strcpy strcat strcmp strlen

函数的声明

函数的返回值的类型 函数名(参数列表); //参数是形参,形参是用来接收实参的值

函数的实现

函数的返回值的类型 函数名(参数列表)

{

函数的主体

}

函数的调用

函数名(参数);//参数是实参,实参把值传递给形参

string一族函数实现

#include

char *mystrcpy(char *dest, const char *src); //能够利用字符串的结束标志'\0'

char *mystrcat(char *dest, const char *src);

int mystrcmp(const char *s1, const char *s2);

size_t mystrlen(const char *s);

char *mystrcpy(char *dest, const char *src)

{

int i = 0;

for(i = 0; src[i] != '\0'; i++)

dest[i] = src[i];

dest[i] = src[i];

return dest;

}

char *mystrcat(char *dest, const char *src)

{

int i = 0, j = 0;

for(i = 0; dest[i] != '\0'; i++); //空循环,只是为了找dest的'\0'的位置

for(j = 0; src[j] != '\0'; i++, j++)

dest[i] = src[j];

dest[i] = src[j];

return dest;

}

int mystrcmp(const char *s1, const char *s2)

{

int i = 0;

for(i = 0; s1[i] == s2[i] && s1[i] != '\0'; i++);

//for的退出条件两个1.两个字符串找到了不相同的字符2.两个字符串碰到了'\0'

return s1[i] - s2[i];

}

size_t mystrlen(const char *s)

{

int i = 0;

for(i = 0; s[i] != '\0'; i++);

return i;

}

int main(void)

{

char dest[20] = "hello";

char *src = "world";

//printf("dest = %s\n", dest);

//printf("mystrcpy = %s\n", mystrcpy(dest, src)); //经过mystrcpy完成字符串拷贝

printf("mystrcat = %s\n", mystrcat(dest, src));

//printf("mystrcmp = %d\n", mystrcmp(dest, src));

printf("mystrlen = %ld\n", mystrlen(dest));

//printf("dest = %s\n", dest);

return 0;

}

内核方式实现string一族函数

#include

#include

char *mystrcpy(char *dest, const char *src); //能够利用字符串的结束标志'\0'

char *mystrcat(char *dest, const char *src);

int mystrcmp(const char *s1, const char *s2);

size_t mystrlen(const char *s);

char *mystrchr(const char *s, int c);

char *mystrcpy(char *dest, const char *src)

{

char *save = dest;

while(*dest++ = *src++);

return save;

}

char *mystrcat(char *dest, const char *src)

{

int i = 0, j = 0;

for(i = 0; dest[i] != '\0'; i++); //空循环,只是为了找dest的'\0'的位置

for(j = 0; src[j] != '\0'; i++, j++)

dest[i] = src[j];

dest[i] = src[j];

return dest;

}

int mystrcmp(const char *s1, const char *s2)

{

int i = 0;

for(i = 0; s1[i] == s2[i] && s1[i] != '\0'; i++);

//for的退出条件两个1.两个字符串找到了不相同的字符2.两个字符串碰到了'\0'

return s1[i] - s2[i];

}

size_t mystrlen(const char *s)

{

const char *sr = s;

while(*++sr);

return sr - s;

}

char *mystrchr(const char *s, int c)

{

int i = 0;

for(i = 0; s[i] != c && s[i] != '\0'; i++);

return s[i] == c ? (char *)(s + i) : NULL;

}

char *mystrrchr(const char *s, int c)

/*

定义一个指针sp保存s的值,sp找到字符串'\0'

从'\0'的前一个字符查找c

直到找到了或者sp == s

*/

{

const char *p = s + strlen(s);//p指针保存的是最后一个字符的地址

do

{

if(*p == c)

return (char *)p;

}while(--p >= s);

return NULL;

}

int main(void)

{

char dest[10] = "hello";

char *src = "zack:x:1000:1000:zack,,,:/home/zack:/bin/bash";

char *ret = NULL;

//printf("dest = %s\n", dest);

//printf("mystrcpy = %s\n", mystrcpy(dest, src)); //经过mystrcpy完成字符串拷贝

//printf("strcpy = %s\n", strcpy(dest, src)); //经过mystrcpy完成字符串拷贝

//printf("mystrcat = %s\n", mystrcat(dest, src));

//printf("mystrcmp = %d\n", mystrcmp(dest, src));

//printf("mystrlen = %ld\n", mystrlen(dest));

//printf("dest = %s\n", dest);

//printf("strchr = %s\n", strchr(src, ';'));

ret = mystrchr(src, ':');

if(ret == NULL)

printf("Not Find It!\n");

else

printf("ret = %s\n", ret);

return 0;

}

变量的使用和存储方式程序实例

变量

局部变量能够和全局变量重名

若是函数中没有局部变量,使用的是全局变量

若是函数中有局部变量,使用的是局部变量

#include

int a = 100;

/*

存储区域 全局区

做用域 整个程序中有效

生命周期 程序结束会被释放

*/

void func_1(void)

{

printf("func_1.a = %d\n", a);

}

void func(void)

{

int a = 200;

/*

存储区域 栈区

做用域func函数内有效

生命周期 函数结束会被释放

*/

printf("func.a = %d\n", a);

}

int main(void)

{

int a = 300;

/*

局部变量

存储区域    栈区

做用域      main函数内有效

生命周期    函数结束会被释放

*/

printf("main.a = %d\n", a);

func();

func_1();

{

int a = 400;

/*

块级变量

存储区域 栈区

做用域 块内有效

生命周期 当跳出块内被释放

*/

printf("main{}.a = %d\n", a);

}

printf("main.a = %d\n", a);

return 0;

}

实现atoi

#include

#include

int myatoi(const char *nptr);

int myatoi(const char *nptr)

{

int i = 0;

int ret = 0;

int flag = 1;

for(i = 0; nptr[i] == ' '; i++);

if(nptr[i] == '+' || nptr[i] == '-')

flag = nptr[i++] == '+' ? 1 : -1;

for(; nptr[i] != '\0'; i++)

{

switch(nptr[i])

{

case '0' : case '1' : case '2' :

case '3' : case '4' : case '5' :

case '6' : case '7' : case '8' :

case '9' :

ret *= 10;

ret += nptr[i] - '0';

break;

default : return ret * flag;

}

}

return ret * flag;

}

int main(void)

{

int num = 0;

num = myatoi("456abc123");

printf("num = %d\n", num);

return 0;

}

///sprintf 至关于itoa

va_arg例子

可变参数列表的函数

未来实现的功能函数客户在使用时,不肯定传参个数,就能够

声明可变参数列表的函数

va_list ap;

va_list 类型的变量,存储了有关额外参数和检索状态的信息

#include

#include

int add(int num_args, ...);//num_args是须要几个整数加法运算

int add(int num_args, ...)

{

int val = 0;

va_list ap;//

int i = 0;

va_start(ap, num_args);

for(i = 0; i < num_args; i++)

val += va_arg(ap, int);

va_end(ap);

return val;

}

int main(void)

{

int sum = 0;

sum = add(10, 1, 2, 3, 4, 5, 6 ,7 ,8 ,9 ,10);

//前面的10是后面参数个数, 1 2 3 ...想要相加的数字

printf("sum = %d\n", sum);

return 0;

}

实现printf

须要使用

putchar

putc

puts

函数替换

printf

#include

#include

int myprintf(const char *format, ...);

int myprintf(const char *format, ...)

{

va_list ap;

int d;

char c, *s;

float f;

va_start(ap, format);

while(*format)//format = "hello world!";

{

if(*format == '%')

{

format++;

switch(*format)

{

case 'd' : d = va_arg(ap, int);

printf("%d", d);

break;

case 's' : s = va_arg(ap, char *);

printf("%s", s);

break;

case 'c' : c = (char) va_arg(ap, int);

printf("%c", c);

break;

case 'f' : f = (float)va_arg(ap, double);

printf("%f", f);

break;

}

}

else

putchar(*format);

format++;

}

}

int main(void)

{

myprintf("hello world!");

//myprintf("%d-%s-%c-%f\n", 100, "hello world", 'A', 3.14);

return 0;

}

static

static是C语言中的关键字

static用来修饰静态的

static关键字的功能

1.仅限于当前文件使用(隐藏)

全部未加static关键字修饰的全局变量,对于其余文件来讲都是可见的

若是在全局变量名前面加static关键字修饰的话,能够在不一样的文件中定义相同的全局变量名,不受影响

2.保持局部变量的生命周期

若是局部变量不加static关键字修饰,变量存储在栈区中,函数结束就被释放

若是局部变量加static关键字修饰,变量存储在静态区中,当程序结束时会被释放

局部变量前加static关键字修饰,只在第一次调用时初始化,也是惟一的一次初始化

在静态区会存储 : 全局变量和static关键字修饰的变量

3.被static关键字修饰的变量或者数组默认初始化的值为0

程序实例

#include

int main(void)

{

static int arr[10];

int i = 0;

for(i = 0; i < 10; i++)

{

printf("arr[%d] = %d\n", i, arr[i]);

}

return 0;

}

/

运行结果:

arr[0] = 0;

arr[1] = 0;

arr[2] = 0;

...

arr[9] = 0;

局部变量用static修饰只初始化一次

被static关键字修饰的变量或者数组默认初始化的值为0

/

#include

void func(void)

{

static int i = 10; //静态的局部变量

int a = 10; //局部变量(当函数执行结束时被释放)

i++;

a++;

printf("i = %d a = %d\n", i, a);

}

int main(void)

{

func();

func();

func();

func();

return 0;

}

/

运行结果:

i = 11 a = 11

i = 12 a = 11

i = 13 a = 11

i = 14 a = 11

/

工程文件实例

func.h

#ifndef __FUNC_H

#define __FUNC_H

int add(int , int );

#endif

/*

3行预处理是为了防止头文件被重复包含

*/

func.c

#include "func.h"

int add(int a, int b)

{

return a + b;

}

main.c

/*

第三阶段

多文件编程

main.c main函数和功能函数的调用

func.c 功能函数的实现

func.h 功能函数的声明

makefile 编译规则

*/

#include

#include "func.h"

int main(void)

{

int a = 13, b = 7;

int sum = 0;

sum = add(a, b);//功能函数的调用

printf("sum = %d\n", sum);

return 0;

}

makefile

main : main.o func.o

gcc -o $@ $^

# # 在makefile中表明注释

#   $   在makefile中表明引用变量

#   $@  表明上一句话:以左的内容

#   $^  表明上一句话:以右的内容

clean :

rm -rf *.o main

#   在makefile中注释使用的是#

#   在第一行须要写最终生成的可执行文件的名字    最终生成的可执行文件:依赖    的文件

#   在第二行须要写使用的工具(必需要写tab)

#   最后的clean :是清除工具,当执行make clean会把

#   全部的.o文件和可执行文件都删掉(还原到最初的文件)

#   当在终端中想要执行编译,直接make就能够

makefile

main : main.o func.o

gcc main.o func.o -o main

clean :

rm -rf *.o main

程序实例

func.c

#include "func.h"

int a;

void func(void)

{

a++;

}

func.h

#ifndef __FUNC_H

#define __FUNC_H

void func(void);

#endif

main.c

#include

#include "func.h"

int a = 100;

int main(void)

{

printf("a = %d\n", a);

func();

func();

func();

func();

printf("a = %d\n", a);

return 0;

}

//104

func.h

#ifndef __FUNC_H

#define __FUNC_H

void func(void);

#endif

func.c

#include "func.h"

int a;

void func(void)

{

a++;

}

main.c

/*

若是全局变量加上static关键字修饰,当前的全局变量和其余文件的全局变量不相同

*/

#include

#include "func.h"

static int a = 100;

int main(void)

{

printf("a = %d\n", a);

func();

func();

func();

func();

printf("a = %d\n", a);

return 0;

}

100     100

func.h

#ifndef __FUNC_H

#define __FUNC_H

void func(void);

#endif

func.c

#include

#include "func.h"

char c = 'A';

void func(void)

{

printf("hello world!\n");

}

main.c

/*

全局变量

优势

当项目工程是多文件的时候,定义全局变量减省函数传参的麻烦

缺点

当其余.c文件定义的全局变量和它同名,会有影响

*/

#include

#include "func.h"

char c;

int main(void)

{

func();

printf("c = %c\n", c);

return 0;

}

//

运行结果:

hello world

c = A

//

函数

函数名 : 就是函数的入口地址(函数名就是地址,能够打印函数名,打印出地址)

1.函数与函数的关系 调用与被调用的关系

main函数调用功能函数

功能函数能够调用功能函数

2.功能函数调用main函数

会形成栈区破裂(段错误,核心以转储)

3.功能函数本身调用本身(函数递归)

注意:要最早写退出条件

函数递归

注意 : 递归的退出条件

看别人写的递归时,只调用两,三次便可

#include

int func(int num)

{

if(num == 1)

return 1;

return num + func(num - 1);

}

int main(void)

{

int sum = 0;

sum = func(3);

printf("sum = %d\n", sum);

return 0;

}

程序实例

/*

12345

倒叙打印出来

54321

*/

#include

void func(int num)

{

if(num == 0)

return ;

printf("%d", num % 10);

func(num / 10);

}

int main(void)

{

func(12345);

printf("\n");

return 0;

}

itoa

/*

实现itoa

sprintf能够代替itoa的功能

*/

#include

void itoa(int data, char str[]);

void itoa(int data, char str[])//123

{

int i = 0;

if(data < 10)

{

str[0] = data + '0';

str[1] = '\0';

return ;

}

itoa(data / 10, str);

for(i = 0; str[i] != '\0'; i++);

str[i] = data % 10 + '0';

str[i + 1] = '\0';

}

int main(void)

{

char buf[10] = {0};

int num = 0;

scanf("%d", &num);

itoa(num, buf);

printf("buf = %s\n", buf);

return 0;

}

存储区域介绍

代码区

管不了

栈区

系统帮助程序员管理

不须要程序员本身开辟空间,释放空间

自动释放

堆区

malloc->free

zalloc->free

程序员须要本身管理的内存空间

本身开辟,本身释放

申请和释放都是程序员管理

(忘记释放会使内存耗尽)

全局区

全局变量

常数区

程序结束才会释放

(char *p1 = NULL;)

(p1 = "abc";)

内存    真实存储4G

只用内存真实空间4K

虚拟内存4G

1G kernel(内核)

--------------------

3G environment/cmd环境变量(系统设定的全局变量)和命令->argc argv

int main(int argc, char *argv[])

栈向下 从高地址到低地址

堆向上 从低地址到高地址

.bss 静态存储区(全局变量,静态变量) !未初始化

.date 初始化的 不为0                 !已初始化

RO date 只读数据段

text 代码段

.bss存在可执行文件中

.date不存在可执行文件中

makefile

一个工程中的源文件不可胜数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件须要先编译,哪些文件须要后编译,哪些文件须要从新编译,甚至于进行更复杂的功能操做,由于makefile就像一个Shell脚本同样,其中也能够执行操做系统的命令。

可变参的函数

stdarg.h 头文件中定义了一个变量类型va_list和三个宏定义,

这三个宏定义可用于在参数个数未知(即参数个数可变)时获取函数中的参数.

可变参数的函数一般在参数列表的末尾时使用省略号(...)定义的.

va_list是一个类型

适用于 va_start(),va_arg() 和va_end()这三个宏存储信息

void va_start(va_list ap, last_arg)

这个宏初始化 ap 变量,它与va_arg和va_end宏是一块儿使用的.

last_arg 是最后一个传递给函数的已知的固定参数,即省略号以前的参数.

例子:

int printf(const char *format, ...); 中的format

int ioctl(int fd, unsigned long request, ...); 中的request

type va_arg(va_list ap, type)

这个宏检索函数参数列表中类型为 type 的参数.

void va_end(va_list ap)

这个宏容许使用了 va_start 宏的带有可变参数的函数返回

若是在从函数返回以前没有调用 va_end,则结果为未定义.

const

const是C语言中的关键字

const是用来修饰只读(read only)的

当const关键字修饰变量时,变量名变成只读的了,

只能经过变量名读取内存空间的数据而不能经过变量名来修改(能够经过指针来修改)

const关键字修饰的变量名

写法 const int a; 或者int const a;

volatile是一个关键字

volatile是为了防止编译器优化

----------------------------

底层操做硬件时常常会用

volatile int led_status;//led_status是用来控制led灯的亮灭(0灯亮1灯灭)

led_status = 1;//编译器会优化

led_status = 0;

----------------------------

程序实例

#include

int main(void)

{

volatile const int a = 100;

int *p = &a;

printf("a = %d\n", a);

//a = 200; //不能修改,会报错

*p = 200;

printf("a = %d\n", a);

return 0;

}

常量指针

指针指向常量(指向常量的指针)

定义 :

const int *p;

const char *src;

或者

int const *p;

char const *src;

*p或者*src被const关键字修饰,只能经过*p或者*src读取指向空间的数据

可是不能经过*p或者*src修改指向空间的值

常量指针是能够改变指针的指向

程序实例

#include

int main(void)

{

int a = 100;

int b = 200;

const int *p = &a;

char const *src = NULL;

/*

printf("a = %d\n", a);

*p = 200;*p是read only,因此不能经过*p修改指向空间的值

printf("a = %d\n", a);

*/

printf("*p = %d\n", *p);

p = &b;

printf("*p = %d\n", *p);

return 0;

}

指针常量

指针是常量

定义

int * const p;

char * const src;

特色

指针p被const关键字修饰,意味着p指针的指向不能改变,可是能够经过*p

改变指向空间的值

程序实例

#include

int main(void)

{

int a = 100;

int b = 200;

int * const p = &a;

/*

printf("a = %d\n", a);

*p = 200;能够修改

printf("a = %d\n", a);

*/

printf("*p = %d\n", *p);

p = &b; //不能够

printf("*p = %d\n", *p);

return 0;

}

指针数组

是一个数组,数组中的每个成员都是相同类型的指针

定义

数据类型 数组名[成员个数] ;

int arr [5] ; //5个成员arr[0] ~ arr[4],每一个成员都是int类型

char str [20] ; //20个成员str[0] ~ str[19]

int * arr [5] ; //5个成员arr[0] ~ arr[4],每一个成员都是int *类型

char * argv [4] ; //4个成员argv[0] ~ argv[3],每一个成员都是char *

命令行参数

int main(int argc, char *argv[]);

当在终端中执行./a.out就至关于调用main函数

main函数的参数有两个argc和argv

argc 统计命令行参数的个数

argv argv中的每一个成员指向命令行参数中的每一个字符串

程序实例

#include

int main(void)

{

int a, b, c, d;

int *arr[4];

int i = 0;

arr[0] = &a;

arr[1] = &b;

arr[2] = &c;

arr[3] = &d;

for(i = 0; i < 4; i++)

{

scanf("%d", arr[i]);

}

printf("a = %d b = %d c = %d d = %d\n", a, b, c, d);

return 0;

}

#include

int main(int argc, char *argv[])

{

int i = 0;

printf("argc = %d\n", argc);

for(i = 0; i < argc; i++)

{

printf("argv[%d] = %s\n", i, argv[i]);

}

return 0;

}

数组、指针区别

#include

#include

int main(void)

{

char *str[3] = {

"hello world",

"hello China",

"uplooking"

};

/*

定义的str是指针数组,有3个成员,每一个成员为char *类型

str[0] ~ str[2]这3个成员每一个成员获取一个字符串常量的首地址,意味着都指向常量区

*/

char arr[3][20] = {

"hello world",

"hello China",

"uplooking"

};

/*

定义的arr是(字符)二维数组,有60个成员,每一个成员为char类型

二维数组中的每个成员都会获取字符串中的一个字符进行保存

*(arr[1] + 2) = 'L';

*/

int i = 0;

/*==================区别一=================*/

printf("sizeof(str) = %ld\n", sizeof(str)); //24

printf("sizeof(arr) = %ld\n", sizeof(arr)); //60

/*=========================================*/

/*==================区别二=================*/ //运行结果相同

for(i = 0; i < 3; i++)

{

printf("str[%d] = %s\n", i, str[i]);

}

for(i = 0; i < 3; i++)

{

printf("arr[%d] = %s\n", i, arr[i]);

}

/*=========================================*/

/*==================区别三=================*/ //运行结果相同

for(i = 0; i < 3; i++)

{

printf("strlen(str[%d]) = %ld\n", i, strlen(str[i]));

}

for(i = 0; i < 3; i++)

{

printf("strlen(arr[%d]) = %ld\n", i, strlen(arr[i]));

}

/*=========================================*/

/*==================区别四=================*/

//printf("str[1] = %s\n", str[1]);

//*(str[1] + 2) = 'L';//str[1]成员指向的是常量区

//printf("str[1] = %s\n", str[1]);

printf("arr[1] = %s\n", arr[1]);

*(arr[1] + 2) = 'L';//str[1]成员指向的是常量区

printf("arr[1] = %s\n", arr[1]);

/*=========================================*/

return 0;

}

#include

int main(void)

{

char arr[10] = "uplooking";

char *p = "uplooking";

/*

arr数组和p指针都保存在栈区中

只不过指针p保存的是字符串常量的首地址

或者指针p保存的是常量区的一个地址

*/

return 0;

}

指针数组的定义

type *arr_name[arrnum];

int *arr[4];

char *argv[4];

数组指针

是一个指针,指向数组(二维数组)的指针

定义

type (*point_name)[arrnum];

int (*p)[4];

定义了一个数组指针p,指针p应该指向一行有4个成员,每一个成员为int类型的数组

程序实例

#include

int main(void)

{

int arr[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};

int (*p)[4];

int i, j;

p = arr;

for(i = 0; i < 3; i++)

{

for(j = 0; j < 4; j++)

{

//printf("arr[%d][%d] = %d\n", i, j, arr[i][j]);

//printf("*(*(arr + %d) + %d) = %d\n", i, j, *(*(arr + i) + j));

//printf("p[%d][%d] = %d\n", i, j, p[i][j]);

printf("*(*(p + %d) + %d) = %d\n", i, j, *(*(p + i) + j));

}

}

return 0;

}

#include

void print(const int (*p)[4]);

void change(int (*p)[4]);

void print(const int (*p)[4])

{

int i, j;

for(i = 0; i < 3; i++)

{

for(j = 0; j < 4; j++)

{

printf("p[%d][%d] = %d\n", i, j, p[i][j]);

}

}

}

void change(int (*p)[4])

{

int i, j;

for(i = 0; i < 3; i++)

{

for(j = 0; j < 4; j++)

{

scanf("%d", &p[i][j]);

}

}

}

int main(void)

{

int brr[2][4] = {11,22,33,44,55,66,77,88};

int arr[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};

print(arr);//经过print函数遍历二维数组arr

change(arr);//经过change函数改变二维数组arr成员的值

print(arr);

return 0;

}

typedef

typedef是C语言中的关键字

使用typedef来定义类型,或者给已有的数据类型取别名

使用方法

typedef 已有的数据类型 别名; //最后必需要有分号;

typedef int abc; //凡是用abc类型定义的变量都是int类型

typedef struct stu

{

int id;

char name[20];

int math;

}STU;

STU a;

*/

程序实例

#include

typedef int abc;

int main(void)

{

abc a = 100;

printf("a = %d\n", a);

printf("sizeof(a) = %ld\n", sizeof(a));

printf("sizeof(abc) = %ld\n", sizeof(abc));

//printf("sizeof(abcd) = %ld\n", sizeof(abcd)); 会报error abcd未定义

return 0;

}

typedef int arr_type[5];

#include

typedef int arr_type[5];

/*

typedef int[5] arr_type;

*/

int main(void)

{

arr_type a = {11,22,33,44,55};

int i = 0;

printf("sizeof(a) = %ld\n", sizeof(a)); //20

printf("sizeof(arr_type) = %ld\n", sizeof(arr_type)); //20

printf("a = %p\n", a); //

printf("a + 1 = %p\n", a + 1); //+4

for(i = 0; i < 5; i++)

{

printf("a[%d] = %d\n", i, a[i]);

}

return 0;

}

#include

typedef int (*Arr_Point)[4]; //定义了数组指针类型

/*

typedef int(*)[4] Arr_Point;

*/

int main(void)

{

int arr[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};

//想要定义指针和数组产生关系

Arr_Point p = arr;//用数组指针类型定义的变量都是数组指针

int i, j;

for(i = 0; i < 3; i++)

{

for(j = 0; j < 4; j++)

{

printf("p[%d][%d] = %d\n", i, j, p[i][j]);

}

}

return 0;

}

#include

int main(void)

{

int *arr[3];

int (*p)[3];

printf("sizeof(arr) = %ld\n", sizeof(arr));

//指针数组的大小=一个成员的大小*成员个数24

printf("sizeof(p) = %ld\n", sizeof(p));

//数组指针的大小=8;不管何种指针在当前机器上测试出来的都是8个字节

return 0;

}

指针函数

是一个函数,函数的返回值是一个指针

char *strcpy(char *dest, const char *src);

char *strcat(char *dest, const char *src);

void *malloc(size_t size);

FILE *fopen(const char *path, const char *mode);

上述函数都是指针函数

*/

#include

int *func(void)

{

int a = 100;//a变量是一个局部变量,当函数执行结束后被释放

return &a;

}

int main(void)

{

int *p = NULL;

p = func();

printf("p = %p\n", p); //p = (nil)

printf("*p = %d\n", *p); //段错误

return 0;

}

功能函数内定义数组,想要返回数组

#include

int *func(void)

{

static int arr[5] = {11,22,33,44,55}; //局部变量

return arr;

}

int main(void)

{

int *p = NULL;

int i = 0;

p = func();

for(i = 0; i < 5; i++)

{

printf("p[%d] = %d\n", i, p[i]);

}

return 0;

}

函数指针

int *func(int a, int b);

函数指针

是一个指针,指向函数的指针

定义

int (*p)(int ,int);

定义了函数指针p,指针p指向函数的返回值为int类型,参数为int,int,这样的函数

#include

int add(int a, int b)

{

return a + b;

}

int sub(int a, int b)

{

return a - b;

}

int main(void)

{

int a = 13, b = 7;

int (*p)(int,int);

p = add;

printf("a + b = %d\n", p(a, b));

p = sub;

printf("a - b = %d\n", p(a, b));

return 0;

}

/*

typedef void (*sighandler_t)(int);

typedef void (*)(int) sighandler_t;

sighandler_t p;

*/

#include

typedef int (*Func_Point)(int ,int);

int add(int a, int b)

{

return a + b;

}

int sub(int a, int b)

{

return a - b;

}

int main(void)

{

int a = 13, b = 7;

Func_Point p, q;

p = add;

printf("a + b = %d\n", p(a, b));

q = sub;

printf("a - b = %d\n", q(a, b));

return 0;

}

回调函数

#include

#include

#include

void func(int none)

{

printf("No I Don't Even Like You A Little Bit!\n");

sleep(1);

//alarm(1);

}

int main(void)

{

signal(SIGALRM, func);

alarm(1);

while(1)

{

printf("Hey! Girl You Like Me Little Bit?\n");

sleep(1);

}

return 0;

}

函数指针数组

是一个数组,数组中的每个成员都是函数指针

定义

int (*arr[4])(int , int);

定义了一个函数指针数组,数组中有4个成员,arr[0] ~ arr[3],每一个成员都是函数指针

指向函数返回值为int类型,参数为int int的函数

#include

typedef int (*Func_Point)(int, int);

int add(int a, int b)

{

return a + b;

}

int sub(int a, int b)

{

return a - b;

}

int mul(int a, int b)

{

return a * b;

}

int div(int a, int b)

{

return a / b;

}

int main(void)

{

int a = 13, b = 7;

Func_Point arr[4];

int i = 0;

arr[0] = add;

arr[1] = sub;

arr[2] = mul;

arr[3] = div;

for(i = 0; i < 4; i++)

{

printf("arr[%d] = %d\n", i, arr[i](a, b));

}

return 0;

}

结构体

1.定义结构体

为了定义结构,必须使用struct关键字

struct tag //tag是结构体标签

{

member-list; //member-list是结构体成员,通常来讲写的是定义(变量 数组 指针)

member-list;

member-list;

...

}variable-list; //variable-list是结构体类型的变量,定义在结构体的末尾,能够定义多个结构体类型的变量

注意 : 当定义完结构体以后必需要加;

2.定义结构体类型的变量

数据类型 变量名;

int a ;

struct stu s ;

3.结构体类型的变量访问成员

份量运算符. ->

变量名.成员名

指针->成员名

4.结构体类型的变量初始化

数据类型 变量名= {数值,数值};

struct stu s = {10086, "yidong", 59};

5.经过sizeof结构体测试

sizeof(结构体) =获得的是结构体的大小

是在成员大小的和的基础上作了字节对齐

6.结构体成员的地址

结构体的成员在存储空间中是连续的

程序实例

*/

#include

#include

struct stu

{

int id;

char name[20];

int math;

};

int main(void)

{

struct stu s, t;

s.id = 100;

//s.name = "xiaoming"; //error 由于name是字符数组的数组名

//strcpy(s.name, "xiaoming");

sprintf(s.name, "xiaoming");

s.math = 100;

t = s;

printf("t.id = %d\n", t.id);

printf("t.name = %s\n", t.name);

printf("t.math = %d\n", t.math);

return 0;

}

#include

#include

struct stu

{

int id;

char name[20];

int math;

};

int main(void)

{

struct stu t;

scanf("%d", &t.id);

scanf("%s", t.name);

scanf("%d", &t.math);

printf("t.id = %d\n", t.id);

printf("t.name = %s\n", t.name);

printf("t.math = %d\n", t.math);

return 0;

}

#include

#include

struct stu

{

long id;

char name[21];

int math;

};

int main(void)

{

printf("sizeof(struct stu) = %ld\n", sizeof(struct stu));

//40

return 0;

}

#include

#include

struct stu

{

//char a; //4

//int c; //4

//short b; //4一共12

};

int main(void)

{

printf("sizeof(struct stu) = %ld\n", sizeof(struct stu));

/0,由于结构体中都注释了,结构体为空

return 0;

}

struct stu

{

//char a; //2

//short b; //2

//int c; //4一共8字节

};

#include

#include

struct stu

{

int id;

char name[20];

int math;

};

int main(void)

{

struct stu s = {10010, "liantong", 59};

struct stu *p = &s; //sizeof(p) = 8;

printf("p->id = %d\n", p->id);

printf("p->name = %s\n", p->name);

printf("p->math = %d\n", p->math);

printf("&s = %p\n", &s); //

printf("&s.id = %p\n", &s.id); //与结构体地址相同

printf("s.name = %p\n", s.name); //+4

printf("&s.math = %p\n", &s.math); //+20

//printf("%d\n", (*p).id); //也能够这么用

scanf("%d", &p->id); /注意取地址

scanf("%s", p->name);

scanf("%d", &p->math);

printf("p->id = %d\n", p->id);

printf("p->name = %s\n", p->name);

printf("p->math = %d\n", p->math);

return 0;

}

#include

#include

struct wuxia

{

int wuli;

int zhili;

char name[20];

};

void print(const struct wuxia *p);

void change(struct wuxia *p); 注意传参

void print(const struct wuxia *p) ///

{

int i;

for(i = 0; i < 3; i++)

{

printf("武力值: %d\n", p[i].wuli);

printf("智力值: %d\n", p[i].zhili);

printf("姓  名: %s\n", p[i].name);

}

}

void change(struct wuxia *p)

{

int i;

for(i = 0; i < 3; i++)

{

scanf("%d", &p[i].wuli);

scanf("%d", &p[i].zhili);

scanf("%s", p[i].name);

}

}

int main(void)

{

struct wuxia arr[3] = { //只有初始化的时候能够这样赋值

{100, 100, "huangshang"},

{0, 0, "songbingjia"},

{59, 59, "luyoujiao"}

};

/*

int i = 0;

for(i = 0; i < 3; i++)

{

scanf("%d", &arr[i].wuli);

scanf("%d", &arr[i].zhili);

scanf("%s", arr[i].name);

}

*/

print(arr); //经过print函数遍历数组

change(arr); //经过change函数改变数组成员的值

print(arr);//打印

return 0;

}

老师笔记

定义方式

1.

struct

{

int a; //4

char b; //4

double c; //8

}s1;

//上述定义了拥有3个成员的结构体,分别为int的a,char的b和double的c

//同时又定义告终构体变量s1

//这个结构体并无标明其标签

2.

struct SIMPLE

{

int a;

char b;

double c;

};

//上述定义了拥有3个成员的结构体,分别为int的a,char的b和double的c

//结构体的标签被命名为SIMPLE,没有定义结构体类型的变量

struct SIMPLE t1, t2[20], *t3;

//用SIMPLE标签的结构体定义告终构体类型的变量t1结构体类型的数组t2结构体类型的指针t3

3.

typedef struct

{

int a;

char b;

double c;

}Simple2;

//也能够用typedef建立新类型

Simple2 u1, u2[20], *u3;

注意 :

在上面的结构体定义中和声明被编译器看成两个彻底不一样的类型,即便他们的成员列表是同样的,  ///

若是令 t3=&s1 是违法的操做,编译器会报警告/

定义结构体时,结构体的成员

1.

struct SIMPLE

{

int a;

char b;

double c;

};

struct COMPLEX

{

char string[100];

struct SIMPLE a;//结构体的成员是其余结构体类型的变量(能够和其余结构体类型的成员同名)

//由于struct COMPLEX结构体定义中存在struct SIMPLE结构体类型的成员

//因此应该把struct SIMPLE定义放到struct COMPLEX以前

};

2.

struct NODE

{

char string[100];

struct NODE *next_node;//结构体的成员是本身结构体类型的指针(通常来讲在链表或者树中常用)

};

3.若是两个结构体互相包含,则须要对其中一个结构体进行不完整声明,以下所示:

struct B; //对结构体B进行不完整声明

struct A

{

struct B *partner; //结构体A中包含结构体B类型的指针

//other members;

};

struct B

{

struct A *partner; //结构体B中包含结构体A类型的指针

//other members;

};

注意 :

当定义结构体时结构体的成员能够是其余结构体类型的变量

结构体的成员也能够是本身结构体类型的指针

固然不能够是本身结构体类型的变量

而一般本身结构体类型的指针的应用是为了实现一些更高级的数据结构如链表和树等.

/*共用体    联合 union*/

使用单块内存空间,管理不一样数据类型

占用的内存空间以共用体当中最大的为准

1.同一个内存段能够用来存放几种不一样类型的成员,可是在每一瞬间只能存放其中的一种,而不是同时存放几种。

换句话说,每一瞬间只有一个成员起做用,其余的成员不起做用.

2.共用体变量中起做用的成员是最后一次存放的成员,在存入一个新成员后,原有成员就失去做用

3.共用体变量的地址和它的各成员的地址都是同一地址.

4.共用体变量的初始化

(1)union data a=b; //把共用体变量初始化为另外一个共用体

(2)union data a={123}; //初始化共用体为第一个成员

(3)union data a={.ch='a'}; //指定初始化项目,按照C99标准

/*

共用体(联合)

须要使用C语言关键字union

1.定义共用体

union U

{

char c;

short s;

int i;

long l;

float f;

double d;

};

2.共用体的成员共用同一起存储空间

用一起存储空间管理不一样的数据类型

*/

#include

union U

{

int i;

float f;

};

struct stu

{

int id;

char name[20];

union U math;

};

int main(void)

{

struct stu s;

int mode = 0;

printf("Please Enter Your Id : ");

scanf("%d", &s.id);

printf("Please Enter Your Name : ");

scanf("%s", s.name);

printf("Please Enter Your Math(1.int 2.float) : ");

scanf("%d", &mode);

switch(mode)

{

case 1 : scanf("%d", &s.math.i); break;

case 2 : scanf("%f", &s.math.f); break;

}

printf("================================\n");

printf("Id : %d\n", s.id);

printf("Name : %s\n", s.name);

switch(mode)

{

case 1 : printf("Math : %d\n", s.math.i); break;

case 2 : printf("Math : %.1f\n", s.math.f); break;

}

return 0;

}

/*

经过共用体测试大端格式和小端格式

大端格式

高字节存放低地址

十六进制数据0x12345678

地址 存储空间

0x1000 0x12

0x1001 0x34

0x1002 0x56

0x1003 0x78

小端格式(X86平台)

低字节存放低地址

十六进制数据0x12345678

地址 存储空间

0x1000 0x78

0x1001 0x56

0x1002 0x34

0x1003 0x12

*/

#include

union U

{

int i;

char c[4];

};

int main(void)

{

union U u;

u.i = 13;  //00000000 00000000 00000000 00001101

printf("u.c[0] = %d\n", u.c[0]);

printf("u.c[1] = %d\n", u.c[1]);

printf("u.c[2] = %d\n", u.c[2]);

printf("u.c[3] = %d\n", u.c[3]);

return 0;

}

位域

有些信息在存储时,并不须要占用一个完整的字节,而只需占几个或一个二进制位.

例如存放一个开关量时,只有0和1两种状态,用1位二进位便可.

为了节省存储空间,并使处理简便,C语言提供了"位域"或"位段".

其实是把 一个字节 中的二进制位划分为几个不一样的区域,并说明每一个区域的位数.

每一个域有一个域名,容许在程序中按域名进行操做.这样就能够把几个不一样的对象用一个字节的二进制位域来表示.

struct 位域结构名

{

类型说明符 位域名: 位域长度;

...//省略

};

/*

位域

无符号类型

*/

#include

struct S

{

unsigned int a : 1;//a b c是位域名a会管理1位b会管理以后的2位c会管理以后的3位

unsigned int b : 2;

unsigned int c : 3;

};

union U

{

unsigned char x;

struct S s;

};

int main(void)

{

union U u;

u.x = 100;

printf("u.s.a = %d\n", u.s.a);

printf("u.s.b = %d\n", u.s.b); //

printf("u.s.c = %d\n", u.s.c); //这两行若是定义不是无符号的会打印负号,最高为是符号位,在单片机上都是无符号的,因此定义的时候要用unsigned

return 0;

}

/*

位域

无符号类型

位运算符<< >> & | ~ ^

寄存器

*/

#include

struct S

{

unsigned char a0 : 2;

unsigned char a1 : 2;

unsigned char a2 : 2;

unsigned char a3 : 2;

unsigned char a4 : 2;

unsigned char a5 : 2;

unsigned char a6 : 2;

unsigned char a7 : 2;

unsigned char a8 : 2;

unsigned char a9 : 2;

unsigned char a10: 2;

unsigned char a11: 2;

unsigned char a12: 2;

unsigned char a13: 2;

unsigned char a14: 2;

unsigned char a15: 2;

};

union U

{

unsigned int GPIOA_MODER;//一共32bit

struct S s;//有16个位域,每一个位域管理2个位

};

int main(void)

{

union U u;

u.s.a9 = 1;//如今想要把PA9管脚配置成输出模式

return 0;

}

枚举

enum

是一个被命名的整型常数的集合

枚举的说明与结构和联合类似, 其形式为:

enum 枚举名

{

标识符[=整型常数],

标识符[=整型常数],

...

标识符[=整型常数] //没有逗号

}枚举变量;

若是枚举没有初始化, 即省掉"=整型常数"时,则从第一个标识符开始,顺

次赋给标识符0, 1, 2, ...。但当枚举中的某个成员赋值后,其后的成员按依次

加1的规则肯定其值。

在枚举中标识符能够和变量同名

当在函数中使用时,用的是变量

#include

enum E

{

a,

b = 99,

c,

d

};

int main(void)

{

enum E x;

printf("a = %d\n", a); //0

printf("b = %d\n", b); //99

printf("c = %d\n", c); //100

printf("d = %d\n", d); //101

return 0;

}

#include

enum E

{

a,

b = 99,

c,

d

};

int main(void)

{

int z = 100;

enum E x = z;

printf("x = %d\n", x); //100

printf("a = %d\n", a); //0

printf("b = %d\n", b); //99

printf("c = %d\n", c); //100

printf("d = %d\n", d); //101

return 0;

}

/*

枚举

使用方法

1.使用枚举中的标识符做为case以后的整常量使用

enum A{HEADINSERT, TAILINSERT};

*/

#include

enum E

{

Mode_1,

Mode_2,

Mode_3

};

int main(void)

{

int mode = 0;

scanf("%d", &mode);

switch(mode)

{

case Mode_1 : printf("菜鸟难度!\n"); break;

case Mode_2 : printf("地狱难度!\n"); break;

case Mode_3 : printf("中国难度!\n"); break;

}

return 0;

}

/*

枚举

enum

在枚举中标识符能够和变量同名

当在函数中使用时,用的是变量

使用方法

1.使用枚举中的标识符做为case以后的整常量使用

enum A{HEADINSERT, TAILINSERT};

*/

#include

enum E

{

a,

b = 10,

c,

d

};

int main(void)

{

int i = 0;

for(i = a; i < d; i++)

{

printf("hello world!\n");

}

return 0;

}

/*

枚举

enum

在枚举中标识符能够和变量同名

当在函数中使用时,用的是变量

使用方法

1.使用枚举中的标识符做为case以后的整常量使用

enum A{HEADINSERT, TAILINSERT};

2.循环使用

3.硬件管脚的定义 寄存器赋值的定义

*/

#include

enum E

{

GPIO_MODER_INPUT,

GPIO_MODER_OUTPUT,

GPIO_MODER_FF,

GPIO_MODER_IF

};

int main(void)

{

return 0;

}

枚举类型变量的赋值和使用

枚举类型在使用中有如下规定:

1.枚举值是常量,不是变量。不能在  程序中  用赋值语句再对它赋值。例如对枚举weekday的元素再做如下赋值:sun=5;mon=2;sun=mon;都是错误的。

2. 枚举元素自己由系统定义了一个表示序号的数值,从0开始顺序定义为0,1,2…。如在weekday中,sun值为0,mon值为1,…,sat值为6。

3. 只能把枚举值赋予枚举变量,不能把元素的数值直接赋予枚举变量。如:a=sun;b=mon;是正确的。而:a=0;b=1;是错误的。如必定要把数值赋予枚举变量,则必须用强制类型转换,如:a=(enum weekday)2;其意义是将顺序号为2的枚举元素赋予枚举变量a,至关于:a=tue;

还应该说明的是枚举元素不是字符常量也不是字符串常量, 使用时不要加单、双引号。

注意:

1. 枚举中每一个成员(标识符)结束符是","不是";",最后一个成员可省略","。

2. 初始化时能够赋负数,之后的标识符仍依次加1。

3. 枚举变量只能取枚举说明结构中的某个标识符常量。

预处理指令 描述

#define 定义宏

#include 包含一个源代码文件

#undef 取消已定义的宏 能够用#undef命令终止宏定义的做用域

#ifdef 若是宏已经定义,则返回真

#ifndef 若是宏没有定义,则返回真

#if 若是给定条件为真,则编译下面代码

#else #if 的替代方案

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

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

/*条件编译*/

#include

int main(void)

{

#if 0

printf("hello world!\n");

#else

printf("hello China!\n");

#endif

return 0;

}

/*条件编译

#ifdef #else #endif

*/

#include

#define SUB

//定义了ADD宏

int main(void)

{

int a = 13, b = 7;

int sum = 0;

#ifdef ADD

sum = a + b;

#else

sum = a - b;

#endif

printf("sum = %d\n", sum);

return 0;

}

/*条件编译

#ifndef #else #endif

*/

#include

#define SUB

//定义了ADD宏

int main(void)

{

int a = 13, b = 7;

int sum = 0;

#ifndef ADD

//若是没有定义过ADD宏

sum = a + b;

#else

sum = a - b;

#endif

printf("sum = %d\n", sum);

return 0;

}

/*条件编译

#if #elif #elif #endif

*/

#include

#define FLAG 3

int main(void)

{

int a = 13, b = 7;

int sum = 0;

#if FLAG == 0

sum = a + b;

#elif FLAG == 1

sum = a - b;

#elif FLAG == 2

sum = a * b;

#elif FLAG == 3

sum = a / b;

#endif

printf("sum = %d\n", sum);

return 0;

}

宏函数(能用函数就不用宏)

宏定义是C程序提供的预处理功能之一.包括带参数的宏定义和不带参数的宏定义.

具体是指用一个指定的标志符来进行简单的字符串替换或者进行阐述替换.

1)不带参数的宏定义

格式:#define 宏名 替换内容

1.宏名通常用大写

2.提升程序的通用性和易读性,减小输入错误和便于修改。

例如:数组大小经常使用宏定义

3.能够用#undef命令终止宏定义的做用域

4.宏定义能够嵌套

2)带参数的宏定义

格式:#define 宏名(参数表)替换内容

注意:当使用宏定义时,实参若是是表达式,未来在替换时容易出问题

3)带参数的宏定义和函数关系

函数调用在编译后程序运行时进行,而且分配内存.

宏替换在编译前进行,不分配内存.

宏展开不占运行时间,只占编译时间,函数调用占运行时间(分配内存、保留现场、值传递、返回值)

/*

宏定义(就是替换)

(不带参数的宏定义)

#define 宏名[宏值]  []缺省项,能够没有值

注意 :

1.[]的内容是缺省值

2.宏定义最后不要加;

*/

#include

#define BUFSIZE 128

#define PAL 3.14

int main(void)

{

char buf[BUFSIZE];

int i;

for(i = 0; i < BUFSIZE; i++)

return 0;

}

#include

#define ADD(A,B) A+B

int add(int a, int b)

{

return a + b;

}

int main(void)

{

int a = 13, b = 7;

printf("add = %d\n", add(a, b));

printf("ADD = %d\n", ADD(a, b));

return 0;

}

/*

宏定义(就是替换)

(带参数的宏定义)

#define 宏名[宏值]

注意 :

1.[]的内容是缺省值

2.宏定义最后不要加;

宏定义和函数

宏定义的优势 : 比函数更快

函数的优势 : 比宏定义更准确(更稳定)

*/

#include

#define FUNC(A) A*A

//1 + 2 * 1 + 2 = 5

int func(int a)//

{

return a * a;

}

int main(void)

{

printf("FUNC = %d\n", FUNC(1 + 2));//FUNC = 5;

return 0;

}

#include

#define MAX(A, B) A>B?A:B

int max(int a, int b)

{

return a > b ? a : b;

}

int main(void)

{

int a, b;

scanf("%d-%d", &a, &b);

printf("max = %d\n", max(a, b));

printf("MAX = %d\n", MAX(a, b));

return 0;

}

=========附加预处理=============

咱们使用的文件包含、条件编译、宏定义以外的一些预处理

1)预约义宏

宏 描述

__DATE__ 当前日期,一个以"MMM DD YYYY"格式表示的字符常量。

__TIME__ 当前时间,一个以"HH:MM:SS"格式表示的字符常量。

__FILE__ 这会包含当前文件名,一个字符串常量。

__LINE__ 这会包含当前行号,一个十进制常量。

2)预处理器运算符

宏延续运算符(\)

一个宏定义或者表达式一般写在一行上,可是若是语句太长一行容纳不下,则使用宏延续运算符(\)。

字符串常量化运算符(#)

在宏定义中,当须要把一个宏的参数转换为字符串常量时,则使用字符串常量化运算符(#)。

标记粘贴运算符(##)

宏定义内的标记粘贴运算符(##)会合并两个参数。它容许在宏定义中两个独立的标记被合并为一个标记。

defined() 运算符

预处理器 defined 运算符是用在常量表达式中的,用来肯定一个标识符是否已经使用#define定义过。若是指定的标识符已定义,则值为真(非零)。若是指定的标识符未定义,则值为假(零)。

/*结构体程序实例*/

#include

typedef struct stu

{

int id;

char name[20];

int math;

}STU;

int main(void)

{

STU s, *p;

p = &s; ///结构体指针p必需要有指向才能进行下面的操做

p->id = 100;

sprintf(p->name, "Tom");

p->math = 100;

printf("p->id = %d\n", p->id);

printf("p->name = %s\n", p->name);

printf("p->math = %d\n", p->math);

return 0;

}

指针偏移

#include

union U

{

unsigned int *pi; //32bit

unsigned short *ps; //16bit

};

/*

用同一块8个字节空间存储地址

当使用pi指针偏移时地址偏移4个字节

当使用ps指针偏移时地址偏移2个字节

*/

int main(void)

{

union U u;

int a = 100;

short s = 200;

u.pi = &a;

printf("&a = %p\n", &a);

printf("u.pi = %p\n", u.pi);

printf("=========================\n");

printf("u.pi + 1 = %p\n", u.pi + 1);

return 0;

}

附加预处理

#include

int main(void)

{

printf("__DATE__ = %s\n", __DATE__);

printf("__TIME__ = %s\n", __TIME__);

printf("__FILE__ = %s\n", __FILE__);

printf("__LINE__ = %d\n", __LINE__);

printf("__FUNCTION__ = %s\n", __FUNCTION__);

return 0;

}

/*

附加预处理

若是想要使用宏定义表示字符串

定义一个带参数的宏,而后在宏值的前面加#便可

*/

#include

#define PRINT_STR(n) #n

int main(void)

{

printf("PRINT_STR = %s\n", PRINT_STR(abc)); //

return 0;

}

/*

附加预处理

标记粘贴运算符(##)

宏定义内的标记粘贴运算符(##)会合并两个参数。它容许在宏定义中两个独立的标记被合并为一个标记。

*/

#include

#define INT_VAR(n) var##n

int main(void)

{

int var1 = 100;

int var2 = 200;

int var3 = 300;

printf("INT_VAR = %d\n", INT_VAR(3)); //300

return 0;

}

经过fopen fclose 实现命令 touch

#include

int main(int argc, char *argv[])

{

FILE *fp = NULL;

int i = 0;

for(i = 1; i < argc; i++)

{

fp = fopen(argv[i], "a");

if(NULL == fp)

{

perror("fopen()");

/*??????????????*/

/*

建立多个文件,若是其中某个文件打开失败了,在程序结束前关闭以前打开的文件

*/

return -1;

}

fclose(fp);

fp = NULL;

}

return 0;

}

fgetc

文件操做

1.标准IO

stdin

stdout

stderr

2.系统调用IO

文件描述符

0 1 2

#include

int main(int argc, char *argv[])

{

FILE *fp = NULL;

int ch = 0;

fp = fopen("Tmp", "r");

if(fp == NULL)

{

perror("fopen()");

return -1;

}

while(1)

{

ch = fgetc(fp);

if(ch == EOF)

break;

fputc(ch, stdout);

}

fclose(fp);

fp = NULL;

return 0;

}

#include

#define BUFSIZE 128

int main(int argc, char *argv[])

{

FILE *fp = NULL;

char buf[BUFSIZE] = {0};

char *ret = NULL;

fp = fopen(argv[1], "r");

if(fp == NULL)

{

perror("fopen()");

return -1;

}

while(1)

{

ret = fgets(buf, BUFSIZE - 1, fp); //BUFSIZE - 1 是留一个给‘\0’

if(ret == NULL)

break;

fputs(buf, stdout);

}

fclose(fp);

fp = NULL;

return 0;

}

实现cp功能

cp srcfile destfile

fgetc

fgets

homework

实现diff命令

#include

int main(int argc, char *argv[])

{

FILE *fps = NULL;//fps文件流指针指向源文件

FILE *fpd = NULL;//fpd文件流指针指向目标文件

int ch = 0;//ch变量获取文件的字符

if(argc < 3)//错误判断若是命令行参数少于3个

{

printf("%s: 在'%s'后缺乏了要操做的目标文件\n", argv[0], argv[1]);

printf("Try '%s --help' for more information.\n", argv[0]);

return -1;

}

fps = fopen(argv[1], "r"); //打开源文件

if(fps == NULL) //错误判断(打开文件失败)

{

perror("fopen()");

return -2;

}

fpd = fopen(argv[2], "w"); //打开目标文件

if(fpd == NULL) //错误判断(打开文件失败)

{

perror("fopen()");

fclose(fps); //若是程序能够执行到这里证实源文件打开成功,在退出以前须要关闭

return -3;

}

while(1)

{

ch = fgetc(fps); //从源文件中获取字符

if(ch == EOF) //判断文件是否到末尾

break;

fputc(ch, fpd);

}

fclose(fpd);

fclose(fps);

fpd = fps = NULL;

return 0;

}

fread\fwrite

init.h

#ifndef __INIT_H

#define __INIT_H

typedef struct stu

{

int id;

char name[20];

int math;

}STU;

#endif

/fread

#include

#include "init.h" //init.h中只定义了一个结构体

int main(void)

{

FILE *fp = NULL;

STU s = {10086, "yidong", 8192};

printf("s.id = %d\n", s.id);

printf("s.name = %s\n", s.name);

printf("s.math = %d\n", s.math);

printf("==========我是分割线=========\n");

fp = fopen("data.bin", "r");

if(fp == NULL)

{

perror("fopen()");

return -1;

}

fread(&s, sizeof(STU), 1, fp);

printf("s.id = %d\n", s.id);

printf("s.name = %s\n", s.name);

printf("s.math = %d\n", s.math);

fclose(fp);

fp = NULL;

return 0;

}

/fwrite

#include

#include "init.h" //init.h中只定义了一个结构体

int main(void)

{

FILE *fp = NULL;

STU s;

scanf("%d", &s.id);

scanf("%s", s.name);

scanf("%d", &s.math);

fp = fopen("data.bin", "w");

if(fp == NULL)

{

perror("fopen()");

return -1;

}

fwrite(&s, sizeof(STU), 1, fp);

fclose(fp);

fp = NULL;

return 0;

}

fprintf

#include

int main(void)

{

FILE *fp = NULL;

fp = fopen("Tmp", "w");

if(fp == NULL)

{

perror("fopen()");

return -1;

}

fprintf(fp, "%d-%c-%f-%s\n", 100, 'A', 3.14, "hello world");

fclose(fp);

fp = NULL;

return 0;

}

fscanf

#include

int main(void)

{

int a = 0;

char c = 0;

float f = 0;

char buf[128] = {0};

FILE *fp = NULL;

fp = fopen("Tmp", "r");

if(fp == NULL)

{

perror("fopen()");

return -1;

}

fscanf(fp, "%d-%c-%f-%s", &a, &c, &f, buf);

printf("a = %d\n", a);

printf("c = %c\n", c);

printf("f = %f\n", f);

printf("buf = %s\n", buf);

fclose(fp);

fp = NULL;

return 0;

}

不一样方式读取键盘键值(设备文件)

/*

1.getchar() wsad

2.访问键盘设备文件

"r"

千万不要"w"

cat /proc/bus/input/devices 查看全部的输入设备对应的event

cat /dev/input/eventX 查看特定的输入设备文件(X = 0 1 2 3 ...)

标准IO 系统调用IO

stdin 0

stdout 1

stderr 2

*/

#include

#include

#include

int main(void)

{

int ch = 0;

struct termios old, new;

tcgetattr(0, &old);//用来获取终端信息0表明标准输入文件的文件描述符

new = old;

new.c_lflag &= ~ICANON;//与等于 按位取反 表明反操做

new.c_lflag &= ~ECHO;//取消回现

tcsetattr(0, TCSANOW, &new);//TCSANOW立马产生影响

while(1)

{

ch = getchar();

switch(ch)

{

case 'w' : printf("向上\n"); break;

case 's' : printf("向下\n"); break;

case 'a' : printf("向左\n"); break;

case 'd' : printf("向右\n"); break;

case ' ' : printf("落子\n"); break;

case 'q' : printf("退出\n");

tcsetattr(0, TCSANOW, &old);//在程序退出以前把老的模式设置回去

return 0;

}

}

return 0;

}

/*

1.getchar() wsad

2.访问键盘设备文件(系统调用IO)open  close  read  write

"r"

千万不要"w"

cat /proc/bus/input/devices 查看全部的输入设备对应的event

cat /dev/input/eventX 查看特定的输入设备文件(X = 0 1 2 3 ...)

标准IO 系统调用IO

stdin 0

stdout 1

stderr 2

open("/dev/input/event3");

操做设备文件

/usr/include/linux/input.h

/usr/include/linux/input-event-codes.h

*/

#include

#include

#include

#include

#include

#include

#include //使用到了头文件中的东西,须要包含

int main(void)

{

int kb_fd = 0;//未来保存打开键盘设备的文件描述符

struct input_event ev;//未来保存从键盘设备中获取的信息

struct termios old, new;

tcgetattr(0, &old);//用来获取终端信息0表明标准输入文件的文件描述符

new = old;

new.c_lflag &= ~ICANON;//与等于 按位取反 表明反操做

new.c_lflag &= ~ECHO;//取消回现

tcsetattr(0, TCSANOW, &new);//TCSANOW立马产生影响

kb_fd = open("/dev/input/event3", O_RDONLY);//以只读的方式打开键盘设备

if(kb_fd < 0)//打开失败,作错误处理

{

perror("open()");

return -1;

}

while(1)

{

read(kb_fd, &ev, sizeof(ev));//读取键盘文件信息,保存到结构体中

if(ev.type == EV_KEY)

{

if(ev.value == SYN_REPORT)

{

switch(ev.code)

{

case 103 : printf("向上\n"); break;

case 108 : printf("向下\n"); break;

case 105 : printf("向左\n"); break;

case 106 : printf("向右\n"); break;

case 28  : printf("落子\n"); break;

case 16  : printf("退出\n");

tcsetattr(0, TCSANOW, &old);

close(kb_fd);

return 0;

}

}

}

}

close(kb_fd);//关闭文件

kb_fd = -1;

return 0;

}

C语言实现把字节数转化成kb,C语言笔记相关推荐

  1. C语言常见数据类型字节数和打印格式总结(快速掌握)

    目录 一.简介 二.字节数对比 三.输出不同类型格式 四.常用类型简写总结 一.简介 本文主要介绍C语言常见数据类型字节数.不同类型输出格式和c程序中不同类型的简写总结.c语言中,常见数据类型的字节数 ...

  2. js中字节B转化成KB,MB,GB

    GB.MB.KB分别是: GB:吉字节(GB.Gigabyte,在中国又被称为吉咖字节或京字节或十亿字节或戟),常简写为G,是一种十进制的信息计量单位. MB:兆字节(Megabytes)是计算机存储 ...

  3. C语言int的字节数跟什么有关,C语言中int型字长和什么有关

    满意答案 momo猫万岁 2018.01.07 采纳率:50%    等级:8 已帮助:1710人 这个和操作系统有关,一般int的长度都会采用机器字长,比如win32系统,int占4字节,32位: ...

  4. C语言数据类型占字节数

    一.程序运行平台         不同的平台上对不同数据类型分配的字节数是不同的.         个人对平台的理解是CPU+OS+Compiler,是因为:         1.64位机器也可以装3 ...

  5. 把字节数B转换为KB,MB,GB的方法

    在文件系统中,我们可以通过一些系统自带的方法轻而易举地获取到文件的大小,但是这时我们得到的往往是文件的字节数,而我们通常更习惯于看到类似于B,KB,MB和GB这样的数据,博主在这里使用java编写了一 ...

  6. C语言 笔试 各个字节数,C语言笔试试题及答案

    (1)在计算机中,一个字节所包含二进制位的个数是 A)2 B)4 C)8 D)16 (2)在多媒体计算机中,CD-ROM属于 A)存储媒体 B)传输媒体 C)表现媒体 D)表示媒体 (3)在DOS系统 ...

  7. c语言读取文件字节数,怎么在C语言中利用fstat函数获取文件的大小

    怎么在C语言中利用fstat函数获取文件的大小 发布时间:2021-01-22 17:03:17 来源:亿速云 阅读:110 作者:Leah 怎么在C语言中利用fstat函数获取文件的大小?针对这个问 ...

  8. c语言编程回文数用数组,【C语言程序设计】C语言回文数怎么求?

    问题描述 打印所有不超过n(取n<256)的其平方具有对称性质的数(也称回文数). 问题分析 对于要判定的数n计算出其平方后(存于a),按照"回文数"的定义要将最高位与最低位 ...

  9. 兴业数金C语言笔试,2021兴业数金校园招聘C语言开发工程师职位

    中公金融人银行招聘网整理分享各大银行官方发布的招聘考试信息,整理的内容仅供格式参考,详情以官方发布的为准,忘各位考生悉知!笔面试通知等信息以各位考生接收到官方发布的短信或邮件为准! 岗位职责: 1.负 ...

最新文章

  1. 主板上这家伙,要当 CPU 和内存的中间商!
  2. sql中set命令解析
  3. linux筛选之后备份到命令,linux find 命令使用备份
  4. gview java_java - 如何在干净模式下运行eclipse? 如果我们这样做会发生什么?
  5. passwd命令提示: 鉴定令牌操作错误
  6. 学之思开源考试系统 - 使用手册
  7. Struts 2 Spring Hibernate三大框架的执行流程以及原理
  8. maven pom.xml指定jdk
  9. mysql 返回自增id_mysql 返回自增id
  10. C语言显示系统时间的几个办法
  11. JAVA中的继承和覆盖
  12. 理解Linux高性能网络架构的那些事
  13. Binding.scala使用教程8--binding.scala结合semanticUI
  14. python xlrd 写入已有的excel并保留原excel格式
  15. mysql怎么画继承_UML类图(上):类、继承和实现
  16. 利用R语言对泰坦尼克号沉没事件幸存者的数据分析与预测
  17. 使用pymysql报错:pymysql.err.InternalError: Packet sequence number wrong - got 5 expected 1
  18. 前端提高篇(十一)JS进阶8函数参数及arguments
  19. 网易服务器维护中,网易:22日凌晨3点服务器维护,预计时间10小时
  20. 我提了离职,公司给我涨薪了,还能待下去吗?

热门文章

  1. p720 自带的磁带机备份aix系统
  2. wxpython的简单使用【代码实现】
  3. 张一鸣打造“抖音”等现象级产品的秘密:技术深度融合业务,引爆产品创新!
  4. php redis 详细操作
  5. 01-Partial Dependence Plot(PDP)部分依赖图
  6. Linux 修改时区和时间
  7. libjpeg库使用举例
  8. Python自动化工具(自动化操作)
  9. 计算机基础实验4,计算机基础实验 3-4 实验报告
  10. break在java语言中什么意思_在Java语言的控制结构中,break语句是经常用到的语句。在switch语句中break语句的作用是( )_学小易找答案...