一,什么是c语言
一门通用的计算机编程语言(人和计算机交流的语言)
二,应用
广泛应用于底层软件开发(底层软件:即操作系统和驱动)
操作系统:如windows,Linux
驱动:链接电脑硬件和操作系统
三,工具
工具:编译器
常见编译器:clang, GCC , WlN-TC , SUBLIME , Turbo C等
四,C语言的基本知识 中文学习网站
(1)数据类型
(2)操作符
(3)关键字
(4)文件操作
(5)函数入门
(6)常用函数
(1)数据类型↑↑↑
char 字符数据类型(存放一个字母)1字节
short 短整型(存放数字)2字节
int 整形(存放数字)4字节
long 长整型(存放数字)4字节
long long 更长整形(存放数字)8字节
float 单精度浮点数(存放小数)4字节
double 双精度浮点数(存放小数)8字节
(2)操作符↑↑↑
1,算数操作符;+ - * / %取模、取余
int main()
{
float a = 9 / 2;
printf("%f\n",a); //此处打印结果为4
float b = 9 / 2.0;
printf("%f\n",b); //此处打印结果为4.5
除号左右两端只要有小数,打印结果才对
return 0;
}
2,移位操作符;>> <<(移动的是二进制位)
3,位操作符;&按位与 ^按位异或 |按位或
4,赋值操作符;= += -= *= /= &= ^= |= >>= <<=
a = a + 5;等于 a += 5://相同作用
a*=b—5等同于a=a*(b-5);
5,关系操作符;> >= < <= != ==
6,逻辑操作符;&&逻辑与 ||逻辑或(描述真假的问题)
7,下标引用操作符;[]
8,函数调用操作符;()
9,结构成员操作符; . ->
struct Stu
{
char name[20];
int age; //结构体内的成员变量
double score;
};
int main()
{ struct Stu a = {"老李“,16,99.5};//结构体的创建和初始化
printf("%s %d %lf\n",a.name,a.age,a.score);这里用到结构成员操作符中的点
struct stu* d = &a;
printf("%s %d %lf\n",(*d).name,(*d).age,(*d).score);
printf("%s %d %lf\n",d->name,d->age,d->score);三种打印结果一样
return 0; 这里用到箭头
}
单目操作符(只有一个操作数)
1,逻辑反操作 !
2,负值- 正值+
3,取地址 &
4,操作数的类型长度(字节) sizeof
5, 对一个数的二进制按位取反 ~
6,前置后置 ++ - -
(a++先取值再加,++a先加再取值)
7,强制类型转换()
8,间接访问操作符(解引用操作符)*
int main()
{ int a = 10;
peintf("%p\n",&a);//%p专门用来打印地址
int* c = &a;//c用来存放地址叫指针变量
//*号说明c为指针变量,int说明c的执行对象的类型
*c = 1;这里*号为解引用操作符,*c是通过c里面的地址找到a。并把a改为1
}
三目操作符(条件操作符)
Exp1?exp2:exp3
(exp1成立,exp2计算,整个表达式的结构是exp2的结果,否则为exp3)
(3)关键字{c提供,不能做变量名}↑↑↑
I auto自动
int main()
{ auto int a = 2;a为局部变量,在括号内自动创建自动销毁,auto一般都省略
}
I return返回
I void空,无
I break跳出循环
I continue继续、跳过本次循环后面内容
I char字符数据类型
I short短整型
I int整形
I long长整形
I float单精度浮点数
循环语句
I while循环 do用在do while循环 for循环
#include<stdio.h>
//在while循环中,break用于永久的终止循环
//while循环中,continue用于跳过此次循环中continue之后的内容
int main() //while循环
{
int a = 1;
while (a < 10)//小括号内不满足时跳出循环
{
printf("%d\n", a);
a++;
}
return 0;
}
//while先判断在循环
//do while先循环在判断
int main()
{
int i = 1;
do
{
printf("%d", i);
i++;
} while (i <= 10);
return 0;
}
//for循环
int main()
{
int i = 0;
for (i = 1; i <= 10; i++);//与while循环类似,i++最后执行
{
printf("%d", i);
}
return 0;
}
分支语句
I if语句 else语句 switch语句 以及default默认
int main() 分 | int main() 没有括号的话else与离得最近
{ int a = 10; 隔 |{ int a = 10; 的if匹配
if(a>8) 线 | if(a<8)
{ printf("ok"); | printf("no1");
} | else if(a >= 8 && a <= 12)
else | printf("no2");
{printf{"no"); | else if(a >= 12 && a <=20)
} | printf("no3");
} else不写的话为单分支 | else
下半部分else可不写 | printf("no4");
| }
——————————————————————————————————————————————————————————————————————————————
多分支的情况下用if else太麻烦,应采用switch语句 涉及到默认语句default
int main()
{ int day = 0;
scanf("%d",&day);
switch(day)
{
case 1: case后面要求为整形常量表达式,可以是1,2,3,4
printf("星期一"); 也可以是a,b,c,d
break; 也可以是1+2,3+4,6+7
case 2:
printf("星期二");
break;
case 3: case后的数决定“进”,break决定“出”,可以不加break
printf("星期三"); 如果不加break则为执行此case后所有内容
break;
case 4:
printf("星期四");
break; 如果不写break的话,printf也可以不写,
case 5: 结果会一直往下滑
printf("星期五");
break;
default: //默认 输入内容上面无匹配项
printf("输入错误");
break; 代码好习惯,最后加break
}
return 0;
}
I goto语句
I const修饰常变量
int main()
{
const int a = 10; //const修饰的常变量,后面不能再改a的值,此时a为常变量,需要常量的地方不能用a
return 0;
}
I enum枚举
enum xingbie
{
nan,
nu,
no //这种枚举类型的未来所能取的值
};
int main()
{
enum xingbie a = nan;
enum xingbie b = nu;
enum xingbie c = no;//枚举常量,只能取这3种上面定义过的结果。
return 0;
}
I extern声明外部(同一个工程内其他源文件的全局变量和函数)符号
int a = 2; |extern int a |线指的是分割左右两边2个源文件
int main() |int main()
{} |{printf("%d/n"a)}
I register寄存器关键字
int main() //a为大量频繁被使用的数据
{ register int a = 100;//建议吧a放在寄存器里面去。
}
I sizeof求大小
int main()
{ printf("%d/n",sizeof(int));
return 0;
}
I static静态的
static int b = 2;修饰全局变量,函数使其不可跨源文件使用(将函数的外部链接属性变成
void test() 了内部链接属性)
{ static int a = 1; a++; printf(“%d”,a);}
int main() 结果为2到11,static使得a在出局部范围时没有被销毁
{ int i = 0; 改变了a的生命周期,本质改存储
while(i<10)
{ test();
i++;
}
return 0;
}
I struct结构体
I typedef类型重定义(重命名)
typedef unsigned int u_int;
unsigned int a = 100;
u_int a = 100;这两个一样
I signed有符号的unsigned无符号的
I union联合体
I unsigned
I case
I volatile
(4)文件操作 ↑↑↑
FILE* pf = fopen(文件名,打开方式) {打开文件}
返回类型:文件指针,失败返回NULL。
fclose(文件名) {关闭文件}
“ab+” 打开一个二进制文件在文件尾进行读写 建立一个新文件
fputc(一个字符,文件指针) {写文件,一次写一个字符}
fputs(字符串,文件指针) {将字符串内的数据放入文件}
fgetc(文件指针) {读文件,一次读一个字符}
fgets(字符串,读取个数,文件指针) {从文件里读n个字符并放到字符数组内}
注意:是按照行来读的,一个fgets只读取一行
fscanf(流,目标) {格式化从文件获取}
列:fscanf(pf,“%d %f %s”,&(s.n),&(s.se),s.arr);
流:指针、屏幕stdout
fprintf(流,类型,目标) {格式化输入到文件}
列: fprintf(pf,“%d %f %s”,s.n,s.se,s.arr);
流:指针、键盘stdin、屏幕stdout
fread(内容地址,大小,读几个,文件指针) {二进制读出}
fwrite(内容地址,大小,写几个,文件指针) {二进制写入文件}
(5)函数入门 ↑↑↑
1.函数是什么
函数在维基百科中被定义为:子程序
在计算机中,子程序是一个大型程序中的部分代码,由一个或多个语句块组成。它负责完成某项特定的任务,而且相较于其他代码,具备相对独立性。
一般会有输入参数并有返回值,提供对过程的封装和细节的隐藏,这些代码通常被集成为软件库。
2.函数库和自定义函数
函数库:
使用函数库里的函数要先引用头文件。 如:#include<stdio.h>放在代码开头等等的例子
由于函数库的知识多而分散,我们一般只学习自己需要的就行了,进行讲解和举例也只是重复的在“造相同的车轱辘”,授人以鱼不如授人以渔。
请在>>>学习吧!猿种!(ง •_•)ง<<<进行查询和学习
自定义函数:
自定义函数和库函数一样,有函数名,返回值类型和函数参数。但是不一样的是这些都是我们自己来设计的。这给程序猿一个很大的发挥空间。
int M(int x, int y)//前面的int为返回类型,M为函数名,intx和y为函数参数
{ //形参
int z = 0;//要与前面的int呼应
if(x > y)
z = x; 函数的定义
else
z = y;
return z; //返回z,即较大值
} 创造一个需要的函数M,来求出a和b的较大值
int main()
{
int a = 1;
int b = 2; 函数的调用
int max = M(a,b);//实参
printf("max = ",max);
return 0;
}
3.函数参数
实际参数(实参):
真实传给函数的参数,叫实参,它可以是:常量,变量,表达式,函数等,无论实参是何种类型的量,在进行函数调用时,他们都必须有确定的值,一遍把这些值传给形参。
形式参数(形参):
形参是指函数名后括号中的变量,因为形参只有在函数被调用的过程中才实例化(分配内存单元),所以叫形参,形参在函数调用完之后自动销毁。
4.函数调用
传值调用:
函数的形参和实参分别占有不同的内存块,对形参的修改不会影响实参。
传址调用:
传址调用是吧函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式。
这种传参方式可以让函数和函数外边的变量建立起真正的联系,也就是函数内部可以直接操作函数外部的变量。
void Add(int* p)//void指的是不用返回return
{
(*p)++;
}
int main() 传址调用的栗子
{
int num = 0;
Add(&num);
printf("%d\n",num);//打印结果为1
Add(&num);
printf("%d\n",num);//打印结果为2
Add(&num);
printf("%d\n",num);//打印结果为3
return 0;
}
5.函数的嵌套调用和链式访问
嵌套调用
int test1()
{
test2(); //函数内部可以调用其他函数,嵌套调用
} //函数不能像套循环那样嵌套定义
int main()
{
test1();
test2();
return 0;
}
链式访问
#include<string.h>
int main()
{
int len = strlen("abc");
printf("%d\n,len);
//上面==下面
printf("%d\n",strlen("abc"));//链式访问,不用再创建len
}一个函数的返回值作另一个函数的参数
int main()
{ //printf的返回值为打印在屏幕上的字符个数
printf("%d",printf("%d",printf("%d",43)));
} 结果为4231
6.函数的声明
1.告诉编译器有一个函数叫啥,参数是啥,返回值类型是啥,但是具体是不是存在,无关紧要。
2.函数的声明一般出现在函数的使用之前,要满足先声明后使用。
3.函数的声明一般要放在头文件中的。
int main()
{
int Add(int,int); //声明一下函数存在
int c = Add(a,b);
}
int Add(int x,int y);//这里函数出现再主函数后面,与编译器扫描规律不合,需要声明
{ ;
}
(6)常用函数↑↑↑
字符串函数
strlen strcpy strcat strcmp strstr strtok strerror
内存函数
memcpy memmove memcmp memset
动态内存操作函数
malloc calloc free
1.字符串函数
返回类型:无符号的整形
不包含字符串最后的“\0”!
返回类型:目的地起始地址
拷贝时会将“\0”也拷贝过去并结束。
目标空间要足够大且必须可修改!
strncpy(目的地地址,源数据地址,正整数n) {拷贝n个字符过去}
如果n>源数据字符长度,会在末尾补\0。
int main()
{
char arr1[] = "abcde"; char arr2[] = "klf";
strcpy(arr1,arr2);//将arr2里的字符串传递到arr1里。
}
返回类型:目的地起始地址
目的地必须足够大。
会将“\0”也追加过去并结束。
strncat(目的地地址,源数据地址,正整数n) {追加n个字符串过去}
追加n个字符后会在末尾补一个\0。
返回类型:1>2返回正数;1<2返回负数;1=2返回零.
strncmp(字符串指针1,字符串指针2,正整数n) {只比较1和2的前n个字符}
int main()
{
char*p1 = "qbc"; char*p2 = "qac";
strcmp(p1,p2);//返回1.
return 0;
}
返回类型:返回1中字符串2相同的那一串数据的首地址,或空指针NULL。
int main()
{
char*p1 = "abcdef"; char*p2 = "def"; char*p3 = "defQ";
strstr(p1,p2);//返回p1中d的地址
strstr(p1,p3);//返回NULL
}
返回类型:指针
会修改原来的字符串,因此一般用来切分临时拷贝的内容。
第一次调用会返回a的地址并把@替换为\0
第二次调用会从原来@的位置开始继续往下找,返回f的地址(strtok会自己记地址!)
找不到时返回NULL
int main()
{
char arr[] = "ab@fx.sw"; char aee[] = "@.";
printf("%s",strtok(arr,aee));//ab
printf("%s",strtok(NULL,aee));//fx
printf("%s",strtok(NULL,aee));//sw
}
返回类型:指针
errno会自动识别程序中的错误原因并把相对应的错误码(如:0,1,2······)发送给strerrorr,由strerrorr将其转换为英语语言的错误信息
#include<errno>
int main()
{
FILE*pf = fope("text.c","r");
if(pf==NULL)
printf("%s\n",strerror(errno));
}
2.内存函数
返回类型:目的地指针
返回类型:目的地指针
用来处理目的地和源指针空间重叠的拷贝。
int main()
{
int arr[] = {1,2,3,4,5,6,7};
memmove(arr+3,arr,3)
}
返回类型:1>2返回正数;1<2返回负数;1=2返回零.
在某个指针所指向的空间设置n个字符。
3.动态内存操作函数
《stdlib.h》
返回类型:void*类型的指针,指向开辟出来的空间。失败返回NULL
返回类型:void*类型的指针,指向开辟出来的空间。失败返回NULL