学习一门编程语言是一条艰辛与快乐共存的一条路,如今选择了这条路,就应该一直走下去,了解C语言的基础知识,要先对C语言有一个大概的认识,下面我介绍一下C语言的基础。
一、什么是C语言。
#include
int main()
{
printf("Hello\n");
printf("Just do it!\n");
return 0;
}
打印结果:
有\n(这是换行操作符,下面会介绍)
无\n
2.1 #include
2.2 int main():main函数是程序的入口 ,一个工程中main函数有且仅有一个,是C语言main函数的一种声明方式,在int main()下有一对{},在其中输入代码。
2.3 printf:表示要输出的结果,其结果放入(" ")中的双引号内,如果需要特别打印某一种字符类型,一般格式为(“需要打印的数据类型\n”,需要输出的变量)蓝色部分表示固定的格式。绿色部分表示需要打印相应内容时输入的不同的东西,\n表示换行,可有可无,只是打印出的结果格式不同不影响打印内容,具体需要打印的类型见后边。
2.4 return 0:返回值为0,先不做深入了解,记作固定的格式,打上去就行。
注:每一个语句后面需要打上一个英文输入下的分号 ;
三、数据类型
#include
int main()
{
printf("%d\n", sizeof(char));
printf("%d\n", sizeof(short));
printf("%d\n", sizeof(int));
printf("%d\n", sizeof(long));
printf("%d\n", sizeof(long long));
printf("%d\n", sizeof(float));
printf("%d\n", sizeof(double));
printf("%d\n", sizeof(long double));
return 0;
}
代码中%d打印的是整型,sizeof()用于打印数据类型的大小。
打印结果:
其中数字大小表示各种数据类型的空间大小,单位为字节(byte)1GB=1024MB 1MB=1024KB 1KB=1024byte 1字节=8位 其中位:是二进制数据中的一个位(bit)简写为b,音译为比特,是计算机存储数据的最小单位。
四、常量与变量
int age = 150;
float weight = 45.5f;
char ch = 'w';
选择需要定义变量的类型(int、char、float等),给变量相应的变量名字(自己灵活定义即可,最好方便自己记忆,比如需要对年龄赋值时,变量名用age),用 = 进行赋值,将值放在等号后面,并习惯性的打上分号。
4.2 变量的分类
全局变量:定义在int main()以外,对整个代码有效
局部变量:定义在某一个范围内用{ }括起来的区域,当出了该范围则无效,如果全局变量和局部变量一起存在,则局部变量优先。
#include
int b = 2020; //全局变量
int main()
{
int b = 2021; //局部变量
int c = 2022; //局部变量
printf("b = %d\n", b);
return 0;
}
打印结果:
4.3 变量的使用
我们以计算两个数字的和为例
#include
int main()
{
int num1 = 0;
int num2 = 0;
int sum = 0;
printf("输入两个操作数:>");
scanf("%d %d", &num1, &num2);
sum = num1 + num2;
printf("sum = %d\n", sum);
return 0;
}
代码中先定义需要输入的两个数字整型int num1=0;int num 2=0;其中赋一个初始值0,在定义一个变量来存放需要输出的值int sum=0;均放上初始值0;先输出一个提示语输入两个操作数:>用scanf(“%d %d”,&num1,&num2)来寻找变量num1和num2的地址,达到对变量随时赋值的目的,sum=num1+num2定义算法,即求两个数的和,并将结果用变量sum来承接,最后用printf来输出sum的值。
4.5 常量
C语言中的常量和变量的定义的形式有所差异
1.字面常量:即已知的值
2.const 修饰的常变量:对所赋值的变量有固定作用,后续不能改变
#include
int main()
{
const int num = 4;
printf("%d\n", num);
int num = 8;//此处对num再赋值已经无效了
printf("%d\n", num);
return 0;
}
其中const修饰的常变量,对赋值的sum有固定作用,后面再对num赋值则无效,虽然对num固定赋值了,但num的本质任然是变量,只是具有了常量的性质,验证如下:
#include
int main()
{
const int n = 10;
int arr[n] = { 0 };//数组[]中需要的是一个常量,虽然const修饰的n有常属性,但是他的本质是一个变量所以有错误
return 0;
}
所以没有输出结果:
3.#define 定义的标识符常量 :定义的标识符不占内存,只是一个临时的符号,预编译后这个符号就不存在了。例如:对MAX的赋值,在main函数外定义。
#include
#define MAX 10
int main()
{
int arr[MAX]={0};
printf(" %d\n", MAX);
return 0;
}
4.枚举常量:需要一一列举出来,需要用到枚举关键字enum,放在枚举里边的叫枚举常量
#include
enum people
{
KID,
MAN,
WOMAN,
}; //其中KID,MAN,WOMAN,叫做枚举常量
int main()
{
printf("%d\n", KID);
printf("%d\n", MAN);
printf("%d\n", WOMAN);
return 0;
}
五、字符串+转义字符+注释
#include
int main()
{
printf("Hello\n");
printf("Just do it!\n");
return 0;
}
转义字符 | 释义 |
\0 | 结束标志 |
\? |
在书写连续多个问号时使用,防止他们被解析成三字母词
|
\' |
用于表示字符常量 '
|
\" |
用于表示一个字符串内部的双引号
|
\\ |
用于表示一个反斜杠,防止它被解释为一个转义序列符。
|
\a |
警告字符,蜂鸣
|
\b |
退格符
|
\f |
进纸符
|
\n |
换行
|
\r |
回车
|
\t |
水平制表符
|
\v |
垂直制表符
|
\ddd |
ddd 表示 1~3 个八进制的数字。 如: \130
|
\xdd |
dd 表示 2 个十六进制数字。 如: \x30
|
1.先给大家介绍一下结束标志\0
#include
int 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;
}
打印结果:
字符串放在数组里面时,末尾会默认输入一个 \0,也就是说在数组char arr1 [ ]={"bit"}中,其实放入的内容有‘b’,‘i’,‘t’,‘\0’,所以打印完bit后就结束了,然而在数组char arr2 [ ]={‘b’,‘i’,‘t’}这种单独的字符时,末尾是不会默认输入\0 的,所以在打印完bit以后并没有结束打印,而是打印了一些随机值。故出现一些“烫烫烫烫烫烫烫烫烫烫烫烫烫烫蘠it”,如果手动在末尾输入 \0 时,就手动给了一个结束标志,如数组char arr3 [ ]={‘b’,‘i’,‘t’,‘\0’},打印完bit遇到了\0,那么就结束打印。
2.转义字符 \? :在书写连续多个问号时使用,防止他们被解析成三字母词,三字母词存在于老一版的编译器中。
#include
int main()
{
printf("(are you ok\?\?)\n");// \?在书写连续多个问号时使用,防止他们被解析成三字母词
return 0;
}
打印结果:
3.转义字符 \' 与 \" :只是单纯的为了输出单引号和双引号
#include
int main()
{
printf("\'");
printf("\"");
return 0;
}
#include
int main()
{
printf("c:\\test\41\test.c");
return 0;
}
输出结果:
其中\t叫作水平制表符相当于以一个tab健的一个空格位置,为防止\t被识别成转义字符,规定\\为反斜杠,防止他被解释为一个转义字符,与双重否定是肯定的意思差不多,八进制数\41转化为十进制是33,对应的ASCII码字符为!,其它字符没有转义字符,就直接打印出来
7.转义字符\a:警告字符,蜂鸣
#include
int main()
{
printf("\a");
return 0;
}
打印的时候会响一声“叮咚”
8.转义字符\b:退格符
#include
int main()
{
printf("abcdef\b\b\b\b");
return 0;
}
打印结果:
\b表示向后退格,退到相应位置时,相应的字符将无法打印,在退格的时候有叠加效果,如上代码中一共输入4个\b,相应向后退4格,在输入的abcdef中倒数第四位c将无法打印
9.转义字符\f:换页,将当前位置移到下一页的开头,在使用打印机时会直接换页,在编译器中表现不明显
10.转义字符\v:垂直制表符,也用于打印时
11.转义字符\r:回车,将当前位置移到本行的开头,并覆盖打印
#include
int main()
{
printf("abcdef\r");
return 0;
}
打印结果:
5.3 注释:1. 代码中有不需要的代码可以直接删除,也可以注释掉
以使用函数计算两个数的和为例:
#define _CRT_SECURE_NO_WARNINGS
#include
int Add(int x, int y)
{
return x + y;
}
/*C语言风格注释
int Sub(int x, int y)
{
return x-y;
}
*/
int main()
{
int a = 0;
int b = 0; //C++注释风格
scanf("%d%d", &a, &b); //用scanf取a,b的地址,能够随机赋值计算
printf("sum=%d\n", Add(a, b)); //调用Add函数,完成加法
return 0;
}
打印结果:
六、 选择语句:用if语句、switch case语句实现
#define _CRT_SECURE_NO_WARNINGS
#include
int main()
{
int num = 0;
printf("学习编程\n");
printf("你能够坚持吗?(0不能/1能)");//>:为提示符
scanf("%d", &num);
if (1==num)
printf("好工作,高薪资");
else
printf("平淡的生活");
return 0;
}
七、循环语句:用while语句、for语句、do ... while语句实现
有些事必须一直做,比如学习,应该日复一日
例如用while实现连续输入1-100的数字:
#include
int main() //代码功能:输出1-100的数字
{
int a = 1;
//int b = 0;
while (a < 101)
{
printf(" %d", a );
a += 1;
}
return 0;
}
打印结果:
八、函数:是简化代码,代码复用。
8.1 库函数:当我们描述的基础功能,它们不是业务性的代码。我们在开发的过程中每个程序员都可能用的到,为了支持可移植性和提高程序的效率,所以C语言的基础库中提供了一系列类似的库函数,方便程序员进行软件开发。如:
8.2 自定义函数:如果库函数能干所有的事情,那就不需要程序员了, 所有更加重要的是自定义函数,自定义函数和库函数一样,有函数名,返回值类型和函数参数。 但是不一样的是这些都是我们自己来设计。这给程序员一个很大的发挥空间。
例如计算两个数的和:
#include
int main()
{
int num1 = 0;
int num2 = 0;
int sum = 0;
printf("输入两个操作数:>");
scanf("%d %d", &num1, &num2);
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 Add(int x, int y),就不需要重复的去敲代码,需要求两个数的和时直接调用函数就行了。
九、数组
9.1 定义:一组相同类型元素的集合
例:要存储1-10的数字,怎么存储?
int arr[10] = {1,2,3,4,5,6,7,8,9,10};//定义一个整形数组,最多放10个元素
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
//如果数组10个元素,下标的范围是0-9
数组中各值对应的下标:
打印数组里面的数值:
#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++)
{
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
打印结果:
十、操作符:算术操作符、移位操作符、位操作符、赋值操作符
10.1 算术操作符:+ - *(乘号) /(除号) %(取余)
1. 除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数。
2. 对于 / 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法。
3. % 操作符的两个操作数必须为整数。返回的是整除之后的余数。
#define _CRT_SECURE_NO_WARNINGS
#include
int main()
{
int a = 0;
int b = 1; //对b赋的初始值不能为0,因为在后面要作为除数
int c = (-8 + 22) * a - 10 + b / 2;
int d = a % b;
scanf("%d%d", &a, &b);
printf("计算结果=%d\n", c);
printf("取余=%d\n", d);
return 0;
}
打印结果:
10.2 移位操作符: <<左移操作符 >>右移操作符
1.移位操作符的操作数只能是整数
2.针对的是十进制转化为二进制后,对二进制的数值进行移位,
3.左移操作符,左边舍去右边补零
4.对于移位运算符,不要移动负数位,这个是标准未定义的
int main()
{
int a = 1;//int型有4个字节32个比特位转化为二进制00000000000000000000000000000001 转化为十进制就为1
int b=a << 2; //00000000000000000000000000000100 转化为十进制就为4
int b=a<<-1;//错误的移位
printf("%d", b);
return 0;
}
打印结果:
移位操作符是针对二进制数进行移位,例如上述代码中int类型4个字节=4x8=32位,将对应的整数先转化为32位的二进制数,在对二进制数进行移位,移位遵循——左移操作符时,左边舍去右边补零;右移操作符时,右边舍去左边补零。最后再将移位后的二进制数转化为十进制数打印出来。
10.3 位操作符: &按位与 |按位或 ^按位异或(均是对二进制进行)
#include
int main()
{
int a = 1; //0001
int b = 2; //0010
printf("%d\n", a & b); //0000
printf("%d\n", a | b); //0011
printf("%d\n", a ^ b); //0011 相同为0不同为1
return 0;
}
打印结果:
10.4 赋值操作符:= += -= *= /= &= ^= |= >>= <<=
操作符 | 作用 |
! |
逻辑反操作
|
- | 负值 |
+ | 正值 |
& | 取地址 |
sizeof | 操作数类型长度(以字节为单位) |
~ | 对一个数的二进制按位取反 |
-- | 前置、后置-- |
++ | 前置、后置++ |
* | 间接访问操作费(解引用操作法) |
(类型) | 强制类型转换 |
前五个操作符在前面已经介绍了,我向大家介绍后面五种就行
1.对一个数的二进制按位取反~:~是一元运算符,用来对一个二进制数按位取反,即将0变1,将1变0,例:十六进制9对应:0x00000009 当取反时~9对应:0xfffffff6
#include
main()
{
int a = 0;
printf("%x", ~a);
}
打印结果:
2.前置、后置++:前置++作用是先进行运算再赋值,而后置++为先先复制后运算
前置++:
#include
main()
{
int i = 2;
int a=++i;
int b = i;
printf("a=%d\n", a);
printf("b=%d\n", b);
}
打印结果:
代码中我们先给 i 一个初始值2,用b来反应 i 最终的值。前置++是先对2进行+1运算,然后将加上1后的值3赋给变量a,故a的值为3,经过运算和赋值后 i 的值变为3,故将i变化后的值3赋给b,故b的值为3
后置++:
#include
main()
{
int i = 2;
int a = i++;
int b = i;
printf("a=%d\n", a);
printf("b=%d\n", b);
}
打印结果:
代码中我们先给 i 一个初始值2,用b来反映 i 最终的值。后置++是先 i 的值2先赋给a,然后对 i 加1,则a的值为2,经过赋值和运算后 i 的值变为3,故将 i 变化后的值3赋给b,故b的值为3。
3.前置、后置--:
前置--:
#include
main()
{
int i = 2;
int a = --i;
int b = i;
printf("a=%d\n", a);
printf("b=%d\n", b);
}
打印结果:
代码中我们先给 i 一个初始值2,用b来反映 i 最终的值。前置--是先对2进行-1运算,然后将减去1后的值1赋给变量a,故a的值为1,经过运算和赋值后 i 的值变为1,故将 i 变化后的值1赋给b,故b的值为1
后置--:
#include
main()
{
int i = 2;
int a = i--;
int b = i;
printf("a=%d\n", a);
printf("b=%d\n", b);
}
打印结果:
代码中我们先给 i 一个初始值2,用b来反映 i 最终的值。后置--是先 i 的值2先赋给a,然后对 i 减1,则a的值为2,经过赋值和运算后 i 的值变为1,故将 i 变化后的值1赋给b,故b的值为1。
4.间接访问操作费(解引用操作法) *:该操作符常用于指针
#include
int main()
{
int a = 10;
int* p= &a;
*p =20;
printf("%d\n", a);
return 0;
}
想要了解此代码需要先了解指针的概念,可先往下翻,初步了解指针。代码中*p=20;其中的*就是解引用操作符,意思是通过p中存放的地址,找到p所指向的对象,而*p就是p所指向的对象,其代表的就是变量a。
5.强制类型转换(类型):
#include
int main()
{
double a = 3.14;
printf("%d\n", (int)a);
return 0;
}
打印结果:
原本定义的变量是double型,在(类型)的强制转换下,将变量a转换为int类型,使用该操作符时,将需呀转化的类型放入括号内,将需要转化的变量紧放其后切只对一个变量有效,如果在()后有两个变量,则只对紧跟的第一个变量有效该转换只能在该语句生效,并且在其他地方,变量a仍然是double类型。
> | 大于 |
>= | 大于等于 |
< | 小于 |
<= | 小于等于 |
!= | 用来测试“不相等” |
== | 用来测试“相等” |
&& | 逻辑与 |
|| | 逻辑或 |
十一、常见关键字:C语言提供了丰富的关键字,这些关键字都是语言本身预先设定好的,用户自己是不能创造关键字的。
#include(stdio.h)
#define c 100
int main()
{
printf("%d\n", c);
int d = 100;
printf("%d", d);
return 0;
}
打印结果:
12.2 #define 定义宏:
#include
#define add(x,y)(x)+(y) //宏名 参数 宏体
int main()
{
int a = 10;
int b = 20;
int c = add(a, b); //替换成int c=((a)+(b))
printf("%d", c);
return 0;
}
打印结果:
十三、 指针
13.1 想了解指针需要先了解一下内存:内存是电脑上特别重要的存储器,计算机中程序的运行都是在内存中进行的 。 所以为了有效的使用内存,就把内存划分成一个个小的内存单元,每个内存单元的大小是1个字节。 为了能够有效的访问到内存的每个单元,就给内存单元进行了编号,这些编号被称为该内存单元的地址。
内存单元有相对应的编号,这一个编号就是地址,这个地址也叫做指针,也就是说地址就是指针,用来储存地址的变量叫指针变量。
如何取出变量的地址呢?就要用到前面介绍的取地址符&
#include
int main()
{
int num = 10;
#//取出num的地址。注:这里num的4个字节,每个字节都有地址,取出的是第一个字节的地址(较小的地址)
printf("%p\n", &num);//打印地址,%p是以地址的形式打印
return 0;
}
&num的作用就是取出创建的变量num的地址
内存 | |
一个字节 | 0xFFFFFFFF |
一个字节 | 0xFFFFFFFE |
一个字节 | 0xFFFFFFFD |
0x0012FF47 | |
0x0012FF46 | |
0x0012FF45 | |
0x0012FF44 | |
一个字节 | 0x00000002 |
一个字节 | 0x00000001 |
一个字节 | 0x00000000 |
变量num的类型是int类型,其大小为4个字节,红色的部分为num的地址,打印的地址就是读取到num的第一个地址。
变量取出来后如果需要储存,就需要定义指针变量:
int num = 10;
int* p=&num; //int说明指针变量p所指的变量num是一个整形
指针的具体使用:
#include
int main()
{
int a = 10;
int* p= &a;
*p =20;
printf("%d\n", a);
return 0;
}
打印结果:
#include
int main()
{
printf("%d\n", sizeof(char *));
printf("%d\n", sizeof(short *));
printf("%d\n", sizeof(int *));
printf("%d\n", sizeof(double *));
return 0;
}
打印结果:
结论:指针大小在32位平台是4个字节,64位平台是8个字节。
#include
struct xs //定义结构体类型要用struct,这个类型名叫xs(自己定义)
{
char name[20]; //叫做结构体成员,其中要放的是字符串,需要将字符串放到字符串数组里面
int age ;
char sex[10];
char id[15];
};
void project(struct xs* dy) //自定义函数project,将s的地址赋给dy,*dy表示的是s
{
printf("%s %d %s %s\n", (*dy).name, (*dy).age, (*dy).sex, (*dy).id);
printf("%s %d %s %s\n", dy->name, dy->age, dy->sex, dy->id);
}
int main()
{
struct xs s = { "张三", 21 ," 男 ","20209999" };//s为创建的结构体变量,访问其对象时,需要加.这个操作符
printf("%s %d %s %s\n", s.name, s.age, s.sex, s.id);
project(&s); //自定义函数,取s的地址给自定义的函数
return 0;
}
打印结果:
上面展示了结构体的三种打印方式,其中放在project()函数里面的是利用指针打印,外面的那一种是直接打印不用创建指针。在函数内的打印方式和外面的那一种差别不大。
函数外:打印时填入需要打印的类型,最后在后面写上 结构体变量(s).字符串的变量名(name、age、sex、id) 这种格式打印
函数内:将结构体变量名用指针来代替,只是改变的形式,但没改变本质,最后将操作符“.”改成 “->”就行