十三天学会C语言笔记

day1
Linux C基础课程~

【1】操作系统的介绍
内核:linux unix
操作系统:ubuntu redhat centos deepin

linux内核的功能:
	文件管理
	内存管理
	设备管理
	进程管理
	网络管理
	
ubuntu:是一个以桌面应用为主的Linux操作系统。
Ubuntu基于Debian发行版和GNOME桌面环境,与
Debian的不同在于它每6个月会发布一个新版本。
Ubuntu的目标在于为一般用户提供一个最新的、同
时又相当稳定的主要由自由软件构建而成的操作系
统。Ubuntu具有庞大的社区力量,用户可以方便地
从社区获得帮助

【2】Linux文件系统的结构
操作系统中通过什么方式组织和管理文件:文件系统

windows的文件系统将一块硬盘分为
C D E F盘,然后在各个盘中保存用户
的数据或者文件。

linux文件系统是一颗倒置的树,它分为根目录和
子目录。在根目录下有一些特定功能的目录。比如
/bin /etc /home /lib等,如果你在外接一个U盘
也是通过目录的形式来访问。

linux文件系统中的各个目录的功能不是用户随意指定的
它是根据FHS(Filesystem Hierarchy Standard)标准规定
各个目录下存放的内核及功能

/bin  可基本用户命令二进制文件
/boot 和系统驱动相关的文件
/dev  设备文件(通过此文件访问设备驱动)
/etc  系统配置文件
/home/linux 用户家目录
/lib  可执行程序需要连接的库文件
/sbin 系统二机制文件
/mnt/hgfs/share 共享目录
......	

【3】linux系统常用命令
终端的打开方式
1、点击
2、ctrl+alt+t
3、打开一个终端后再打开一个新的终端
ctrl+shift+n
关闭终端:exit

终端字体的调整
放大:
	ctrl+shift+"+"
缩小:
	ctrl+"-"

linux    @     ubuntu     :     ~             $ 
  |      |       |        |     |             |
用户名  间隔    主机名   间隔   用户的家目录  用户的类型
whoami          hostname          /home/linux/

$:普通用户
#:超级用户

【2】linux系统常用的命令
linux系统是多用户多任务分时操作系统
$:普通用户 linux
#:超级用户 root

linux   -----> su root ----> root

su root  切换到root用户
su linux 切换到linux用户
sudo -i  同样可以切换到root用户

sudo passwd root 设置root用户的密码

sudo  :让本次操作具备root权限
su    :切换用户

[1]ls命令
	ls 显示当前目录下的文件或者目录
	ls -l 显示文件或者目录的属性信息
	ls -a 显示所有文件包含隐藏文件(以.开头的文件就是隐藏文件)
	ls -lh h按照文件大小单位来显示
	ls -i 显示文件的inode号
	ls -R 递归显示文件
	
d          rwx          rwx       r-x  
|           |            |         |

文件的类型 用户的权限 组的权限 其它用户的权限

 5      linux    linux      4096  Jul 15  2016  arch
 |        |        |         |          |        |
链接数  用户名    组        大小       时间    文件名、目录
 
 
文件的类型(7种):bsp-lcd
-:普通文件,二进制文件
d: 目录
l: 链接文件(类似于windows快捷方式)
c: 字符设备驱动文件类型
b: 块设备驱动文件类型
p: 管道文件(进程间通讯)
s: 套接字文件

文件的权限:
	r 4   w 2    x  1       - 0
   读     写   可执行   没权限

	0664  :前面的0代表八进制
	0775

链接数:
	文件:链接个数
	目录:子目录的个数

[2]cd命令
	cd:切换目录的命令
	
	cd 要进入的目录
	
	cd .. 或cd ../  退到上一级目录下
	cd -
	cd ~ 或者cd
	cd /	

day2

	cd -         进入到上一次操作的目录下
	cd ~ 或 cd   回到linux用户的家目录 /home/linux
	cd /         进入根目录

	在/home/linux目录下进入etc目录的方法
	cd /etc
	cd ../../etc
	
	cd 绝对路径(从根目录开始访问)
	cd 相对路径(通过目录间的位置关系访问)
	
	
【1】pwd命令
	查看当前位置
	
	
【2】clear命令
	clear 清屏命令
	ctrl+l
	
【3】touch命令(创建文件)
	如果文件不存在,创建文件
		touch 文件名
		touch 1.c
		touch 2.c 3.c 4.txt

	如果文件存在,更新文件的时间戳,
	不会改变文件的内容。
		touch 1.c
		
【4】mkdir命令(创建目录)
	mkdir hello :在当前目录下创建一个hello的目录
	mkdir 目录1 目录2 ...可以同时创建多个目录,
				 这些创建的目录是在同一级的。
	mkdir -p 1/2/3 创建具备层级关系的1 2 3这些目录
	mkdir -m 0664 test2 创建目录,目录的权限是0664
	mkdir -m 0777 test3 创建0777权限的目录,
	                    目录的背景色会换成绿色

【5】删除目录
	rmdir :只能用来删除空目录

【6】rm命令
	删除文件
	rm 1.txt 删除1.txt文件
	rm *.c   删除所有的.c文件
	
	删除目录
	rm 1 -r 删除1目录 (-r递归删除)
	rm test -rf        (-f强制删除)
	rm test* -rf 删除所有已test开头的文件
	rm * -rf     删除所有的当前目录下的文件
	sudo rm * -rf  删除所有的当前目录下的文件

作业:
	1.复习课上指令
	2.删除除1.c之外所有文件和目录
	linux@ubuntu:~/DC20021$ ls
		1.c  1.txt  2.c  3.c  hello  test
		
	rm !(1.c) -rf

【1】cp命令(拷贝)
拷贝文件
cp 源文件的路径/名字 目标路径
cp /home/linux/test.c /etc
拷贝/home/linux目录下的test.c到/etc目录下

拷贝目录
cp 路径/原目录 目标路径 -r  (递归拷贝)
cp 路径/原目录 目标路径 -a  (递归拷贝)


拷贝的同时进行重命名
cp /home/linux/test.c ~/hello.c 
cp ~/DC20021 ~/tools/123 -r

	拷贝的同时进行重命名

练习:
    1.将/etc下的passwd文件拷贝到家目录DC20021目录下
	 cd
	 mkdir DC20021
	 cp /etc/passwd ~/DC20021/
	
	2.将etc下的groff拷贝到DC20021目录下
	 cp /etc/groff/ ./ -r

    3.将etc下的passwd文件拷贝到家目录DC20021目录下test.c
	 cp /etc/passwd ./DC20021/test.c

	4.将etc下的groff拷贝到DC20021目录下hello
	 cp /etc/groff/ ./hello -r

【2】mv命令
移动(目标路径存在)
mv 源文件 目标路径
mv 源目录 目标路径

mv test.c DC20021 //将test.c移动到DC20021目录下
mv test   DC20021 //将test目录移动到DC20021目录下

重命名(目标路径不存在)
mv 源文件名字  目标文件名字
mv test.c hello.c
mv test hello

day3

Linux C基础课程第三天

【2】windows和ubuntu文件互传
1.共享目录
虚拟机->设置->选项->共享文件夹->总是启用
选择windows上的一个目录即可D:\share
windows D:\share
ubuntu /mnt/hgfs/share

2.直接拖
	vm tools
	
3.借助服务器
	samba	
	
	
	windows           ubuntu
	winSCP   <---->   sudo apt-get install ssh

【3】命令
echo 打印命令
echo “1231123”—>在终端上显示
echo 12312312 > 123.c 将12312312放到123.c的文件中
echo 12312312 >> 123.c 将12312312追加123.c的文件中

> :重定向 (清空文件后将echo后面的内容写到文件中)
>>:追加

cat  查看
cat 123.c  将123.c文件中的内容显示到终端上

【4】linux系统中文件编辑器的使用
vi/vim编辑器

打开文件
	touch 文件名
	vi 文件名 / vim 文件名
使用
	命令行模式:
	    1.打开文件的时候,默认处在命令行模式
		2.从插入模式进入到命令行模式的Esc
	
	插入模式:
		1.从命令行进入插入模式,按下键盘的i
		
		
	底行模式
		1.从命令行模式进入底行模式 shift + :
		:w   保存
		:q   退出
		:q!  不保存退出
		:wq  或者 x 保存退出
		:wq! 强制保存退出 

【2】vim编辑器
vi test.c

命令行:
	按下键盘Esc键
	拷贝
		yy  拷贝光标所在的行
		3yy 拷贝光标所在的向下三行
		nyy 拷贝光标所在向下的n行
		yG  拷贝光标所在向下到尾行
		
		鼠标选中想要拷贝的行,按下键盘的y
		
	剪切
		dd  剪切光标所在的行
		4dd 剪切贯标所在的向下4行
		ndd 剪切贯标所在的向下n行
		
		鼠标选中想要剪切的行,按下键盘的d
	粘贴
		p  
		
	撤销
		u (反向撤销ctrl+r)
	
	文件收尾快速跳转
	调到首行
		gg
	跳转到尾行
		G(shift+g)
		
	让单词高亮显示	
		/你想高亮的单词
		/^main   以main开头
		/main$   以main结尾
		/^main$  以main开头并main结尾
		
		n :跳到下一个单词
		N :跳到上一个单词
		
	代码对齐的功能:
		gg=G   对齐本文件
		鼠标选中想要对齐的行,按下键盘的=
		(对齐选中的行)
	删除:
		ndd
		鼠标选中想要剪切的行,按下键盘的d
		
		dG  删除光标到文件尾部的所有的行
		dgg 删除光标到文件头部的所有的行
		x :删除光标所在位置的字符
		或者进入插入模式backspace
		
		
插入模式:
	按下键盘的i键
	I :在光标所在行首进入插入模式
	i :在光标所在前进入插入模式
	A :光标所在行尾进入插入模式
	a :在光标所在后进入插入模式
	O :在光标所在上一行进入插入模式
	o :在光标所在行下一行进入插入模式
	

底行模式:
	按下键盘的shift+:
	
	保存、退出
		:q
		:q!
		:w
		:wq 或者 x
		:wq!
		:wqa
	
	取消高亮
		:nohl
	设置光标(ubuntu文件内容向拷贝到windows)
		set mouse=  可以右键拷贝
		set mouse=a 不可以右键拷贝
		或
		按着shift键,鼠标选中想要拷贝的行,
		松开shift,右键拷贝(12.04)
		按着shift键,鼠标选中想要拷贝的行,
		不松松开shift,右键拷贝(16.04)			
		
	跳转到对应行号
		:n 
		:10
		
	设置行号是否显示
		:set nonu  取消行号
		:set nu    显示行号
		

	拷贝、剪切
	
	替换
	
	文件另存
	
	打开多个文件

day4

Linux C基础课程 第四天

【1】复习
vim编辑器的使用
命令行模式
Esc

yy nyy  鼠标选中y
dd ndd  鼠标选中d
p
u

gg G

/hello  n N  /^hello  /hello$

dG  dgg  x
F2: 显示文件中的变量,函数,宏
F3: 显示当前文件目录下的文件或者目录

插入模式:
 i
 I
 a
 A
 o
 O
底行模式:
保存退出
:q
:q!
:w
:wq 或 :x
:wq!
:wqa

取消高亮显示
:nohl

行号显示与否
set nu
set nonu

拷贝(通过终端向windows拷贝)
按下shift ,鼠标选中想要拷贝的行,右键拷贝
set mouse=
set mouse=a

行跳转(vi 文件名 +行号)
:50

拷贝、剪切
:3,4y   拷贝3-4行
:3,$y   拷贝3-尾行的内容
:12,19d 剪切12-19行
:3,$d   剪切3-尾行

替换
:%s/旧的字符串/新的字符串/g 全局替换
:%s/旧的字符串/新的字符串/  替换每一行第一次出现的旧字符串
:11,12s/旧的字符串/新的字符串/g 替换11-12行的旧字符串
:11,12s/旧的字符串/新的字符串/
:11,$s/旧的字符串/新的字符串/g 替换11到尾行的内容
:11,$s/旧的字符串/新的字符串/ 替换11到尾行的内容
                            (第一次出现的字符串)
文件另存
:w 路径/文件的新的名字

文件的插入
:r  路径/文件名   将文件中的内容插入到光标所在的位置

打开多个文件	
:vsp 路径/新文件的名字  左右打开
:sp 路径/新文件的名字   上下打开

【2】写一个helloworld
vi 01helloworld.c //打开一个新的文件

#include <stdio.h> //包含头文件(printf的头文件)
//#include 包含头文件的固定用法
//<>       stdio.h在系统的/include /usr/include
//""       代表的是当前的路径

//main是入口函数 ,后面的是参数
int main(int argc, const char *argv[]) 
{
	printf("hello world.\n"); //printf是一个打印语句
	                          // '\n'换行
	printf("hello DC20021 everyone\n");   
	
	return 0; //函数的返回值,如果返回的是0,(代码执行成功)
			  //return -1;  返回负数代表代码执行失败了
}             //c语言每句话结束都要使用;


使用c语言编写的是语言文件,它是不能够直接执行的,
原因机器只能识别0和1二进制。
源文件 ----->编译------>二进制文件(可以执行)

编译:
gcc 01helloworld.c -o helloworld

执行:
./helloworld

结果:
hello world.
hello DC20021 everyone

【3】gcc编译器
gcc<-gnu(开源组织)

gcc -v  查看gcc的版本
 gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5) 
 gcc编译的代码只能够在ubuntu(x86)上执行,不能够在
 手机上执行,因为手机(arm架构的)
 
一、预处理
    1、将头文件进行替换,对宏进行替换,
	对条件编译替换,它不会对语法检查。
gcc -E 01helloworld.c -o               helloworld.i
	 |         |       |                      |
 预处理的参数  |     指定后面要生成程序的名字 |
			   |                              |
		   源文件                        预处理后的文件
二、编译
	对语法进行检查的,将预处理后的文件编译成汇编文件
	
	gcc -S helloworld.i  -o helloworld.s

三、汇编
	将汇编文件编译成可执行文件,这个文件没有连接库
	gcc -c helloworld.s -o helloworld.o

	参数:ESc 后缀:iso
四、链接
	将依赖的库连接到可执行程序中
	
	libc.a 静态库:在编译的时候直接将所依的所有内容
				   编译到可执行程序中
	libc.so动态库:编译的时候只是将符号链接编译进去
				   执行的时候会反过来找这个库
	gcc helloworld.o -o helloworld


编译:
 gcc 01helloworld.c -o helloworld
 gcc 01helloworld.c  ----->
            //生成可执行程序的名字a.out

PM:
【1】计算机的组成
1.输入输出
2.控制器
3.总线
4.运算单元ALU
5.存储设备

存储设备:
硬盘:机械硬盘,固态硬盘
	emmc
	
内存:SDROM DDR4(掉电丢失)

iROM:只读存储器,只能被写入一次,存放启动代码

iRAM:随机存储器,(掉电丢失)

cache:高速缓存

cpu ---->register--->------>内存--->硬盘
                    |         |
					|->cache->

【2】存储大小的单位
bit 只能用来存储1或者0
byte(字节)=8bit
kb = 1024 byte
Mb = 1024 Kb = 1024*1024byte
Gb = 1024Mb
Tb = 1024Gb

【3】数据的类型(ubuntu 32位)
基本类型
字符类型
char 1字节
signed char 有符号的字符类型
unsigned char 无符号的字符类型

	整形
		短整型
		short 或者short int 2字节
		signed short
		unsigned short
		整形
		int  4字节
		
		长整形
		long 或者long int 4字节
		
		长长整形
		long long 或者 long long int 8字节
	实型(浮点类型)
		float  单精度的浮点类型 4字节
		double 双精度的浮点类型 8字节
		
	枚举类型(下一门课程讲解)
		enum
构造类型
	数组
	char buf[2];
	结构体(下一门课程讲解)
	struct
	共用体(下一门课程讲解)
	union
指针类型(都是4字节)
	char *;
	int *;
	long *;
	void *
空类型
	void

【4】常量
字符常量(char)(只能赋值给字符类型)
man ascii 查看字符常量对应的值

	'\n'   'a'  'A'  't'  :单引号引起来的是字符
	 10    97   65   116
	 
	'0'   0  '\0'
	48    0   0

整形常量(short int long)
	0 10 100 500 -2 -1 -10 
	0b1101
	0664
	0xac8f
实型常量(浮点)(float double)
	3.14  2.85  3.14e-1  0.314E2
	
字符串常量(在c中没有字符串类型)
	"helloworld"
	"c program"

标识常量(宏)(保留)


char a = 'a';
char b = -10;
short c = 10
int d = 1000;
long y = 500;                                                                           
float t = 3.14;
double v = 2e-3;

【5】进制转化
二进制(逢二进一)(0b是二进制的开头)
0b110110 = 转化为10进制 = 125+1*24+122+1*21

十进制(逢十进一)
65 = 0b100 000
50 = 0b?00110010?
12 = 0b1100

八进制(逢八进一)(0是八进制)
0 1 2 3 ... 7
0664 = 6*8^2+6*8^1+4*8^0 = 436
     = 0b110 110 100
0775 = 0b111 111 101 
     
	 7 = 4 + 2 + 1  = 0b111
	  
注意八进制中的一位转化成二进制对应的是三位

十六进制(逢十六进一)(0x代表十六进制)
0 1 2 3 4 ... 9 a b ...f(10-15是通过字符来表示的)
0xa38f = 0b1010 0011 1000 1111
0x1b0  = 0b0001 1011 0000

f = 15 = 8 + 4 + 2 + 1

注意十六进制中的一位转化成二进制对应的是四位

07531    =  0b111 101 011 001
0x3876fc =  0b0011 1000 0111 0110 1111 1100
23       =  0b1 0111
         =  16+4+2+1

day5

Linux C基础课程 第五天

【1】复习
数据类型:
char signed char unsigned char 1字节
short (short int) 2字节
int 4字节
long (long int) 4字节
long long int 8字节
float 4字节
double 8字节
long double 12字节
数组 不确定
int [2] 8字节

void *
char *             4字节
int  *

void               空类型

常量:
	字符常量(man ascii)
	'\n'  10
	'\0'  0
	'0'   48
	'A'   65
	'a'   97
	
	整型常量
	 10 100 0b1101  0664 0xaf  
	 
	实型常量
	3.14 5.69  0.012e2 0.012E-2

	字符串常量
	"hello world"
	"100"
	"0"
	
	标识常量(宏)

进制转换
	二进制
	0b1101
	八进制
	0664
	十进制
	57
	十六进制
	0xaf
	
练习进制转化
	0x4cfd81 转化为八进制
	0b 010 011 001 111 110 110 000 001
	023176601
	
	0x4003f  转化为二进制
	0b0100 0000  0000 0011 1111
	
	061345   转化为二进制
	0b110 001 011 100 101
	
	37       转化为二进制	
	37 = 32 + 4 + 1
	0b  0010 0101

【2】变量
<存储类型> <变量类型> 变量名;
存储类型6中:
auto register extern static volatile const

<变量类型> 变量名;
char a;
int tt;

1.变量名只能由数字,字母,下划线组成,不能以
  数字开头
  tyx  t123_  _123t  1ttw (错误) ww% (错误)
2.变量名在写的时候不能和关键字重复,关键字(32个)
	auto register static volatile const extern  6
	void char short int long struct union enum
	float double  signed unsigned               12
	typedef                                     1
	sizeof  求类型大小的关键字                  1
	if else switch case do while goto for       8
	return continue break default               4

3.见名知意
	
4.区分大小写
	Max max
	
int light_on;
int LightOn;

变量存储数据的能力
char : 127 - (-128) 
unsigned char :0 - 255

short: (2^15-1) - (-(2^15))) 
        32767 - (-32768)
unsigned short : 0-65535

int:(2^31-1) - (-(2^31))	
	2147483647 - (-2147483648)

变量的符号
char 8bit
 1       0000000
 |           |
 符号位   数据位
 1:代表负数
 0:代表正数

0 111 1111 = 2^7-1 = 2^6+2^5+2^4+2^3+2^2+2^1+2^0

unsigned char:
 0000 0000 	 都是数据位
 1111 1111
 
 char = signed char  都是有符号的
 
变量存储的方式(数据是以补码存放的)
源码,反码,补码
反码:除符号位外,其他的位取反
补码:在反码的基础上加1

正数的源码反码和补码是一样的
5 = 0101 = 0101 = 0101

-5 = 1000 0101 = 1111 1010 = 1111 1011
      源码         反码       补码

char a = 128;
128 = 
	1000 0000 补码 
	1111 1111 反码
	1000 0000 源码-128
	
129 = 
	1000 0001 补码
	1111 1110 反码
	1111 1111 源码-127

【3】数据打印的格式
%c 字符
%d 整数
%ld 长整形
%lld长长整形
%f 实型 (默认是小数点后六)
%.3f (小时小数点后三位)
%g 实型 (显示小数点后的有效位)
%Lf 显示long double
%s 显示的是字符串
%o 显示八进制
%#o 显示八进制并显示前缀
%x 显示16进制
%#x 显示16进制的数并显示前缀

PM:

【1】标识常量宏
第一种用法
#define M 10

1.含义:使用M代替10这个数字
2.可以让数据具备对应的含义,减少魔鬼数字的出现。
3.可以通过宏让代码中使用数字的所有一块改变
4.宏在定义的时候写成大写。
5.宏的最后的位置不需要使用";"
6.宏是预处理阶段完成的替换

第二种用法
	#define M 10
	#define N M+10
	x = N+N;
	y = N*N;
	
	printf("x = %d,y = %d\n",x,y); //40,120


第三种用法
	#define S(a) #a
	printf("S(10) = %s\n",S(10));  //"10"
	这里的一个#代表的是字符串化
	
	S(10)        #10
	   |           |
	 数字10       "10"
	
第四种用法
	#define NAME(a,b) a##b
	#define HW "helloworld"
	int hello = 1000;
	printf("hello = %d\n",NAME(h,ello));
	printf("hello = %d\n",NAME(he,llo));
	printf("HW = %s\n",NAME(H,W));
	
	这里的“##”表示的是字符串拼接
	h##ello ==>hello
	H##W  ===>HW

    NAME(h,ello) h##ello ==>hello

第五中用法
	#define MAX(a,b) ({int max; if(a>b)max=a;else max=b;max; })
	
	max = MAX(5,10);
	
	在宏中如果有多句话,需要使用({})
	宏的最后一句话执行的结果就是返回值

自己写的: #define MAX(a,b) (do{int max;if(a>b)max=a;else max=b;max;}while(0))


day6

Linux c基础课程 第六天

【1】复习
宏:
1.
#define M 10
2.
#define N M+10

	x = N+N;  //10+10+10+10 = 40
	y = N*N;  //M+10*M+10 = 10+10*10+10 = 120
	
	#define ADD(x) x+x
	
	int m=1,n=2,k = 3;
	int sum;
	sum = ADD(m+n)*k;  
	    = m+n+m+n*k = 1+2+1+2*3 = 10;
	printf("sum = %d\n",sum);
	
	//宏替换是在预处理阶段进行,m+n = 3在执行的
	//时候才会出现结果,所以是先完成了替换在执
	//行了运算
3.
	#define S(a) #a
	在宏中#代表字符串化
	传入的是一个整数,#会帮你转化为字符串
	
4.
	#define NAME(a,b) a##b
	
	这里的##代表的是字符串拼接
	
	int hello = 1000;
	
	NAME(he,llo) ==>hello
	
5.	
	#define MAX(a,b) 
	({int max; if(a>b)max=a;else max=b;max; })
		
	max = MAX(5,10);
	
	在宏中如果有多句话,需要使用({})
	宏的最后一句话执行的结果就是返回值

【2】运算符号
单目运算符
+ 正
- 负
++ 自加
注:自加是每次增加1,
1.++i,先对i进行自加1,本次直接加上去了。
2.i++先执行了加1,但是本次加1没加上去,
在执行下一句的时候就会加上去。
– 自减是每次减去1
–i:本句话减去1了
i–:下一话才减去1
&:取地址符号,
例如:int a=100; &a = 0xbf8a00dc
*:取地址中的内容 *&a = 100
!:取反 真取反是假,假取反是真。
0假,非0就是真

	~:按位取反
		比如char a = 0xc3; //1100 0011
			a = ~a;        //0011 1100
	
	强制类型转化
		int b =100;
		char a;
		a = (char)b;
		
算术运算符
	+  加 c = a+b
	-  减 c = a-b
	*  乘 c = a*b
	/  除 c = a/b;  2/3 = 0 如果分子小于分母结果是0
	%  取余数(取模):这个符号不能和实型的数结合使用
		int a;
		a = 2%3;
		a = 2.0%3;
		a = 2/3.0;

PM:(大家进入直播间回复下)
【1】
移位运算符
<< 左移动
>> 右移动

 如果一个数是正数,不管是左移动还是右移动都补充的是0
 如果一个数是负数,左移补充的是0,右移补充的是1
 0000 0100
 1<<2 = 4
 1<<3 = 8
 8>>1 = 4
 8>>3 = 1
 1<<20 = 使用十六进制表示
 
 int =>4字节=>32bit
	0000 0000 0001 0000
	0000 0000 0000 0000 = 0x100000
 
关系运算符
	> 大于   
	< 小于
	== 等于 
	!= 不等于
	>= 大于等于
	<= 小于等于
	
与运算符(位)
	&
		
	1&0 = 0
	0&0 = 0
	1&1 = 1
	
	0和任何数相与都为0,
	1和任何数相与都为任何数

	int a = 0xfc //====>1111 1100
	请使用&将a变量的第三位清零,
	并不改变其他的位。
	
	a & 1111 0100 =>1111 0100;

	 a = a & (~(1<<3));
	 
	1<<3 ===> 0000 1000
	~(1<<3) ===>1111 1111 1111 1111
	            1111 1111 1111 0111
				
异或运算符(位)
	^
	相异为真,相同为假
	1^1 = 0
	0^1 = 1
	0^0 = 0
	
	int x = 10;
	
	x = x ^ x;
	
	x = ?
	
	int a=5,b=10;
	请使用异或交换两个变量的值?
	   a = a ^ b;                                                                              
	   b = a ^ b;
	   a = a ^ b;
	   
	 0101  =>a
	^1010  =>b
   --------------
	 1111 => a
	^1010 =>b
   --------------
	 0101 =>b
	^1111 =>a
	-------------
	 1010 =>a
	
或运算符(位)
	| 
	
	1|0 = 1
	1|1 = 1
	0|0 = 0
	1和任何数相或都为1
	0和任何数相或都为任何数
	
	int a = 0xfc 
	请使用|将a变量的第0和1位设置为1,
	并不改变其他的位。
	
	a = a | ( 1<<0 | 1<<1);
		

逻辑运算符(这个不是按位操作的,它是整体操作的)
	|| 或
	if(weight>100 || weight<10){
		printf("please take care your healty\n");
	}	
	1.如果||符号前的表达式成立,||后面的表达式就不会执行了
	2.如果||符号前的表达式不成立成立,
		||后面的表达式就会执行了
	
	&& 与
	if(weight<=100 && weight>=10){
		printf("your are healty\n");
	}	
	1.如果&&符号前的表达式不成立成立,
		&&后面的表达式就不会执行了
	2.如果&&符号前的表达式成立成立,
		&&后面的表达式就会执行了
	
条件运算符(三目运算符)
	?:
	d=a?b:c
	如果a为真,将b赋值给d
	如果a为假,将c赋值给d
		
	
赋值运算符
	= 赋值运算符
	+= 先加后赋值
	-= 先减后赋值
	*=
	/=
	%=
	>>=
	<<=
逗号运算符
	,  它取出的结果是逗号后的结果

补全的修改:
vi ~/.vim/snippets/c.snippets
:71行是一个折叠的代码,使用键盘的z o

 69 # main()
 70 snippet main
 71     #include <stdio.h>
 72                                                                                         
 73     int main(int argc, const char *argv[])
 74     {
 75 +---  2 lines: ${1}---------------------------------------------------------------------
 77     }
~                    


经过上述的修改,新打文件之后,输入main按下键盘
的tab键。就可将上述的代码补全到你的新文件中了。

day7

Linux C基础课程 第七天

【1】复习
运算符





异或

逻辑
条件
赋值
逗号

运算符优先级问题:单算移关与,异或逻条赋,逗
	上述的运算符是有优先级的,
	从上往下优先级逐渐降低的。
同种类型的运算符如何计算:
	单 条 赋  从右向左结合
	剩余的运算符都是从左向右


作业:
	1. 执行下列程序段后,变量a,b,c的值分别是    
	int x=10,y=9;
		 int a,b,c;
		 a=(--x==y++)?--x:++y; // a=8  x=8 y=10;
		 b=x++; //b= 8 x=9 y=10
		 c=y;  //c=10
		 
	A、a=9,b=9,c=9   
	B、a=9,b=10,c=9  
	C、a=1,b=11,c=10  
	D、a=8,b=8,c=10 
	

	2.将一个32位的无符号的整数,实现高低位
	反转,比如31反转后再0位,30位反转后
	 在第1位......(不能定义新的变量)
   
	思想:
		1.相邻位交换 
		2.相邻的两位交换
		3.相邻的四位交换

【2】输出

printf("控制格式",变量列表);
功能:向终端上显示要打印的信息
参数:
	@控制格式 %d %c %s 
	@参数列表 (变量,变量)
	
unsigned int a;
printf("%c\n",a); 打印字符类型
printf("%d\n",a); 打印整形
printf("%u\n",a); 打印无符号整形
printf("%ld\n",a);打印长整形
printf("%lld\n",a);打印长长整形
printf("%#o\n",a);打印八进制 #代表显示八进制的前缀
printf("%#x\n",a);打印十六进制 #代表显示十六进制的前缀
printf("%f\n",a); 打印浮点类型,小数点后6位
printf("%.2f\n",a);打印浮点类型,小数点后2位
printf("%g\n",a);  打印浮点类型,小数点后有效位
printf("%e\n",a);  打印浮点类型,会以指数的形式显示
printf("%Lf\n",a); 打印long double类型浮点数据
printf("%p\n",&a); 打印一个变量的地址
printf("%s\n",&a); 打印的是字符串

printf("%04d\n",a); 占用四个位置,没数据的位补充0
printf("%4d\n",a); 占用四个位置,没数据的位补充空
printf("%-4d\n",a); 占用四个位置,-左对齐
printf("%d\t%d\n",a,a); 这里的\t是一个制表符 (\t=>Tab)

printf("%%\n");     打印一个%号

printf中的转译字符
	printf("abc\067\n");  ==>\067 => '7'
	printf("abc\67\n");  ==>\67 => '7'
	printf("adc\x65\n")  ==>\x65 => 'e'
	printf("hello \"wo\"rld\n");=>\" 代表打印 "
	printf("hello \'wo\'rld\n"); =>\' 代表打印 '  

	'\n' =>回车
	'\t' =>Tab
	'\a' =>发出一个“咚”
	'\b' =>退格
	'\r' =>回滚行首

【3】输入
scanf(“控制格式”,地址列表);
功能:从终端向读取控制格式的内容
参数:
@控制格式 %c %d %u %s
@地址列表 &a,&b
返回值:
成功读取到的项目的个数
失败返回EOF(-1)

练习如下实例~~~~~~~~~~~~
scanf("%d",&a); 输入一个整数

scanf("%d%c",&b,&a); //同时输入两个字符 10c 回车
scanf("%d,%c",&b,&a); //同时输入两个字符 10,c 回车
scanf("%d %c",&b,&a); //同时输入两个字符 10 c 回车

scanf("%d",&b);  //先输入一个整数10,回车
scanf("%*c%c",&a);//c回车   注:%*c它会吃掉回车

scanf("\n%d",&b);
scanf("\t%d",&b); //输入的时候会跳过回车、tab、空格
scanf(" %d",&b);

scanf("%d\n",&b);                                                                       
scanf("%d\t",&b);//输入整数后,回车,tab,空格
scanf("%d ",&b); //都没反应在随便输入一个字符,
                 //就可以结束程序了
				 
char a[10]; //这是一个char类型有10成员的数组,a数组名
            //a是数组的首地址

// scanf("%s",a); //不能够hello w ,遇到空格 tab 结束了
scanf("%[\n]",a);//%[\n]:除了’\n’之外的所有字符全输入
printf(“a = %s\n”,a);

实例1:
1.输入三角形边长,求面积(开根号sqrt)
s = (a+b+c)/2;
area = √s*(s-a)*(s-b)*(s-c)

man sqrt
#include <math.h> //头文件
double sqrt(double x);
功能:开根号
Link with -lm.  //连接库

验证:输入3 4 5 结果是=>6

注释:
// 单行注释
/* */ 多行注释
#if 0 多行注释
#endif


day8

Linux C基础课程 第八天

【2】输入、输出
int putchar(int c);
功能:向终端上输出一个字符

常见的用法如下:
putchar(a);    //char a = 100;
putchar('\n'); //'\n'
putchar(65);   //65
//'\n' 65 'A' =>数值=>向终端上输出的时候重新转化成字符


int getchar(void);
从终端读取一个字符

常见的用法:
char a;
a = getchar();  //从终端读入一个字符,输入a ,a= 'a'
                //输入10 ,a= '1'
getchar();      //用来吃掉终端上输入的'\n'
                //它和scanf("%*c")功能相同


gets(char s[]);
功能:从终端向数组中读入多个字符
在读入的字符最后会加上'\0',当输出字符串的时候
遇到'\0'才会结束。
注意:gets非常傻,即使读取的字符超出
自己能够承受的范围,也会接着往下读,
这样是不安全的。尽量不要使用这个函数,
或者使用的时候注意越界问题即可。


puts(char s[]);
功能:将数组中的内容输出到终端上(多个字符)
在输出的时候会字符加上'\n'

【3】c语言中的控制语句
1.if/else if/else
if(条件1){ //条件1成立,语句1执行
语句1;
}

	if(条件1){ //条件1成立,语句1执行
		语句1;
	}else if(条件2){ //条件2成立,语句2执行
		语句2;
	}else { //如果条件1 条件2都不成立,执行else中的语句3
		语句3;
	}

	if(条件1){
		语句1;
	}else{
		语句2;
	}
	
	注意if可以单独使用,else不能单独使用

2.switch/case/default/break
switch(变量){
	case 常量1: 语句1;
	case 常量2: 语句2;break;
	default: 语句n;
} 

1.switch对应的括号中是变量(字符或整形)
2.当变量和常量1相等的时候执行语句1.
3.case后面跟的break是结束switch/case语句
  如果没有break;继续向下执行。
4.如果变量和case后的常量都没比较成功,会执行
  default语句。
5.case后跟的是常量,常量,常量!!!


3.do/while /while 循环语句
	do{
		循环体;
	}while(循环条件)
	
	注意:do/while循环体总会被执行一次
	如果循环条件为真,会继续执行循环体。
	如果条件为假,退出循环。
	
	
	while(循环条件){
		循环体;
	}
	
	注意:如果循环条件成立,循环体会被执行,
	如果循环条件不成立,退出循环执行。
	
4.for循环
   for (语句1; 语句2; 语句3){   
		循环体;
	}   

	先执行语句1,接着执行语句2,如果
	语句2为真,执行循环体。循环体执行完
	执行语句3,在执行语句2,如果语句2为真
	再次执行循环体。
	
	int i,sum=0;
	for(i=1; i<=100; i++){
		sum+=i;
	}   
	printf("sum = %d\n",sum);  



	for语句可以嵌套
	*
	**
	***
	****
	*****
	
	*****
	 ****
	  ***
	   **
	    *

5.break;
	1.可以结束switch/case语句;
	1.可以结束一层循环(while for);

day9

Linux c基础课程 第九天

【2】控制语句剩余部分
goto 跳转语句

用法:
	loop:
		
	goto loop;

1.goto只能在当前函数内跳转,
	不能跳转到其它函数。
2.goto是跳转语句,效率低。
  一般使用goto语句,做统一出错处理。
  其他的情况一般不使用goto。

continue:
	它会执行下一次循环语句,本次continue
	语句后面的语句就不会执行了。
   for(i=0; i<=100;){
		if(i%2 != 0){ 
			i++;
			continue; //执行下次循环,sum+=i++;  
		}             //就不会去执行了。                                                                      
		sum+=i++;   
	}   

return:
	功能用来结束一个函数。
	return后面的数字,代表函数执行的结果
	如果整数都是自己固定的函数,如下
	int get_leap_year()
	{
	  if((year%4 == 0 && year%100 !=0)||
			year%400 == 0){ 
			return 1; //代表闰年
		}

		return 0;//代表平年
	}
	
	如果返回的是负数,表示程序执行出错了。

【3】数组(格式如下)
char a[10]; //字符数组
int b[10]; //整形数组

1.数组属于构造类型,它是基本
	数据类型元素的组合
2.数组中的成员在内存上是连的
3.a:代表的是数组名,它同时又
  代表数组的首地址。a是一个常量
  (不可以a++,++a),可以做a+1;
4.[10]:[]数组的格式,10数组的成员
   有十个。
   a[0] a[1] a[2] ... a[9]
	 |
	代表的是数组的下标
5.编译器不对数组越界检查。
	a[-1] 不会出错
	a[10] 不会出错

输入的使用:
	定义的时候赋值:
	int a[10] = {1,2,3,4,5,6,7,8,9,10};
	int a[10] = {1,2,3,4,5,};
	a[0]-a[4] 他里面的值1,2,3,4,5
	a[5]-a[9] 这里的值都是0

	int a[10] = {0};
	数组中的成员都是0
	
	int a[] = {1,2,3,4};
	这里a没指定数组成员的个数,但是初始化
	的时候给了4个处理,编译器就会给他4个
	int类型的大小
	
	先定义变量,在赋值
	int a[5];
	a[0] = 1;
	a[1] = 2;
	a[2] = 3;
	a[3] = 4;
	a[4] = 5;

练习:
	在终端上输入5个数,
	将这个5个数打印出来

PM:

【1】数组的首地址的问题
int a[5];

a:数组的首地址
	a+1 => 4字节 移动的是int类型

&a:对数组的首地址取地址
	&a+1 =>20字节 移动的是int [5]类型

&a[0]:取第0个元素的地址
	&a[0]+1 =>4字节 移动的是int类型
	
	             /\
|	变量  4       |
|-----------------|
|	数组 20       |
|-----------------|
|数组地址的地址   |
\/                |
升维            降维

【2】数组的排序问题
冒泡排序:拿相邻的两个数比较,如果前面
的数字大,就将这个两个数进行交换。否者不
交换

50  2 	-10  100  30    第几趟  比较次数
2   -10 50   30   100   i=0      4
-10 2   30   50         i=1      3
-10 2   30              i=2      2
-10 2                   i=3      1


趟:i=0  ===> i<N-1
趟内比较的次数:
	j=0  ===> j=N-1-i

选择排序:
从数组中随机选择一个数,和数组中的
其他成员挨个比较,如果这个数比数组中
的数小就交换数据。

day10

Linux c基础课程 第十天

【1】复习
控制语句:
1.goto
2.continue
3.return

数组
	int a[5] = {1,2,3,};
	int a[5] = {0};
	int a[] = {1,2,3,4,5};
	
	1.a++ 错误
	2.编译器不会对数组的越界检查
	3.认识下面内容
	a[0]+1  数值a[0]加上1
	&a[0]+1 向后移动4个字节
	a+1     向后移动4个字节
	&a+1    向后移动4*5个字节
	
	数组的排序问题:
	1.冒泡排序
	2.选择排序
	
作业:
	1.对选择排序效率进行优化,思想如下:
	通过比较数组中的两数,将最大数的数组的下标记下,
	当本趟比较结束后,进行一次数据交换即可。

	2.日历程序
	代码链接:https://github.com/daizhansheng/LIVE_NOTE/
	注意:
		大家把代码下载下来,给10分钟
		的时间,看不明白的地方直接问
	**/如果能看懂,今天晚上尝试自己在写一遍	/**

【1】字符数组
char a[5];

字符数组和整形的数组的特性是一样的,但是
字符数组在赋值的时候,赋值的是字符。
第一种情况:
char a[10] = {'h','e','l','l','o'};
	
for(i=0; i<10; i++) //它会把数组中的
	putchar(a[i]);	//成员全部遍历一遍
	
printf("%s\n",a); //%s打印的时候,遇到'\0'	
                  //就结束了
	
第二种情况:	
char a[] = {'h','e','l','l','o','\0'};	
		
for(i=0; i<5; i++) //它会把数组中的
	putchar(a[i]);	//成员全部遍历一遍
	
printf("%s\n",a); 
//%s打印的时候,遇到'\0'就结束了
//但是上述的数组中没有'\0'的成员,但是
//的时候可能,有可能不正确,如果想让让它
//正确,必须在最后的位置补充'\0'元素

第三种情况
char a[] = "hello"; 
printf("%s\n",a);  //正确的,赋值了6个成员
                   //最后一个是'\0'成员

PM:

【1】字符数组
1.字符串的拷贝
在终端上输入一个字符串,将这个字符串
保存在a[50]数组中 ,请将a[50]数组中的
字符拷贝到b[50]中。将b数组的内容打印
一下。
while(a[i])
b[j++] = a[i++];

2.字符串拼接
	请将b数组中的内容拼接到a数组后
	a[100] = 从终端上输入的
	b[50] = "no zuo no die"
	a[] = "hello worldno zuo no die"
	
	//1.找到a的尾部
	while(a[i]) i++;                                                                        
	//hello'\0'
	a[i++] = ' ';

	//2.将b追加到a的尾部
	while(b[j])
		a[i++] = b[j++];

3.求字符串的长度
	//1.找到a的尾部
	while(a[i]) i++;                                                                        
	printf("len = %d\n",i);

4.字符串的比较(作业)
	a[50] = "hello world";
	b[50] = "hello worlc"

	拿a数组中的字符和b数组中的字符
	做减法运算,如果差值
	大于0  a大
	小于0  b大
	等于0  接着比较下一个字符,如果
	到a,b的结尾都是相等的,认为这两个
	字符串相等。

【2】二维数组
int a[4][3];

1.二维数组在内存上也是连续的
2.二维数组的数组名也不允许做自加操作
  应为a也是常量
3.a[4]       [3]
	|         |
  行下标     列下标
4.在定义数组的时候行下标可以省略,
	列下标不能省略

二维数组的初始化
int a[3][2] = {1,2,3,4,5,6};
int a[3][2] = {
   
   {1,2},{3,4},{5,6}};
int a[][2] =  {
   
   {1,2},{3,4},{5,6}};
int a[3][] =  {
   
   {1,2},{3,4},{5,6}}; //错误的

二维数组如何访问(遍历)
a[0][0]
a[0][1]
a[1][0]

练习:
1.将二维数组中最大值的
	行和列的下标打印出来

2.打印杨辉三角(前10行)

	   
	1        
	1  1
	1  2  1
	1  3  3  1
	1  4  6  4  1
	1  5  10 10 5 1		
				
	int a[10][10];
		
作业:
	1.字符串的比较(作业)
		a[50] = "hello world";
		b[50] = "hello worlc"
	
		拿a数组中的字符和b数组中的字符
		做减法运算,如果差值
		大于0  a大
		小于0  b大
		等于0  接着比较下一个字符,如果
		到a,b的结尾都是相等的,认为这两个
		字符串相等。
	2.打印如下内容
		int a[4][3];
		&a  a  a[0] &a[0][0]  打印四个地址
		加1后移动的字节的个数
		&a+1
		a+1
		a[0]+1
	    &a[0][0]+1

day11

Linux c基础课程 第十一天

【1】复习
字符数组
char a[10] = {‘h’,‘e’,‘l’,‘l’,‘o’};
char a[] = {‘h’,‘e’,‘l’,‘l’,‘o’,’\0’};
char a[] = “hello”;

for(i=0;i<10;i++)
	putchar(a[i]);

printf("%s",a);
puts(a);

二维数组
	int a[4][3] = {1,2,3,4,5,};
	int a[4][3] = {
   
   {1,2,3},{1,},{2,3,4}};
	int a[][3] = {
   
   {1,2,3},{1,},{2,3,4}};
	
	二维数组的遍历方式:
		两层for循环
		
		for(i=0; i<4; i++){
			for(j=0; j<3; j++){
				printf("%d\n",a[i][j]);	
			}
			
		}

作业:
1.字符串的比较(作业)
a[50] = “hello world”;
b[50] = “hello worlc”

	拿a数组中的字符和b数组中的字符
	做减法运算,如果差值
	大于0  a大
	小于0  b大
	等于0  接着比较下一个字符,如果
	到a,b的结尾都是相等的,认为这两个
	字符串相等。
2.打印如下内容
	int a[4][3]; int b[3]
	&a  a  a[0] &a[0][0]  打印四个地址
	加1后移动的字节的个数
	&a+1 =>48
	a+1  =>12
	a[0]+1=>4
	&a[0]+1=>12
	&a[0][0]+1=>4

	int a[3];
	&a+1    12 
	a+1     4
	&a[0]+1 4
		
二维数组   一维数组   变量		
<-----------升维-----------	
------------降维----------->	

如果要计算一个地址加1移动的字节的个数:
地址加1 ==>降维 ==> 降维之后类型占用多少
                    个字节就代表向后移动多
                    少个字节。
如果地址+1,这个地址前有"&",代表升降维度抵消。


二维字符数组
	char a[10][10] = {"hello","hahaha"};
	char a[][10] = {"hello","hahaha"};
	char a[10][10] = {
   
   {'h','e','l','l'},{'r',}};

	for(i=0;i<2;i++){
		//printf("%s",a[i]);
		printf("%s",&a[i][0]);
	}

【2】指针
地址:存储器的每一个字节都有编号,这个编号就是地址
指针:地址就是指针,指针就是地址
指针变量:指向变量地址的变量就是指针变量。

以后再用的时候,统称为指针。

指针的格式
	char  *p;  
	short *t;
	int   *q;
	long  *b;
	注意:在定义变量的时候,这里的*只代表
		  定义的变量是指针变量,并没有代表取
		  地址中的内容的函数。
认识两符号:
	& :取地址
	* :在指针变量前加*,代表可以读写这块内存


指针实例:
    int a = 10; 
	int *p = &a; 
	printf("*p = %d\n",*p);	//10
	*p = 100;
	printf("a = %d\n",a);  //100
	printf("&a = %p,p = %p,&p = %p\n",&a,p,&p);
             |          |      |
            a的地址  a的地址  p变量的地址

PM:
【1】指针占用内存大小
在32位操作系统上,所有的指针都是
占用4字节。因为32位操作系统存储设备
的编址是用4字节来表示的。

指针变量加1移动的大小是它指向的变量类型
的大小。

short a = 10;
short *p = &a;

p+1==>short=>2字节

【2】指针变量的应用
指针变量使用必须遵从如下三个步骤
1.定义指针变量
2.为指针变量分配内存
3.使用指针变量

注:如果在定义完指针后,没有给指针
赋初值,这个指针就是野指针,这个野指针
可能导致不可预期的后果。

如何规避野指针,在定义指针的时候赋NULL;

https://github.com/daizhansheng/LIVE_NOTE/04point.c

【3】指针和一维整形数组
int a[5] = {1,2,3,4,5};
int *p = a;

a[i]<===>*(a+i)<===>p[i]<===>*(p+i);

实例见:
	05point.c
	06point.c

【4】指针和一位字符数组的结合
char a[] = “hello world”;
char *p = a;
printf(“a = %s\n”,a);
printf(“p = %s\n”,p);

char a[] = "hello world";
char *p = "hello world";
*a = 'w'; //正确的

// *p = ‘w’; //错误的

// a++; //错误的
p++; //正确的 p = p + 1;
p = a; //正确的 p = a

【5】应用层内存段的划分
|-----------------------------------
|堆区:使用malloc函数分配的
| 内存就在这个区间。
|-----------------------------------
|栈区:用户的函数的执行,函数
| 内部定义的局部变量,都在
| 栈区。
|-----------------------------------
|静态区 |.data:
| |存放的是已初始化的全局变量,
| |static修饰的已初始化的全局变量。
| |-----------------------------
| |.bss(这里的初值都是0)
| |未初始化的全局变量,static修饰的
| |未初始化的变量
| |-----------------------------
| |.ro (.rodata)(只读的数据段)
| |char *p = “hell world”;
| |-----------------------------
| |.text:存放程序代码
| |
|------|-----------------------------

【6】作业:
char a[100] = {0};
a数组中的内容是从终端上输入的

char b[50] = "hello";

在a对应的字符串口,查找b字符串,如果找到了b
字符串将a中这个b字符串的首地址返回。
                  a          b  
                  |          |
char *strstr(char *src,char *sub);
{
	//your code
	如果查找成功返回,src中b字符串的首地址
	如果没找到返回NULL
}

day12

Linux c基础课程 第十二天

【1】复习
指针:
int t;
char *a;
short *b;
int *c;

	c = &t;
	
	*c = 10;
指针占用内存(32位)
	4字节
	
指针加1移动的大小
	指向的类型所占的内存的大小
	
指针和数组的关系:
	int *p;
	int a[] = {1,2,3,4,5};
	p = a;
	
	*p++;
	
	a[i]===*(a+i)====*(p+i)===p[i]
	
	p = &a[2];
	p[-1] = 100;
	
	
	char a[] = "hello world";
	char *p = a;
	
	printf("%s\n",a);
	printf("%s\n",p);
	
	char a[] = "hello world";
	char *p = "hello world";
	
	a++;      //错误
	*a = '2'; //正确
	
	p++;      //正确的
	*p = 'r'; //错误
	
	p = a;  //正确的
	a = p;  //错误的
	
作业:
	char a[100] = {0};
	a数组中的内容是从终端上输入的
	
	char b[50] = "hello";
	
	在a对应的字符串口,查找b字符串,如果找到了b
	字符串将a中这个b字符串的首地址返回。
					  a          b  
					  |          |
	char *strstr(char *src,char *sub);
	{
		//your code
		如果查找成功返回,src中b字符串的首地址
		如果没找到返回NULL
	}

【2】二级指针
char **q;
int **p;

二级指针是指向一级指针的地址
int a = 10;
int *p = &a;
int **q = &p;

&a = p = *q
&p = q
	
a = *p = **q
	
二级指针是指向以及指针的地址,一般
在函数调用的时候使用。
	
作业:
	实现字符串比较的函数。
	int strcmp(char *s1, char *s2);

PM:

【1】指针数组
定义的格式:
char *p[5];
int *t[5];

指针数组的含义:
	指针数组它是一个数组,
	数组中的内容全部是指针
	
指针数组的用法:	
    int b[3] = {50,100,150};
	int *a[3],i;

	a[0] = &b[0];
	a[1] = &b[1];                                                                           
	a[2] = &b[2];

	for(i=0; i<3; i++){
		printf("%d\n",*a[i]);
	}
		
		
用法二:		
int main(int argc, const char *argv[])
argc:命令行参数的格式
argv:执行命令行传递的字符串
	
for(i=0; i<argc; i++){
    printf("%s\n",argv[i]);                                                             
}   

	
命令执行代码的方式	
 ./a.out  fsdf sfdsdf 123 1231 12312

argv[0] = "./a.out"
argv[1] = "fsdf"
argv[2] = "sfdsdf"
argv[3] = "123"


将字符串转化为整数的函数
./a.out "123" "456"
         p
val = 0;
val += val*10 + (*p++ - '0');

#include <stdlib.h>

int atoi(const char *nptr);
功能:将字符串转化为整数
参数:
	@nptr:字符串的首地址
返回值:转化得到的整数

【2】数组指针
格式:
char (*p)[3];
int (*q)[3];

含义:
它是一个指针,执行一个二维数组

赋值:
	int  (*q)[3];
	int  a[4][3];
	q = a;
	
	理解的方法:把a[4]看成一个整体,
	由于a[i] = p[i] = *(a+i) = *(p+i);
	所以它和*p是一样的,那a[][3] = (*p)[3]
	即q = a;


总结:
a[i][j] <====> *(a[i]+j) <===>*(*(a+i)+j)
p[i][j] <====> *(p[i]+j) <===>*(*(p+i)+j)

a:      二维数组的名字,二维数组的首地址
a[0]:    第0行的首地址
a[0][0]: 二维数组首个元素
&a[0][0] 二维数组首个元素的地址
&a[0]    取第0行的地址
&a       取二维数组的地址

int (*p)[3]; //数组指针,指针,它指向一个二维数组
int *p[3]; ://指针数组,数组,数组中是指针

练习题:
用变量a给出下面的定义
a) 一个整型数
int a;
b) 一个指向整型数的指针
int *a;
c) 一个指向指针的的指针,
它指向的指针是指向一个整型数
int **a;
d) 一个有10个整型数的数组
int a[10];
e) 一个有10个指针的数组,该指针
是指向一个整型数的
int *a[10];
f) 一个指向有10个整型数数组的指针
int (*a)[10];

练习题:
1.int a[5][4], (p)[4]=a;,数组a
的首地址为100,
(p+2)+3等于_C_

A、116 B、118 C、144 D、122

	
p+1:  4*4=16
a+1:  4*4=16
p+2:  16*2 = 32
*(p+2) = p[2] => a[2] 行地址

*(p+2) +  3 = 32 + 3*4; = 44

练习:求p[-1]、p[-5]的值
(此题重点在于负号,很简单,考察对指针了解的广度方面)
#include <stdio.h>
int main(void)
{
char* p = NULL;
char* tmp = “12345678”;
p = (char* )(tmp+4);
//p[-1] = ?, p[-5] = ?。
printf("%s\n",p);
return 0;
}

4,不确定

第3题:求p[0]–p[5]的值(这个才有点点挑战)
#include <stdio.h>
int main(void)
{
char* data = “12345678”;
short* tmp = NULL;
char p[6] = {0};
tmp = (short *)&p[2];
*tmp = atoi(&data[4]);
//p[0] = ?, p[1] = ?,
//p[2] = ?, p[3] = ?,
//p[4] = ?, p[5] = ?。

	//结果使用十六进制表示
	
	  return 0;
}

结果:
0   0  0x2e   0x16  0  0

请判断一个机器是大端还是小端
小端:数据底位在底地址中存放,高位在高地址中存放
大端:数据底位在高地址中存放,高位在底地址中存放

int a = 0x12345678;
char b = (char)a;
if(b ==0x78){
	小端
}else{
	大端(0x12)
}

作业:
有一个以空格为分隔符的
字符串"this is a book",
以单词为单元将其逆置,
变为"book a is this" (不允许定义新数组)

char buf[100] = "this is a book";

思路:
	1.将这个字符串先进行一次前后位置的颠倒
	koob a si siht
	
	2.以空格为风格为,进行单词的颠倒
	book a si this

day13

Linux C基础课程 第十三天

【1】复习

二级指针:指向一级指针的指针
int a = 10;
int *p = &a;
int **q = &p;

a:变量     地址:0xc0 存放的值:10
p:指针     地址:0xd0 存放的值:0xc0
q:二级指针 地址:0xf0 存放的值:0xd0

q:是二级指针它存放的是以及指针的地址

q = &p;

*q = p; *q代表去二级指针中的值

*q++   ==>q++   在取*
		*q++  ===> 0xc0;
		 q    ===> 0xd4;
(*q)++ ==>p++;===> p = 0xc4 	

**q    ==>a


-------------------------------
q = &p;

p++; 
p => 0xc4
q => 0xd0

(*q)++ ==>p++;===> p = 0xc4 	

p => 0xc4
q => 0xd0

指针数组:
	char *p[3];
	//注意:如果有括号,先读括后面的内容
	//如果没有括号,从前往后读。
	
	它是一个数组,数组中存放的是指针
	
	p[0] = "he"
	p[1] = "he"
	p[2] = "he"

	printf("%s\n",p[0]); //%s后面跟的是地址
	putchar(*p[0]); ==> 'h'

数组指针
	char (*p)[3];
	char a[3][3];
	a[i][j]=*(a[i]+j)=*(*(a+i)+j)
	p[i][j]=*(p[i]+j)=*(*(p+i)+j)

作业:
有一个以空格为分隔符的
字符串"this is a book",
以单词为单元将其逆置,
变为"book a is this" (不允许定义新数组)

char buf[100] = "this is a book";

思路:
	1.将这个字符串先进行一次前后位置的颠倒
	koob a si siht
	
	2.以空格为分割符,进行单词的颠倒
	book a si this	

PM:

【1】函数(组成c语言的最基本的单元,函数)

函数的定义格式
<存储类型> <返回值类型><函数名字>(参数列表)
{
	函数体;
	return ;
}

函数的三要素:
	1.功能唯一
	2.有固定的输入
	3.有固定的输出

封装函数的原则:
	高内聚,低耦合


函数的返回值类型:
	void   无返回值
    void * 
	char
	char *
	int 
	int *
	long 
	long *
	float
	float *
	double 
	double *
	等等

函数名字定义格式:
	1.函数名必须是数字,字母,下划线组成的
	2.函数做到见名知意
	3.函数命名格式
	
	void check_word(void)
	{
		
		
	}
	
	void CheckWord(void)
	{
		
	}
函数的参数列表:
	1.函数如果没有参数列表,
	可以不写,或者写成void
	
	2.传递的的参数
		2.1.值传递:在函数中修改形参数的值,
			实参拿不到修改后的结果
		2.2.地址传递
		
		2.3.传递数组:不是将数组的所有成员
		都传递过来了,是传递过来了首地址。
		void access_array(int a[3])
		{
			printf("sizeof a = %d\n",
				sizeof(a)); //结果是4
		}
	3.参数列表一般小于等于4个效率最好
	
函数的返回值:
	函数的返回值要和函数的返回值类型相同
	
	
函数嵌套问题:
	在一个函数内,你可以调用
	一次或者多次另一个函数。
	
	在一个函数内,你可以调用自己(递归)
	
	
	求n!使用递归函数实现
	n! = n *(n-1)*(n-2)...2*1;
	int fact(int n)
	{
		if(n==1) return 1; //递归一定要注意结束条件
		return n*(fact(n-1));
	}

指针函数(函数的返回值是一个指针。)
char *chang_word_position()
{
	return 地址;
}

eg:(如下写法是错误的)
	int * return_number(void)
	{
		int a = 10;
		//a是一个局部变量,在函数调
		用的时候被分配内存,当函数
		执行结束,这个内存就被操作
		系统释放了 
		return &a;			
	}

函数指针
	int (*func)(int a,int b);
	
	它是一个指针,它指向了一个函数。
	int add(int a,int b)
	{
		return (a+b);
	}
	int (*func)(int,int) = add;   
    printf("sum = %d\n",add(5,10));
	printf("sum = %d\n",func(5,10));
	printf("sum = %d\n",(*func)(5,10));

【2】c语言中的存储类型(6个)
auto:(自动类型)
在定义变量的时候,变量前默认就是auto
auto int a; 等于 int a

	非自动类型的变量:
	1.全局变量
	2.static修饰的变量
	
register:寄存器类型的变量
	register int a;
	寄存器类型的变量,要不普通的变量执行效率要高。
	在一个soc(system on chip)上寄存器的个数是有限
	在(A53:40)
	
static:
	static 修饰的变量如果没有初始化默认为0;
	static int a;
	printf("a = %d\n",a); //结果是0
	
	作用:1.延长变量的生命周期
			void static_fun()
			{
				static int a = 1;
				a ++; 
				printf("a = %d\n",a);                                                                   
			}
			static_fun();  //2
			static_fun();  //3

		  2.限制作用域
		  static修饰的函数或者变量只能在本文件
		  中使用。
		  
const:(只读变量)
	const int a=10;
	a = 100; //错误
	
	int a = 10;
	int b = 1000;
	const int *p = &a; 
	*p = 100;  错误的
	p = &b;    正确的
	表示p执行的内容不能修改,但是p是可以修改的。
	
	int a = 10;
	int b = 1000;
	int const  *p = &a; 
	*p = 100;  错误的
	p = &b;    正确的
	表示p执行的内容不能修改,但是p是可以修改的。
	
	
	int a = 10;
	int b = 1000;
	int * const p = &a; 
	*p = 100;  正确的
	p = &b;    错误的
	*p可以修改,p不允许修改
	
	const int  * const p = &a;
	代表*p和p都是只读的。
	
	
extern:
	extern int a;
	extern int add(int a,int b);
	
	a或add函数定义没有在当前的.c中,它是
	在另外一个.c中定义的。
	
volatile:(容易改变的)
	
	volatile int *p = 
		(volatile int *)0x8000000; (地址中保存的是10)
	
	*p 取出地址中的值10; 
	//(硬件将0x8000000地址中的值改为了100);
	//由于地址中的数据不是别这个程序修改的,
	//所以下面这个式子在运算的时候,还是拿的之前的
	//数据
	y = *p + 1;  //不加volatile是11  
	             //如果加volatile就是101
				 
	总结:防止编译器对变量优化,每次在使用这个变量
		 的值的时候,都需要重新从内存上取值。


猜你喜欢

转载自blog.csdn.net/weixin_48430195/article/details/108681953