写在前面
本文作者将从什么是C语言入手让大家更了解它,然后手把手教学编写第一个程序。
作者还把C语言主要有的的知识面结合自己的理解整理记录成此文章,简单介绍C语言大概的知识面和要点,意在使读者尤其是初学者能大概了解C语言更快更好的学好它。
目录
1.什么是C语言
1.1计算机与机器语言
1.2汇编语言
1.3高级语言
2.编程环境的构建
2.1C语言编译器
2.2Visual Studio 安装
3.第一个c语言程序
3.1写前必备
3.2打印Hello world!
3.3代码初解
4. 数据类型
5. 变量和常量
5.1变量
5.2 常量
6. 字符串+转义字符+注释
6.1 字符串
6.2 转义字符
6. 3注释
7. 选择语句
8.循环语句
9.函数
10. 数组
11.操作符
12.常用关键词
13. #define 定义常量和宏
14. 指针
15. 结构体
科学家们为了简化机器,利用数学语言0和1来表示计算机能够识别的通电和断电两种状态。所以计算机能识别的所有指令以及存储和操作的数据都是由0和1组成的。计算机里都采用二进制。
“二进制”,就是一种仅用“1”和“0”的排列组合来表示具体数值的,一种记数方法。
虽然简化了很多,但这时候机器就只能听得懂0和1,给机器下达一条简单的指令需要很长的一串01数字。写程序下指令还是很复杂,编程只有科学家会,写的过程也很痛苦,还需要不断地查表,出现了问题也很难检查。
这些可以由计算机直接识别的二进制代码就叫做机器语言,无需编译即可下达指令给计算机。
类似说,英语也是一门语言,用于人和人之间交流合作。说出英语后,懂英语的人会根据你说的指令去干活。而机器语言就是电脑机器等可以听懂或者看懂的言语。人输入机器语言机器听懂以后会做出你指定的相关动作,例如打开软件,计算数字之和。
为了进一步地简便化,科学家们发明了助记符。
举一个例子,假设0101 0110 表示需要机器去做加法,这时候科学家们用add标记这一串数字,以后下达命令写代码的人只需要写这些标记符就可以了,会有专门的编译器把助记符翻译成复杂的机器语言传达给机器。
由这些助记符构成的语言就叫汇编语言。
后来科学家依次发明了b语言和 c语言 c++ java Python等高级语言,编程越来越方便。
对于C语言来说:
C语言是一门通用计算机编程语言,广泛应用于底层开发。作为面向过程的计算机编程语言,与C++,Java等面向对象的编程语言有所不同。它既具有高级语言的特点,又具有汇编语言的特点。 设计目标是提供一种能以简易的方式编译、处理低级存储器的编程语言。
尽管C语言提供了许多低级处理的功能,但仍然保持着跨平台的特性,以一个标准规格写出的C语言程序可在包括类似嵌入式处理器以及超级计算机等作业平台的许多计算机平台上进行编译。
C语言出现后,各个公司都自己改造c语言,导致各个人用的符号都不一样。二十世纪八十年代,为了避免各开发厂商用的C语言语法产生差异,让c语言成为通用语言,由美国国家标准局为C语言制定了一套完整的美国国家标准语法,称为ANSI C,作为C语言最初的标准。
目前2011年12月8日,国际标准化组织(ISO)和国际电工委员会(IEC)发布的C11标准是C语言的第三个官方标准,也是C语言的最新标准,该标准更好的支持了汉字函数名和汉字标识符,一定程度上实现了汉字编程。
C语言编译器主要有Clang、GCC、WIN-TC、SUBLIME、MSVC、Turbo C等。
Gcc是最常用的编译器,但对于初学者来说一般使用集成开发环境(IDE,全称Integrated Development Environment用于提供程序开发环境的应用程序,集成了代码编写功能、分析功能、编译功能、调试功能等一体化的开发软件服务套)如:Visual Studio ,一般不建议使用Devc++。
首先在在浏览器搜索VisualStudio,然后按照图片步骤操作。
根据电脑的系统去选择。
来到这个界面等待下载。
打开文件
安装完了可以设置自己喜欢的字节,颜色等,这需要创建项目进入以后才能操作,在后面第一个c程序创建项目了后面会讲哦。
学的C语言就改成xx.c,xx.cpp是c++语言。
#include
int main()
{
printf("Hello world!");
return 0;
}
第一种方式按ctrl+F5
第二种:
一个项目中可以写多个.c的源文件但是main函数有且只能有一个
main函数基本写法:
int main()
{
…//写自己的代码
return 0;
}
#include
#为预处理的意思 因为使用了printf。stdio.h这个文件相当于有这个助记符的能翻译printf的字典,要提前告知机器翻译时要用到这个字典来翻译。
printf实现功能在屏幕打印对应内容。
#include
int main()
{
printf("%d ",sizeof(char)); //1
printf("%d ",sizeof(short)); //2
printf("%d ",sizeof(int)); //4
printf("%d ",sizeof(long)); //4
printf("%d ",sizeof(long)); //8
printf("%d ",sizeof(float)); //4
printf("%d ",sizeof(double)); //8 单位都是字节 byte
return 0;
}
eg:int num=0;printf(" %d ",num);char arr[7]="abcdef";//这是字符串,第四章会讲到printf(" %s ",arr);
其本质是向内存申请一块空间,放入值,出了一定的区域会被系统删除,就像记忆一样。
#include int global = 2019; //全局变量int main(){int local = 2018; //局部变量return 0;}
#include int global = 2019;int main(){int global = 2020;printf("global = %d\n", global);return 0;}//运行结果:2022
一般如果在某块代码处需要给全局变量赋一个新值时可以进行变量的覆盖。
变量的作用域和生命周期
123,3.1415
const int num=10;num=20;//会报错,因为const修饰 num的值不能改变了//注:但是它本质还是一个变量,如果有语法规定只能用常量的地方不能放 num,编 译器默认它不符合语法。const int num=10;int arr[num];//报错,因为语法规定,数组定义[]内一定要用常量。(数组后面会介绍,记住就可以)
#define PI 3.1415926 //PI贯穿整个项目都会用到
enum Sex{MALE,FEMALE,SECRET};//枚举常量演示,固定写法printf("%d\n", MALE); //结果为0因为系统默认会给它们依次赋值0,1,2,3……,括号中的MALE,FEMALE,SECRET就是枚举常量 是常量就不能改,
#includeint main() {char arr1[] = "bit";char arr2[] = {'b', 'i', 't'};char arr3[] = {'b', 'i', 't', '\0'};printf("%s\n", arr1);printf("%s\n", arr2);printf("%s\n", arr3);return 0;}
#include #include int main(){printf("abc\0"def");return 0;}
这里的'\t'构成转义字符,等价于Tab键。
为了展现出换行和空四格Tab键等含义,C语言里用转义字符来代表类似的含义。
\a 警告字符,蜂鸣\b 退格符\f 进纸符\n 换行\r 回车\t 水平制表符\v 垂直制表符\ddd ddd表示1~3个八进制的数字。 如: \130 对应字符X
\xdd dd表示2个十六进制数字。 如: \x30 对应字符0
int main(){printf("%c\n",'\130');return 0;}//结果:X 因为130八进制 转为十进制为88,根据 ASCII码表得知对应的为X
#include #include int main(){printf("abc\\tf");return 0;}//想打出\t,避免编译器认成换行符再前面加上\。
\? 在书写连续多个问号时使用,防止他们被解析成三字母词\' 用于表示字符常量'\“ 用于表示一个字符串内部的双引号\\ 用于表示一个反斜杠,防止它被解释为一个转义序列符。
#include int main(){//问题1:在屏幕上打印一个单引号',怎么做?//问题2:在屏幕上打印一个字符串,字符串的内容是一个双引号“,怎么做?printf("%c\n", "\'");printf("%s\n", "\"");return 0;}
#include int main(){printf("%d\n", strlen("abcdef"));printf("%d\n", strlen("c:\test\628\test.c"));return 0;}
/*调用add方法*/
//调用Add函数,完成加法
选择语句有两种实现,一种是if else,一种是switch
#include int main(){int coding = 0;printf("你要保存文件吗?(选择1 or 0)");scanf("%d", &coding);if(coding == 1){prinf("文件保存成功\n");}else{printf("成功退出\n");}return 0;}
#include int main(){int age = 0;
scanf("%d", &age);
if (age < 18)
printf("少年\n");
else if (age >= 18 && age <= 30)
printf("青年\n");
else if (age >= 31 && age <= 45)
printf("中年\n");
else if (age >= 46 && age <= 60)
printf("壮年\n");
else if (age >= 61 && age < 90)
printf("老年\n");
else
printf("老寿星\n");
return 0;
}
switch:
#include
int main() { int day = 0; scanf("%d", &day); int n = 1;
switch (day)//整型表达式
{
case 1: //case 后必须是整型常量表达式
printf("星期1\n");
break;
case 2:
printf("星期2\n");
break;
case 3:
printf("星期3\n");
break;
case 4:
printf("星期4\n");
break;
case 5:
printf("星期5\n");
break;
case 6:
printf("星期6\n");
break;
case 7:
printf("星期天\n");
break;
default:
printf("输入错入");
break;
}
return 0;
}
C语言的循环语句有三种,for ,while,do while
语法结构while(要循环满足的条件){//循环要做的事}int i=0;while(i<10){printf("%d ",i);i++;}//运行结果:0 1 2 3 4 5 6 7 8 9
语法结构for(初始值; 要满足的条件; 改变控制条件真假的变量){//循环要做的事}int i=0;for(i=0;i<10;i++){printf("%d",i);}//运行结果:0 1 2 3 4 5 6 7 8 9
do while:
语法结构do {初始值//循环要做的事改变控制条件真假的变量}while(要满足的条件)int i=0;do{printf("%d",i);i++;}while(i<10)//运行结果:0 1 2 3 4 5 6 7 8 9
应用:求和函数
#include int Add(int x,int y){return x+y;}int main(){int a = 0;int b = 0;scanf("%d %d", &a, &b); //scanf也是库函数 功能将输入的值付给对应的变量//使用格式: scanf("格式控制符", &变量名);int sum = Add(a,b);printf("%d\n", sum);return 0;}
补充:scanf 一个库函数
函数作用
数组定义
不初始化定义:
int arr1[10]; char arr2[3]; double arr3[5];
int arr[7] = {1,2,3,4,5,6,7};//定义并初始化一个整形数组10个元素分别为 12 3 4 5 6 7int arr[10] = {1,2,3,4};//定义并初始化,前四个被初始化,后面未被初始化为0
int arr[]={1,2,3,};//定义整形数组3个元素分别为 12 3 ,系统根据后面个数创建对应大小数组
//arr[3]就是拿到了该数组的下标为3的元素。int arr[8] = {1,2,3,4,5,6,7,8,};arr[3]=100;//4变成了100
#include int main(){int i = 0;int arr[10] = {1,2,3,4,5,6,7,8,9,10};for(i=0; i<10; i++){scanf("%d ",& arr[i]);}for(i=0; i<10; i++){printf("%d ", arr[i]);}printf("\n");return 0;}
+ - * / %
//7,2两边都是整型,结果为整型 7/2 =3余下1 结果为3
%取余:
printf("%d",7%2);//结果为1,因为7除2余1
>> 右移 << 左移
& 按位与^ 按位异或| 按位或~按位取反
=+= -= *= /= &= ^= |= >>= <<= 复合赋值符
! 逻辑反操作- 负值 //+ - 与数学中的正号 负号一样+ 正值& 取地址sizeof 操作数的类型长度(以字节为单位)-- 前置、后置--++ 前置、后置++* 间接访问操作符(解引用操作符)(类型) 强制类型转换
int a=3;printf("%d",!a) //a 非0真 !a为假 输出结果0int a=0;printf("%d",!a) //a 0假 !a为真 输出结果1
&和*涉及指针,在后面讲更便于理解
sizeof a sizeof(a) 两种写法 后面放变量()可以省略sizeof(int) 后面放类型()不能省略
sizeof与strlen
sizeof是操作符,不关注内容只关注内容字节大小strlen库函数,关注'\0'的位置
++ :
int a=10;int b=a++;printf("%d %d",a,b);//结果: 11 10 后置++,先进行赋值操作后再使得a+1
int a=10;int b=++a;printf("%d %d",a,b);//结果: 11 11 前置++,先使得a+1后再进行赋值操作
注意:b=(++a)+(++a) +(++a) 类似的题目都是不正确的,不同的编译环境的执行顺序不同结果是不 同的,我们应该避免这种有争议的代码。有的编译器可能先算三个()里面的自增,有的先算一 个()再加再算括号。
int a=3.14//类型不匹配,报错int a=(int)3.14 //把小数强制装换为int 后面的小数不管有没有大于0.5一概舍掉
>>=< <=!= 用于测试“不相等”== 用于测试“相等”,与赋值号不同“=” 注意区分
&& 逻辑与 两个为真才为真|| 逻辑或 两个为假才为假
注:C语言里要表达18>age>10需要使用&&不能直接用数学表达式
exp1 ? exp2 : exp3 三目操作符
int max=0;//第一种
if (a < b)
max = b;
else
max = a;//第二种,更简化
int max=a>b?a:b;
exp1, exp2, exp3, …expN
[](). -> //ps:最后两章会具体讲
int arr[]={1,2,3,4,5,6,7,8,9} int a=arr [ 7 ] ;双目操作符, arr 和 7都是操作数
归纳以后可以分为四类:
char short int long float double struct enum union 类型const unsigned signed extern static typedef void sizeof auto 与类型有关,修饰和操作类型if else while for goto switch case continue break default do 与选择循环等结构有 关register return volatile 其它
#include
void test()
{
int i = 0;
i++;
printf("%d ", i);
}
int main()
{
int i = 0;
for (i = 0; i < 10; i++)
{
test();
}
return 0;
}//222222222//i局部变量,进入函数会创建i赋值1,出了函数被销毁
#include
void test()
{
//static修饰局部变量
static int i = 0;
i++; printf("%d ", i);
}
int main()
{
int i = 0;
for (i = 0; i < 10; i++)
{
test();
}
return 0;
}
//2 3 4 5 6 7 8 9 10 11
全局变量具有外部链接属性的,可以被其他源文件访问,各个源文件可以链接到一起完成程序。一个全局变量被static修饰,使得这个全局变量失去了外部链接属性变成内部链接属性。只能在本源文件内使用,不能在其他源文件内使用。
一个函数被static修饰,使得这个函数只能在本源文件内使用,不能在其他源文件内使用。
typedef unsigned int unit;unit a=10;//unsigned int过于长给他一个别名,以后定义这样的类型就可以使用重新定义的 // 名字。以后学习链表等也会经常用来定义。
void add(int a,int b){printf("%d",a+b);}
#define MAX 1000
宏:和函数很像,都有参数,都可以实现一定功能#define ADD(x, y) ((x)+(y))int Add(int x, int y){return x + y;}int main()
{
int i = 0;int j = 0;
scanf("%d %d",&i,&j);int sum1=Add(i,j);int sum2=ADD(i,j);
return 0;
}
00000000 00000000 00000000 00001001 为了方便表示地址一般转换成16进制来表示:0x 00 00 00 09 //0x用来表示十六进制
取出变量地址:#include
int main()
{
int num = 10;
printf("%p\n", &num); //打印地址,%p是以地址的形式打印 默认16进制
//取出num的地址,&取地址符
//注:这里num的4个字节,每个字节都有地址,取出的是第一个字节的地址(较小的地
址)return 0;
}
double num=3.14;double* pa=# char c='a';char* pa=&c;
#include int main(){int num = 10;int *p = #*p = 20;//*p就是找到了该地址存的变量num. *p==numreturn 0;}
#include
int main()
{
printf("%d\n", sizeof(char*));
printf("%d\n", sizeof(short*));
printf("%d\n", sizeof(int*));
printf("%d\n", sizeof(double*));% zu 专门打印sizeof大小
return 0;
}
struct Stu
{
char name[20];//名字
int age; //年龄
char sex[5]; //性别char id[15]; //学号
};//自定义的类型,struct Stu就类比int double,两个单词一起等价一个类型struct Stu s={"zhangsan",18,"boy","2106060103"}; //初始化 类比int num=19;
.为结构成员访问操作符,相当单独拿到对应的int ,char[]类型等printf("name = %s age = %d sex = %s id = %s\n", s.name, s.age, s.sex, s.id);
struct Stu *ps = &s;printf("name = %s age = %d sex = %s id = %s\n", (*ps).name, (*ps).age, (*ps).sex,(*ps).id);//过于麻烦,C语言给出了新操作符->代替printf("name = %s age = %d sex = %s id = %s\n", ps->name, ps->age, ps->sex, ps->id);
scanf("%d %s %s %s",&s.age,s.name,s.sex,s.id); //数组名就代表地址,不用取地址符号。