一、在计算机中数据的表现形式
二进制:逢二进一
八进制:逢八进一
十进制:逢十进一
十六进制:逢十六进一
一般计算机都是二进制语言
二、数制之间的转换
- 二进制转八进制:
三位二进制为一位八进制数
- 十进制转二进制
运用短除法取余来转换
- 二进制转十六进制
四位二进制数为一位十六进制数
三、C语言的编程规范
所有的c程序都是从主函数开始到主函数结束
在c语言中{ }表示一个模块,模块之间要注意缩进
;(分号)代表一条语句的结束
return:遇到return关键字代表程序结束
四、C语言中的词法符号
- 标识符
标识符是程序员按照命名规则自定义的词法符号
标识符的命名规则
由数字、字母、下划线组成
不能以数字开头
不能与关键字重名
C语言的32个关键字
存储类型:
auto,register,static,const,volatile,extern
数据类型
char,short,int,float,long,double,signed,unsigned
结构体类型
struct,union,enum
语句类型:
if,else,switch,case,break,default,while,do,for,continue,goto,return
空类型:
void
重命名:
typedef
求字节:
sizeof
在C语言当中要严格区分大小写
- 运算符
赋值预算符
+=,-=,/=,*=
算术运算符
+,-,*,/,
++,--
前++:先取值再自增
后++:先自增再取值
位运算符
~:位非,按位取反
&(与):位与,按位比较
|(或):位或
^(异或):相同为0,不同为1
<<(右移):
表达式1)<<(表达式2)
正数:高位舍去,低位补0
负数:高位舍去,低位补0,最后最高位置1
>>(左移):
(表达式1)>>(表达式2)
正数:低位舍去,高位补0
负数:低位舍去,高位补1(用补码运算)
关系运算符
>,<,==,<=,>=,!=(不等)
逻辑运算符
&&: 逻辑与,全1为1,有0则0
| | :逻辑或,全0为0,有1则1
!:逻辑非
短路法则:
逻辑与:如果前一个表达式为假,则不运行下一个表达式,运行结果为0
逻辑或::如果前一个表达式为真,则不进行下一个表达式,运行结果为1
逗号运算符
以逗号最右边的作为运算结果
三目运算符
(表达式1)?(表达式2):(表达式3)
符号含义:如果表达式1为真则表达式2为运算结果,如果为假,则表达式3为运算结果
求字节
sizeof:求数据类型或变量的字节
原码,补码,反码
对于一个有符号的机器码来说,第一位为数字的符号位,1为负,0为正
原码:机器码
反码:
正数:原码
负数:符号位不变,其他位按位取反
补码:
正数:原码
负数:反码加一
注意:计算机中存储的数据都是存的数据的补码
运算符的优先级:
五、C语言中数据的表现形式
- 常量
程序运行中不能被修改的数据
整形常量
实型常量:
十进制小数形式
指数形式:
3.14e1
规范化指数形式:小数点前一位为0,小数点后第一位不为0
字符型常量:
''括起来的单个字符,'a'
转义字符:
\n换行 \t--tab
字符串常量:
" "括起来的字符串
符号常量:
#define N 100//放在程序的开头 宏定义
- 变量
程序运行过程中能被改变的数据--保存数据
定义变量的一般形式:
<存储类型><数据类型>变量名:
存储类型:
auto:自动存储类型
在定义局部变量时,用auto显示声明代表该变量在栈区(先入后出的一种存储方式)随机分配一片存储空间。如果在定义变量是缺省存储类型,改变变量默认为auto类型
register:寄存器类型
声明的变量在程序运行时直接加载到寄存器上,但是计算机上寄存器有限,可能加载失败,失败后自动转为auto类型
extern:引用类型
该变量不能初始化,代表该变量在别处定义,要在此处使用
1.在一个文件中扩张全局变量的作用范围。
2.在一个源程序中扩展一个全局变量的范围
static:静态类型
1.修饰全局变量,限制全局变量只能在本文中使用
2.修饰局部变量,将局部变量的生命周期延长到整个程序结束,并且该变量只会被定义一次
const:修饰只读
const 修饰的变量,只能读不能写(不能被改变)变量常量化
该变量不能作为等号左值
数据类型:
整型:
char 字符型 一个字节
unsigned:0-255
signed:-128~127
char C;//不说明默认为有符号数
short:短整型 两个字节
int:整型 四个字节
long:长整型 八个字节
浮点型:
flaot :单精度浮点型 四个字节
精确度:小数点后6-7位
double:双精度浮点型 八个字节
精确度:小数点后15-16位
变量名:标识符
命名规则:
1.由字母、数字、下划线组成
2. 不能以数字开头
3. 不能与关键字重名
变量的初始化
在定义的时候赋值
例:int a=10;
int a,b,c,d=10
变量的赋值
例:int a,b,c,d;
char c;
a=10;
c= 'a';
全局变量,局部变量
全局变量:
定义位置:定义在所有模块({})之外的变量
生命周期:从定义开始,到程序结束
使用范围:整个源文件
没有初始化:默认为0
局部变量:
定义位置:定义在所有模块({})之内的变量
生命周期:从定义开始,到模块结束
作用范围:在定义它的模块中
没有初始化:默认为随机值
六、C语言的输入输出
- 格式控制字符串
格式控制符+其他字符
%d--按十进制有符号整数格式输出
%u--按十进制无符号整数格式输出
%md--指定占m域宽,默认右对齐
%-md--默认左对齐
%ld--按十进制有符号长整型格式输出
%o--按八进制无符号整数格式输出
%#o--带前缀
%x--按十六进制无符号整数格式输出
%p--输出一个地址
%f--输出单精度浮点型数据--隐含六位小数
%.nf-输出单精度浮点型数据--指定保留n位有效数据
%lf--输出双精度浮点型数据
%c--输出单个字符
%s--输出一个字符串
%.ns--输出字符串的前n个字符
%%--输出一个%
- scanf--标准输入函数
scanf(“格式控制字符串”,地址列表)
int a=10;
scanf("%d",&a);
格式控制字符串:
格式控制符+其他字符
其他字符:按照原样输入
地址列表:&变量
注意1:在输入数值型数据时,空格、回车、tab都属于无效字符相当于输入结束
注意2:在输入字符型数据时,空格、回车、tab都算是有效字符--脏字符
消除脏字符:%*c
getchar()
返回值:为按照格式正确输入的个数
- printf--标准输出函数
printf(“格式控制字符串”,输出列表)
输出列表:从左到右与控制符一一对应,用逗号隔开
4.getchar--字符输入函数
char ch=0;
ch=getchar();
可以用来消除脏字符
5.putchar--字符输出函数
char ch ='x'
putchar(ch);
putchar('x');
- gets--字符串输入函数
char a[20];
gets(a);
7.puts--字符串输出函数
char strp[20]="hello world";
puts(strp);
注意:打印完字符串之后会自动换行
七、数据类型转换
- 自动类型转换
1.当用一种数据类型的数据,给另一种数据类型的变量赋值时会发生自动类型转换
int a=3.14;//最后输出a=3
2.C语言当中两个整数的数据相除,结果还是一个整数。
3.当多种数据类型的数据发生混合运算时
转换规则:数据会向精确度增加的方向转换
float f=5/2+3.14; //最后f=5.14
float f2=5.0/2+3.14//最后f2=5.64
2.强制类型转换
(数据类型)数据://将数据转换成()里指定的数据类型
int a=5;
int b=2;
float f= (float)a/b;
八、C语言的语句结构
- 顺序结构
C语言按照顺序执行
- 选择结构
1)if语句
if(表达式)
{
语句块1;
}
else
{
语句块2;
}
注意1:如果if或者else后面只有一条语句,{}可以省略
2)switch语句
switch(表达式)
{
case 表达式1:
语句块1;
break;
case 表达式2:
语句块2;
break;
……
case 表达式n;
break;
default:
语句块n+1
}
表达式:整型表达式
表达式1-n:整型的常量表达式
step:表达式1-n哪一个与表达式相等,如果相等则执行表达式n后面的语句块,如果遇到break则停止,没有遇到break关键字则顺序执行后面的语句
- 循环结构
1)while循环--当型循环
while(表达式)
{
语句块;
}
step:判断表达式,如果表达式为真,则执行语句块,然后继续判断表达,如果表达式为真则继续执行语句块,否则结束循环。
2)do {}while()循环--直到型循环
do
{
语句块;
}while(表达式);
step:执行语句块,然后判断表达式,如果表达式为真则继续执行语句块,否则结束循环。
break:
1.在switch语句中遇到break关键字,结束switch语句。
2.结束当前循环
continue:跳过本此循环,执行下一次循环。
3)for循环
for(表达式1;表达式2;表达式3)//三个表达式用分号隔开
{
语句块;
}
表达式1:一般是循环变量的初始化,只会在第一次进入循环时执行一次
表达式2:循环结束的条件
表达式3:一般是循环变量的自增或自减
4)goto--无条件跳转语句
goto 标签;
标签:标识符
step:当程序执行过程中,遇到goto关键字,自动跳转到标签处,继续执行下面的操作
goto后面的标志不能放在定义语句的前面
九、数组
同种数据类型数据的有序集合
- 数据定义的一般形式
<存储类型><数据类型>数组名[元素个数];
数组名:
1.标识符。
2.是整片数组空间的起始地址,代表了整片数组空间
注意:数组名是一个地址常量
long len =sizeof(a);
元素的个数:整型的常量
[ ]:
1.在定义变量[]代表定义是一个数组
2.对于地址来说,偏移并引用
取数组元素:a[下标]--下标从0开始
int a[5];//a[0]--a[4]
数组的清零:memset(数组名,想要清零的样式,想要清零的空间)
2.数组的初始化
1)完全初始化
有多少个元素,就赋多少个初值
int a[5]={11,22,33,44,55}
2)部分初始化
前面依次赋 值,后面没有赋值的自动补0
int a[6]={11,2,3}//给前三个元素初始化,没有初始化的元素默认为0
3)省略初始化
省略的是下标,计算机根据数组后面初始化赋值的个数来开辟对应的空间地址
int a[]={3,3,4,42,4}
3.数组元素的赋值
int a[10]=|{1,2,3};
int b[10];
b=a;//error
-------
int a[5];
a[5]={2,3,4,4,5};//error
-----------
注意:在数组定义之后,只能逐个给每个数组元素赋值
int a[3]={0};
a[0]=11;
a[1]=1;
a[2]=6;
十、字符数组
1.字符数组的初始化
1)完全初始化
char str[5] ={'h','e','l','l','o','\0'};在用%s打印的时候要用\0或者0来结束
printf ("%s\n",str);
字符串常量:" "括起来的一串字符,所有的""括起来的字符串后都有一个隐藏的'\0'
注意:在c语言当中可以用字符串常量来给字符数组初始化
char str[6]="hello";//要开辟足够的空间来保存'\0'
2)部分初始化
char str[10]={'h','e'};
="he";//未定义的默认为'\0'
3)省略初始化
char str[]="hello";
2.字符串操作函数
1)strcpy
头文件:
#include <string.h>
函数的原型:
char *strcpy(char *dest,const char *src);
描述:
将src所指向的字符串,复制到dest所指的数组。
参数:
dest:接收被复制字符的数组
src:字符串的首地址
char str[10];
strcpy(str,"hello");
返回值:
返回dest
2)strlen
头文件:
#include<string.h>
函数的原型:
size_t strlen(const char *s);
描述:
计算s所指向字符串的有效长度。不包括'/0'
参数:
s指向的字符串的首地址
返回值:
s所指向字符串的有效字节数
注意:strlen计算字符串有效长度,只要遇到'\0'就停止计算
3)strcmp
头文件:
#include<string.h>
函数的原型:
int strcmp(const char *s1, const char *s2);
描述:
判断两个字符串是否相同
比较规则:对位比较
参数:
s1:字符串
s2:字符串
返回值:
如果s1>s2,但会大于0的整数
s1<s2,返回小于零的整数
s1==s2,返回值为0
4)strcat
头文件:
#include<string.h>
函数的原型
char *strcat(char *dest, const char *src);
描述:
将src所指向的字符串拼接到dest所指向的数组后面
参数:
src--字符串的首地址
dest--字符数组名
返回值:
dest
5)strstr
头文件:
#include<string.h>
函数的原型
char *strstr(const char *haystack, const char *needle);
描述:
在haystack中所指向的字符串中,找needle所指向的字符串第一次出现的位置
参数:
haystack--字符串
needle--字符串
返回值:
如果找到则返回第一次出现位置(地址)
十一、二维数组
1.二维数组的定义
<存储类型><数据类型> 二维数组名[行号][列号];
int a[1][2];
二维数组名:是整个二维数组的首行地址,代表了整片数组空间
行号,列号:整型的常量
[]:对地址来说,偏移并引用
注意二维数组名还是一个地址常量
去二维数组的元素:a[行号][列号]--行号,列号都从零开始
2.二维数组的初始化
1)完全初始化
int a[2][3]={1,2,3,4,5,6}
={1,2,3,},{4,5,6}
2)部分初始化
int a[2][3]={1,2,3};//给第一行的三个元素赋值,其余的剩下默认为0
int a[2][3]={{1},{2}};
3)省略初始化
注意:行号可以省略,但是列号不能省略。
int a[][3]={1,2,3,4,5,6};
十二、指针
指针就是地址,地址就是指针
地址--内存单元的编号(一般用十六进制的帧数表示)
指针、地址、指针变量。
指针变量用来保存地址(指针)
1.指针变量的定义
<存储类型><数据类型> *指针变量名;
<数据类型>+* --构成了一个新的数据类型--指针类型
存储类型是指针的存储类型
在64位操作系统中,所有的指针变量都占8个字节
*和&互为逆运算
int a=10;
int *p=&a;
char ch ='a';
char *q=&ch;
存储类型是指针的存储类型,数据类型是指针指向对象的数据类型,指针的大小和数据类型没有关系,32位是4,64的大小8
2.指针的运算符
&:取地址符--取变量的地址。
[]:
1.在定义变量时代表的是一个数组
2.偏移并引用。
*:1.定义变量时代表定义的是一个指针变量
2.取(引用)地址下的内容
int a =10;
int *p=&a;
p[0]=123;
printf("%d\n",a);//通过指针间接访问a所占的内存空间
*p=666;//通过指针间接访问a所占的内存空间
printf("%d\n",a);
3.指针变量的初始化
int a=0x11223344;
int *p=&a;
char ch = 'x';
char *q =&ch;
int a[5] ={1,2,3,4,5,};
int *p=a;
注意:在给指针变量初始化时,一定要类型匹配
小端存储:数据的低位,存储到地址低位
4.指针的赋值
1、把已知变量的地址赋给指针
int a=4; 12 int *p=&a;
2、把已知数组的首地址赋给指针
int a【5】={1,2,3,4,5};
int *p=a;====int *p=&a[0];
*和【】可以互换
指针变量名和数组名可以互换,注意,数组名是一个常量,指针是一个变量
3、指针赋值给指针
同级指针
4、把NULL赋值指针
相当于指针的初始化为0x00000000
5.指针的偏移
nt a[5];
int *p=a;
p++;
p++ ---指针向高地址偏移一个数据类型单位。
p-- ---指针向高地址偏移一个数据类型单位。
p+N ---指针向高地址偏移N个数据类型单位--N为一个整数
p-N ---指针向低地址偏移N个数据类型单位
p-q ---两个指针相减表示两指针之间相差多少个数据类型单位
注意:在c语言中同种类型的指针才能运算
6.特殊指针
野指针:
没有指向的指针,比较危险,在定义指针变量时没有初始化,里面保存的是随机的地址。
int *p;
char *p;
避免野指针的出现
int *p=NULL;
注意:如果暂时不知道指针指向,尽量初始化为NULL.
空指针:
NULL--代表0地址空间,不允许访问,一旦访问直接报段错误(非法访问内存)
空类型的指针:
使用空类型指针时必须强制类型转换。
void *p;//p为空类型的指针
int a=10;
void *p=(void *)&a;
*(int*p)
7.多级指针
指针的迭代,一级一级指向
二级指针--指向指针变量的指针
inta=10;
int*p=&a;
int**pp=&p;//指向p指针的指针
8.const修饰指针
const修饰*p
不能通过该指针修饰所指向的内容。
const char *p; char const *p;
const修饰p
这种类型的指针指向不能被改变
char *const p;
即修饰p也修饰*p
const char * const p;
这种类型的指针,既不能修改指针的指向,也不能修改指针所指向的内存空间里面的内容。
十二、数组指针--行指针
本质是一个指针,指向数组一行
1.数组指针定义的一般形式
<存储类型><数据类型>(*数组指针变量名)[N]
N:所指向数组一行有几个元素,是一个整型的常量。
intarr[3][4];
int (*p)[4]=arr;
p[i][j]
=(*(p+i))[j]
=*(*(p+i)+j)
十三、指针数组
同种数据类型指针的集合
1.指针数组定义的一般形式
<存储类型><数据类型>*指针数组名[N]
int*parr[5];
2.指针数组的初始化
inta[3][4]={1,2,3,4,5,6,,7,8,9,10,11,12}
int*p[3]={a[0],a[1],a[2];
for(inti=0;i<3;i++)
{
for(intj=0;j<4;j++)
{
printf("%3d",*(p[i]+j));
}
}
注意1:指针数组名,是整个数组空间的起始地址,代表了整片数组空间
longlen=sizeof(arr);//len = 16;
注意2:指针数组名,是一个地址常量,不能做等号左值。
十二、函数
能够实现特定功能的代码模块的封装
1.函数的作用
提高代码的复用率
增加了代码的可读性
增加代码的逻辑性
2.函数的定义
<返回值类型>函数名(形式参数)
{
函数体;
return返回值;
}
返回值: charshortintlongfloatdoublevoid
函数名:
1.标识符
2.整个函数的入口地址
形式参数:是各种类型变量,可以多个可以没有
函数体:
代码模块->函数功能的具体实现过程。
return:函数调用过程中,程序执行时,遇到return关键字代表整个函数结束,后面可以跟一个返回值,代表整个函数的运行结果。
注意:如果是void类型的函数,则没有返回值。
返回值:
函数只能有一个返回值,高返回值必须与函数的返回值类型对应
函数的三要素:
返回值,形式参数,函数体
3.函数的声明
告诉编译器,该函数是在别处定义,要在后续的程序中使用
声明方式
<返回值类型>函数名(形式参数);
voidPrint(intn);
声明位置:
1.放在调用之前--头文件之后,主函数之前。
2.放在.h文件之中
4.函数的调用
函数调用的一般形式
函数名(实际参数);
实际参数:与函数的形式参数一一对应,每一个实际参数之间用逗号隔开
作为语句调用
intn=0;
scanf("%d",&n);
Print(n);
作为表达式调用
char*p="hello world"
5.函数的传参方式
值传递:
传递数值
地址传递:
利用指针传递地址
数组传递
数组传数组
#include<stdio.h>
intswap(intb[32])
{
printf("b[3]=%d\n",b[3]);
}
intmain(intargc, char*argv[])
{
inta[32]={1,2,3,4};
swap(a);
return0;
}
数组传指针
#include<stdio.h>
intswap(int*b)
{
printf("b[3]=%d\n",b[3]);
}
intmain(intargc, char*argv[])
{
inta[32]={1,2,3,4};
swap(a);
return0;
}
6.static修饰函数
限制该函数只能在本文件中使用,其他文件调用该函数
同一源程序的其他文件可以定义同名的函数。
7.指针函数
本质上还是一个函数,只不过返回值是一个指针。
<返回值类型>*函数名(形式参数)//形式参数不要初始化
{
函数体;
return返回值;
}
<返回值类型>*:char*,int*....
void*:代表该函数返回值是一个空类型指针
注意:在定义指针函数时,不能返回一个内部局部变量的地址。
8.递归函数:
直接或者间接调用函数本身
#include <stdio.h>
int sum=0;
int digui(int n)
{
sum += n;
n++;
if(n<=100)
{
digui(n);
}
return sum;
}
int main(int argc, char *argv[])
{
int n=1;
printf("sum=%d\n",digui(n));
return 0;
}
9.回调函数:
以函数作为参数用函数指针接收传输
#include <stdio.h>
int callback()
{
printf("hello world\n");
}
int callback2()
{
printf("zhangcheng\n");
}
int zhangcheng(int (*zc)())
{
zc();
}
int main(int argc, char *argv[])
{
zhangcheng(callback);
return 0;
}
11.malloc函数:
在堆区申请一片空间
堆区:内存上的一片区域,是程序员手动开辟,手动释放
void*malloc(size_t size);
size:传一个整型的数据,代表申请多少个字节的空间。
返回值:如果申请成功,则返回一个空类型的指针,指向这片空间的其实地址,失败返回NULL。
释放堆区申请的空间
voidfree (void*p);
11.typedef:重命名已知数据类型
12.define:宏定义
define定义出来的是一个常量不可以修改
13.结构体:
可以存放任意数据类型的元素集合
struct(关键字)结构体名
{
数据类型 成员1;
数据类型 成员2;
数据类型 成员3;
。。。。
};//这里的分不能省略
结构体的初始化,按照定义的结构体的成员顺序依次赋值
结构体的调用,变量名.成员
1)结构体的赋值
字符串的赋值只能用strcpy函数赋值。
2)结构体的嵌套
#include <stdio.h>
#include <string.h>
typedef struct student{
int age;
char name[32];
int id;
char sex[32];
}STU;//结构体的定义
typedef struct teacher{
int age;
char name[32];
char sex[32];
STU zhangcheng;
}TEA;
int main(int argc, char *argv[])
{
/* STU zhangcheng;//结构体的初始化
zhangcheng.age = 18;
strcpy(zhangcheng.name,"zhancgheng");
zhangcheng.id=520;
strcpy(zhangcheng.sex,"man");*/
TEA zc = {20,"zc","man",{18,"zhangcheng",520,"man"}};
// printf("name=%s----age=%d\n",zhangcheng.name,zhangcheng.age);//结构体的成员调用
printf("name=%s----age=%d\n",zc.zhangcheng.name,zc.zhangcheng.age);//结构体的成员调用
return 0;
}
3)结构体数组
4)结构体指针
5)结构体的大小
字节序对齐,如果是成员最大的大小大于等于8,按照8字节对齐,如果最大的大小小于8,按照最大的数据类型字节对齐
偶数地址存储
验证方式:结构体的字节数是最大数据类型的倍数
14.共用体:union
和结构体的区别;
1.大小不一样,结构体计算每一个成员,按照字节序对齐方式存储,共用体计算最大成员的大小,字节对齐方式存储
2.存储方式不同,结构体所有成员分别存储不同的空间地址,共用体共用一个空间,只能一个一个存储。
15.枚举型:enum
#include <stdio.h>
int main(int argc, char *argv[])
{
enum week {
monday=3,tuesday,wednesday,thursday,friday,saturday,sunday};
printf("wesday=%d\n",wednesday);
return 0;
}