C语言是一门通用计算机编程语言,广泛应用于底层开发。C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。
尽管C语言提供了许多低级处理的功能,但仍然保持着良好跨平台的特性,以一个标准规格写出的C语言程序可在许多电脑平台上进行编译,甚至包含一些嵌入式处理器(单片机或称MCU)以及超级电脑等作业平台。
二十世纪八十年代,为了避免各开发厂商用的C语言语法产生差异,由美国国家标准局为C语言制定了一套完整的美国国家标准语法,称为ANSI C,作为C语言最初的标准。 [1] 目前2011年12月8日,国际标准化组织(ISO)和国际电工委员会(IEC)发布的C11标准是C语言的第三个官方标准,也是C语言的最新标准,该标准更好的支持了汉字函数名和汉字标识符,一定程度上实现了汉字编程。
C语言是一门面向过程的计算机编程语言,与C++,Java等面向对象的编程语言有所不同。
其编译器主要有Clang、GCC、WIN-TC、SUBLIME、MSVC、Turbo C等。
注
创建项目
创建源文件
编写代码
注:
main函数总结:
main函数是程序的入口,一个工程中main函数有且仅有一个
当出现程序函数"int main()"已有主体这样的错误时,说明一个工程中出现了多个main函数
一个工程中可以有多个.c文件,但是多个.c文件中只能有一个main函数
编译代码以及运行
注意:以上是在VS2019下运行的,如果在VS2013中运行需要注意当运行时会发现程序执行的太快看不到结果,这时需要设置VS2013中的属性(VS2019不需要设置项目属性)
设置项目属性:右击项目->点击属性
注意:VS2013和VS2019的使用大同小异
出现这么多种的类型,是因为计算机语言在编写程序时需要解决生活中问题,计算机语言必须有能力来描述生活中问题(eg:年龄、体重、收入……)以及类型丰富选择性更多空间利用率更高。
每种类型的大小
int main()
{printf("%d\n", sizeof(char)); //1printf("%d\n", sizeof(short)); //2printf("%d\n", sizeof(int)); //4printf("%d\n", sizeof(long)); //4printf("%d\n", sizeof(long long)); //8printf("%d\n", sizeof(float)); //4printf("%d\n", sizeof(double)); //8printf("%d\n", sizeof(long double)); //8 return 0;
}
注:
%d用于打印整数、%lf用于打印double类型、%f用于打印float类型
sizeof是关键字也是操作符,用来计算类型或者变量所占空间的大小
sizeof的单位是字节byte
二进制由0-1组成、八进制由0-7组成、十进制由0-9组成、十六进制由0-f组成
计算机中最小的单位是bit(比特位),一个比特位是存放一个二进制位的
计算机中的单位由小到大:bit、byte(1byte=8bit)、kb(1kb=1024byte)、mb(1mb=1024kb)、gb(1gb=1024mb)、tb(1tb=1024gb)、pb(1pb=1024gb)、……
long和int类型大小相同,这是因为C语言标准规定sizeof(long)>=sizeof(int)即可(在VS中采用的是大小相等)
注意:存在这么多的类型,其实是为了更加丰富的表达生活中的各种值。
常量描述的是不能改变的量
变量描述的是能被改变的量
定义变量的方法
int age = 150;
float weight = 45.5f;
char ch = 'w';
变量的分类:局部变量、全局变量
局部变量:在大括号内部定义的变量
全局变量:在大括号外部定义的变量
变量的使用
//全局变量 - {}外部定义的
int a = 100;int main()
{//局部变量 - {}内部定义的int a = 10;printf("%d\n", a);return 0;
}
注意:当局部变量和全局变量名字冲突的情况下,局部优先。不建议把全局变量和局部变量的名字写成一样的
注意:
#define _CRT_SECURE_NO_WARNINGS 1
scanf_s函数是VS编译器提供的,不是C语言标准规定的,因此如果使用了在VS中能跑,但在其他平台就不行了(可移植性太差了),综上使用scanf函数
scanf_s函数和scanf函数的使用方法是有区别的
当该文件中添加这句代码时#define _CRT_SECURE_NO_WARNINGS 1,每当创建新源文件时都会有这句代码
VS2019路径:
VS2013路径:
变量的作用域和生命周期
作用域
作用域(scope),程序设计概念,通常来说,一段程序代码中所用到的名字并不总是有效/可用的而限定这个名字的可用性的代码范围就是这个名字的作用域。
注:当在整个工程中一个源文件创建的全局变量(eg:int a=10;)另一个源文件想要使用就需要提前声明该变量(extern int a;)
生命周期
变量的生命周期指的是变量的创建到变量的销毁之间的一个时间段
常量
C语言中的常量分为以下以下几种:
int main()
{//字面常量3.14;10;'a';"abcdef";return 0;
}
int main()
{//const修饰的常变量const int num = 10;//num就是常变量 - 具有常属性(不能被改变的属性)return 0;
}
注意:const修饰的变量是常变量,不是常量,更不能作为数组的元素个数
#define MAX 10000
int main()
{// #define 定义的标识符常量//MAX = 20000;//会报错,不能修改int n = MAX; printf("n = %d\n", n); //10000return 0;
}
//性别
enum Sex
{//这种枚举类型的变量的未来可能取值//枚举常量MALE = 3,//赋初值FEMALE,SECRET
};int main()
{//枚举常量可以一一列举的常量enum Sex s = MALE;//MALE = 3;//不能修改,会报错printf("%d\n", MALE); //3printf("%d\n", FEMALE); //4printf("%d\n", SECRET); //5return 0;
}
字符串
由双引号(Double Quote)引起来的一串字符称为字符串字面值(String Literal),或者简称字符串。
%s打印的是字符串,是以\0为结束标志。而arr2数组没有\0因此后面是随机值直到遇到\0结束
strlen函数是计算字符串的长度(不计入\0),遇到\0结束返回字符串长度
总结:字符串的结束标志是一个 \0 的转义字符。在计算字符串长度的时候 \0 是结束标志,不算作字符串内容。
转义字符
转义字符顾名思义就是转变意思(转变他原来的意思)。
下面看一些转义字符:
补充:
经典笔试题:
//程序输出什么?
#include
int main()
{printf("%d\n", strlen("abcdef"));// \32被解析成一个转义字符printf("%d\n", strlen("c:\test\328\test.c")); //14//c : \t e s t \32 8 \t e s t . creturn 0;
}
注释
例如:
注释有两种风格:
例如:
int main()
{int input = 0;//输入的值printf("好好学习吗(1/0)?>:");scanf("%d", &input);if (input == 1){printf("未来可期\n");}else{ printf("回家种地\n");}return 0;
}
例如:
int main()
{printf("变成小白\n");int line = 0;//循环while(line<30000){printf("写代码:%d\n", line);line++;}if (line == 30000){printf("编程大牛\n");}return 0;
}
#include
int main()
{int num1 = 0;int num2 = 0;int sum = 0;printf("输入两个操作数:>");scanf("%d %d", &a, &b);sum = num1 + num2;printf("sum = %d\n", sum);return 0;
}//上述代码,写成函数如下:
#include
int Add(int x, int y)
{int z = x+y;return z;
}
int main()
{int num1 = 0;int num2 = 0;int sum = 0;printf("输入两个操作数:>");scanf("%d %d", &num1, &num2);sum = Add(num1, num2);printf("sum = %d\n", sum);return 0;
}
注意:
数组是一组相同类型的元素的集合
数组的定义:
int arr[10] = {1,2,3,4,5,6,7,8,9,10};//定义一个整形数组,最多放10个元素
数组的使用:
int main()
{//数组 - 一组相同类型的元素的集合//数组是用下标来访问的,从0下标开始//10个整形1-10存起来int arr[10] = {1,2,3,4,5,6,7,8,9,10};int i = 0;while (i < 10){printf("%d ", arr[i]);i++;}char ch[5] = {'a', 'b', 'c'};//不完全初始化,剩余的默认为0return 0;
}
注:这样写int arr[3];只是创建了数组arr并未初始化数组元素的值
上面这样初始化是错误的
补充:
注意:在C99 标准中引用一个概念—变长数组(支持数组创建的时候,用变量指定大小的,但是这个数组不能初始化),但是VS2019 不支持C99中的变长数组
算术操作符
+ - * / %
/号两端如果都是整数执行整数除法(无论用什么类型存储结果)。/号两端有一端是小数则执行小数除法
移位操作符
>> <<
移位操作符:移动的是二进制位。如果是左移操作符空缺位永远补0
位操作符
& ^ |
赋值操作符
= += -= *= /= &= ^= |= >>= <<=
单目操作符
双目操作符指的是有两个操作数;单目操作符指的是只有一个操作数
C语言规定:0表示假,非0表示真;如果一个数为0那么对这个数进行逻辑反操作那么这个数是1
sizeof的使用:
~的使用:
前置++和后置++的使用:
前置–、后置–和前置++、后置++的使用一样
int main()
{int a = 1;int b = (++a) + (++a) + (++a);//12printf("%d\n", b);return 0;
}
注意:上面的代码是有错误的不建议去研究,因为在不同编译器上运行结果可能是不同的,VS下运行结果是12
强制类型转换的使用:
注意:如果想要避免警告,需要使用强制类型转换。不推荐去使用(因为要使用强制类型转换说明设计有缺陷)
关系操作符
逻辑操作符
逻辑与是所有条件都为真时,结果才为真,否则就为假;逻辑或是只要有一个事件为真,结果就为真,否为为假
条件操作符(三目操作符)
exp1 ? exp2 : exp3
exp1成立,exp2计算,整个表达式的结果是exp2的结果;exp1不成立,exp3计算,整个表达式的结果是exp3的结果。
条件操作符的使用:
逗号表达式
exp1, exp2, exp3, …expN
逗号表达式是逗号隔开的一串表达式
逗号表达式的使用:
int main()
{(2, 4 + 5, 6); //逗号表达式int a = 0;int b = 3;int c = 5;//a=5 c=1 b=3int d = (a = b + 2, c = a - 4, b = c + 2);//逗号表达式,是从左向右依次计算的//整个表达式的结果是最后一个表达式的结果printf("%d\n", d); //3return 0;
}
注:逗号表达式是从左向右依次计算的,整个表达式的结果是最后一个表达式的结果。
下标引用、函数调用和结构成员
[] () . ->
下标引用、函数调用操作符的使用:
注:. -> * &下面会提到
常见关键字需要注意的事项:
auto关键字
auto是自动变量,每个局部变量(自动创建自动销毁的)都是auto修饰的自动变量,基本都省略掉了。
auto的使用:
auto int a=10;
注:auto 新的C语言语法中也有其他用法 ( 暂时不考虑)
extern关键字
extern是用来声明外部符号的
extern关键字的使用:
注:
register关键字(寄存器关键字)
register寄存器关键字作用是用register创建的变量建议把它放到寄存器里,具体将变量放不放进去由编译器说了算,register只是起到建议的作用
register关键字的使用:
register int num = 100;//建议num的值存放在寄存器中
注意:register关键字的应用-——大量频繁被使用的数据想放在寄存器中,目的是提升效率。目前编译器比较智能了,它会自动判断该变量是否需要放入寄存器中
补充:
signed关键字
signed有符号的 ;unsigned 无符号的
typedef关键字
typedef 顾名思义是类型定义,这里应该理解为类型重命名(类型重定义)。
typedef关键字的使用:
typedef unsigned int u_int;
//将unsigned int 重命名为u_int, 所以u_int也是一个类型名
int main()
{unsigned int num = 100;u_int num2 = 100;return 0;
}
static关键字
在C语言中static是用来修饰变量和函数的(static - 静态的)
static关键字的使用:
static修饰局部变量
static修饰局部变量,改变了局部变量的生命周期(本质上是改变了变量的存储类型)
static修饰全局变量
static修饰全局变量,使得这个全局变量只能在自己所在的源文件(.c)内部可以使用,而其他源文件不能使用
static修饰函数
static修饰函数,使得函数只能在自己所在的源文件内部使用,不能在其他源文件内部使用。本质上static是将函数的外部链接属性变成了内部链接属性(和static修饰全局变量一样)
注:
总结;
union关键字
union - 联合体(共用体)
void关键字
void - 无、空
注意:
define 是一个预处理指令
作用一:define定义标识符常量(define定义符号)
#define MAX 1000 //MAX也可称为符号int main()
{printf("%d\n", MAX);return 0;
}
作用二:define定义宏
//define 定义宏
#define ADD(X,Y) ((X)+(Y))int main()
{printf("%d\n", 4*ADD(2, 3));return 0;
}
内存
内存是电脑上特别重要的存储器,计算机中所有程序的运行都是在内存中进行的 。所以为了有效的使用内存,就把内存划分成一个个小的内存单元,每个内存单元的大小是1个字节。为了能够有效的访问到内存的每个单元,就给内存单元进行了编号,这些编号被称为该内存单元的地址。
注:
取出变量地址(&操作符)以及定义指针变量:
指针的使用实例(*操作符):
//指针 就是 地址int main()
{int a = 10;int* pa = &a;*pa = 20;//* 解引用操作 , *pa就是通过pa里边的地址,找到a并对a进行操作printf("%d\n", a);return 0;
}
总结:指针的大小是相同的。因为指针是用来存储地址的,指针需要多大空间取决于地址的存储需要多大空间。在32位机器上其实是32个比特位组成的二进制序列作为地址(存储需4字节);在64位机器上其实是64个比特位组成的二进制序列作为地址(存储需8字节)
注:指针大小在32位平台(x86)是4个字节,64位平台(x64)是8个字节。
结构体使得C语言有能力描述复杂类型。比如描述学生,学生包含: 名字+年龄+成绩 这几项信息。这里只能使用结构体来描述了。
结构体的创建:
//结构体可以让C语言创建新的类型出来//创建一个学生struct Stu
{char name[20];//成员变量int age;double score;
};//创建一个书的类型
struct Book
{char name[20];float price;char id[30];
};
结构体的初始化以及.操作符和->操作符的使用:
//结构体可以让C语言创建新的类型出来//创建一个学生struct Stu
{char name[20];//成员变量int age;double score;
};//创建一个书的类型
struct Book
{char name[20];float price;char id[30];
};int main()
{struct Stu s = { "张三", 20, 85.5 };//结构体的创建和初始化printf("1: %s %d %lf\n", s.name, s.age, s.score);//结构体变量.成员变量名struct Stu* ps = &s;printf("2: %s %d %lf\n", (*ps).name, (*ps).age, (*ps).score);printf("3: %s %d %lf\n", ps->name, ps->age, ps->score); //结构体指针->成员变量名return 0;
}
注:.和->用于访问和修改结构体中成员变量的值