今天来和大家浅谈C语言相关基础,若所见不同,可论之。
目录
一、简单介绍Linux(Ubuntu相关)
首先来看看Linux(以ubuntu为例)和windows系统的目录结构
1、window系统的目录结构
如大家所能看见的,window里面可能有多个盘符,例如C盘,D盘,E盘等,C盘尽量不操作,C盘里面存放的是一些系统配置文件,D、E盘是自己所拆分的磁盘,可以存放个人的一些软件,文档、游戏等(C盘里可以操作,建议有一个良好的安装和保存习惯)
目录结构就像是倒置的森林
路径表示
2、Linux下一切皆文件,
Linux是以 / 作为根目录,所有文件都在 根目录(/)下面;
看起来像一个倒置的树;
home下面的目录就是相当于window里面的用户目录
在home上面普通用户没有操作权限,需要在终端(terminal)界面提升权限才能操作
普通用户和超级用户的标识,$ 和 # ,
普通用户需要提升权限,在命令最前面 输入 sudo,就可以管理员权限执行该命令;或者切换root用户下(一般不建议该条);
3、命令格式
命令格式:命令 [选项] [参数]
注意:
1、[ ]表示可以省略: 选项:功能 参数:操作的对象(文件名,目录等)
2、以上三者用空格隔开
在哪里去输入命令:终端(terminal)
终端:人机交互的界面
4、vim编辑器
ubuntu 里面可使用 sudo apt install vim 可以安装vim编辑器,详情请搜索vim安装教程
使用方法:
命令格式 vim文件名;
如果文件存在,打开文件并进行编辑
如果文件不存在,创建文件并打开进行编辑
vim有三种模式:命令行模式、插入模式、底行模式
二、计算机的基本结构
2.1 基本结构
简单地说由这么几部分组成
存储器又分为:
内存:工作存储器,容量较小,读写速度快,掉电数据会丢失
外存:长期保存数据,容量较大,读写速度较慢,掉电数据不会丢失
寄存器:CPU内部存储器,容量最小,读写速度最快
2.2 计算机的数据表示
2.2.1 数据存储方式
分为:数值数据、非数值数据
非数值数据(不能够直接进行算数运算的数据)
字符(‘a’ ‘b’ ) 、图片、声音
ASCII码表:规定了每一个字符以哪八位二进制数表示(1 Type(字节) == 8 bit (比特))
数值数据(可以直接进行算术运算的数据)
数字基本进制有以下几种:二进制、八进制、十进制、十六进制
二进制:逢二进1: 0~1组成
八进制:逢八进1: 0~7组成
十进制:逢十进1: 0~9组成
十六进制:逢十六进1: 0~9,a~f 构成
为区分不同的进制:我们给八进制前加0,十六进制前加0x(0X)
76(十进制) 076(八进制) 0x76(0X76)(十六进制) (如果A-F是大写,X就要用大写)
不合法数 0769
2.3 进制转换:
其他进制转十进制
其他进制转十进制:对应的数乘以对应的指数次幂之和
二进制转十进制: 1010 == 02^0+12^1+02^2+12^3= 10
八进制转十进制: 054 == 48^0+58^1 = 44
十六进制转十进制:0xaf4 == 416^0+1516^1+10*16^2 = 2804
十进制转其他进制
十进制转其他进制:除以其他进制逆序取余数
十进制转二进制: 除2倒取余 43 =>101011
十进制转八进制: 除8倒取余 43=>053
十进制转十六进制:除16倒取余 43=>0x2b
三、C语言的关键字
3.1 关键字
在C语言里面,关键字拥有32个,都是系统预先定义的,全是小写(C语言是区分大小写的编程语言)
数据类型:char、short、int、long、float、double、struct(结构体)、enum(枚举)、union(共用体)、void(空类型)
控制语句:for 、if、else、do、while、break、continue、switch、case、default、goto
存储类型:auto、static、extern、register
const:修饰的变量(或者指针),只读
return:返回函数
signed:有符号数
unsigned:无符号数
sizeof:计算所占内存空间的大小:单位(字节) sizeof(数据类型)//sizeof(变量名)
typedef:给已有的数据类型起别名;
volatile:防止编译器优化(学linux驱动可能比较了解)
3.2 标识符
C 标识符是用来标识变量、函数,或任何其他用户自定义项目的名称。一个标识符以字母 A-Z 或 a-z 或下划线 _ 开始,后跟零个或多个字母、下划线和数字(0-9),第一个不能为数字。
C 标识符内不允许出现标点字符,比如 @、$ 和 %。C 是区分大小写的编程语言。因此,在 C 中,Manpower 和 manpower 是两个不同的标识符。下面列出几个有效的标识符:
mohd zara abc move_name a_123
myname50 _temp j a23b9 retVal
3.3 基本数据类型
包括字符型(char)、整型(short,int,long)、浮点型(float)和双精度浮点型(double)、它们是算术类型
32_OS(32位操作系统):
字符型: char——1字节
整型: short——2字节 int——4字节 long——4字节
浮点型:float——4字节 double——8字节
64_OS:
字符型: char ——1字节 == 8 比特
整型: short—— 2字节 int——4字节 long——8字节
浮点型:float——4字节 double——8字节
读者可自行验证
#include <stdio.h>
int main()
{
/*
char a ;
short b;
int c;
long d;
float e;
double f;
*/
/*
//这是一种输出方式
printf("sizeof(char)=%ld\n",sizeof(char));
printf("sizeof(short)=%ld\n",sizeof(short));
printf("sizeof(int)=%ld\n",sizeof(int));
printf("sizeof(long)=%ld\n",sizeof(long));
printf("sizeof(float)=%ld\n",sizeof(float));
printf("sizeof(double)=%ld\n",sizeof(double));
*/
/*
//这是另一种输出方式
printf("char -> %d\n", sizeof(a));
//求char类型的长度 结果是一个字节 8bit(位)
printf("short -> %d\n", sizeof(b));
//求short类型的长度,结果是2个字节 16bit (位)
printf("int -> %d\n", sizeof(c));
// int类型的字节长度,结果是4个字节 32bit (位)
printf("long -> %d\n", sizeof(d));
// long类型的字节长度,结果是4个字节 32bit(位)
// long 类型在64位OS里面长度是8个字节 64bit(位)
printf("float -> %d\n", sizeof(e));
// float类型的长度,结果是4个字节 32bit(位)
printf("double -> %d\n", sizeof(f));
// double类型的长度,结果是8个字节 64bit (位)
*/
signed char a = 130; //读者可思考保存数据超出范围时该怎么处理
printf("%d\n ", a) ;
/*
float q = 333.33333333; //验证flaot和double的输出方式
double b = 444.44444444;
printf(" %f \n",q);
printf(" %lf \n",b);
*/
return 0;
}
3.4有符号数和无符号数:
unsigned:无符号数:无符号整数 包括0和正数
signed:有符号数
有符号数:有正数有负数
最高位用来表示符号位,0正 1负
在计算机中:数据是以二进制的补码的形式存储的
补码
正数:正数的原码,反码,补码都是一样的(不管是有符号还是无符号,只要是正数)
负数:
原码:最高位为符号位,其他位为数据位(直接转为二进制)
反码:原码的符号位不变,其他位取反(0变1,1变0)
补码:反码+1
知道一个数的补码:如何求原码?
1111 0110?
方法1:减1取反
减1
1111 0101
取反
1 000 1010 (-10)
方法2:补码的补码就是原码 (常用)
1111 0110
取反:1000 1001
加1: 1000 1010 (-10)
四、常量
4.1 字符常量
‘a’ ‘A’
97 65
4.1 整型常量
二进制:1010
八进制:066
十六进制:0xaf5
十进制:99,-2
注意:默认情况下,整形常量为有符号数;
无符号的int类型:98U
Long类型:76L
无符号的长整型:78UL
4.3 浮点型常量
小数:3.14 0.00001 10000(浮点型常量包含整形常量)
指数:1e+5 == 100000 1e-5 == 0.00001
#include <stdio.h>
int main()
{
float a = 0.01;
float b = 0.001;
float c = 0.0001;
float d = 0.00001;
float e = 0.000001;
float f = 0.0000001;
printf("%g\n", a);
printf("%g\n", b);
printf("%g\n", c);
printf("%g\n", d);
printf("%g\n", e);
printf("%g\n", f);
return 0;
}
%g: 选择小数或者指数中比较合适(比较短)的一种情况进行输出
4.4 字符串常量
“hello”占几个字节‘h’ ‘e’ ‘l’ ‘l’ ‘o’ ‘\0’: 6个字节
(字符串用双引号括起来,字符用单引号括起来)
注意:字符串由‘\0’结尾
4.5 标识常量(宏)
本质是:宏只是一个单纯的替换!
4.5.1 宏
#define 宏名 表达式
注意:
1、宏名一般用大写,为了和普通的变量区分开,当然小写也可以
2、宏后没有分号
4.5.2 宏函数:
既有宏的特点,又有函数的特点
#define 函数名(形参列表) 函数体或者表达式
#include <stdio.h>
//#define ADD(a,b) (a+b)
int main()
{
printf("%d\n",ADD(2,3)*ADD(2,1));
return 0;
}
五、变量
如何定义一个变量
意味着要在内存中开辟空间,系统会分配一个0 - 4G的虚拟内存空间
存储类型 数据类型 变量名;
//存储类型:决定了在哪块区域去开辟空间
//数据类型:决定了开辟的内存空间的大小
//变量名:开辟的内存空间的名字
存储类型:auto、static、extern、register
#include <stdio.h>
int count = 5; //全局变量
int main()
{
int sum = 17, //局部变量
return 0;
}
存储类型分为:
auto:
修饰局部变量,存储在栈区, 局部变量如果没有初始化,其值为随机值!
(为了避免随机值,一般给局部变量初始化为0!)
register:
修饰局部变量,修饰的变量存储在寄存器中,但是寄存器的内存空间很小,因此,当寄存器已满时,再用register修饰,变量会存储在栈区
extern:
修饰全局变量,存储在静态区
程序可以由多个.c构成,但是有且只能有一个main函数
作用:告诉编译器,该变量已经在其他文件中定义过了
extern:声明全局变量时:
extern int a //声明全局变量,表示在另一文件就中已经定义或初始化过a变量,此处引用该值
int a //若不做修饰的,则相当于定义变量。全局变量没有初始化,其值为0;
static
即可以修饰局部变量,也可以修饰全局变量,存储在静态区(.bss和.data)
1、如果static修饰局部变量:
作用:延长局部变量的生命周期;如果局部变量没有初始化,那么局部变量的值为0;如果初始化了,只能初始化1次;
如果static修饰局部变量未初始化,那么局部变量的值为0;
使用auto修饰的局部变量未初始化则为随机值
2、如果static修饰全局变量:
作用:限制作用域,只能在本.c文件内使用
六、生命周期 和 作用域
前者是从开辟空间到空间释放
后者是使用的范围
七、数据类型转换
7.1 强转类型转换(我们自己去转的)
#include <stdio.h>
int main()
{
int sum = 17,count = 5;
double mean;
mean = (double)sum / count; //强制类型转换将int型sum转换为double类型
printf(“mean = %.2lf\n”,mean);
return 0;
}
7.2 隐式类型转换(编译器去转的)
C语言的隐式类型转换和显示类型转换 - 知乎 (zhihu.com)
八、运算符
单算移关与,异或逻条赋
单目运算符,算术运算符,左移右移,关系运算符、按位与
异或 、按位或、逻辑运算符、条件运算符、赋值
算术运算符
+、-、*、/、++、--、%
注意:%不能用于浮点数
++在前:先自加,在赋值,最后两边的值相等
++在后:先赋值,在自加
注意:如果++a和a++单独成立一条语句,那么都相当于a+1
8.2关系运算符
> < >= <= == !=
8.3 逻辑运算符
&&、 || 、 !
1、与:&&
表达式1 && 表达式2 && 表达式3 ……
截断法则:有一个为假,结果就为假,前一个为假,后面就不在进行运算了(有0为0,全真为真)
2、或:||
表达式1 || 表达式2 ||表达式3 ……
截断法则:有一个为真,结果就为真,前一个为真,后面就不在进行运算(有真为真,全假为假)
3、非:!
非真(1)即假(0)
非假(0)即真(1)
4、异或 ^
相同为0,不同为1
九、输入输出
函数:具有独立功能的模块
标准输入输出函数:scanf、printf(对变量的类型没有限制)
输入:从键盘拷贝数据到内存中
输出:将内存中的数据拷贝到终端
1.1 输出
printf(“格式控制串”,输出表/变量名);
格式控制串:原样输出的内容 + 格式化符
输出表:输出的内容
注意:输出的内容要和格式化符一一对应
整型:
%d:十进制的整数
%o:八进制
%x %X:十六进制
#:自动在八进制和十六进制前加上前缀
%u:以无符号的整型
%hd:short类型
%ld:long类型
十、三大结构
顺序结构、选择结构、循环结构
1、顺序结构
语句按照一定的先后顺序去执行
2、选择结构
2.1 单分支选择结构
if(表达式)
{
语句;
}
先判断表达式是否成立,如果成立,执行语句
2.2 双分支选择结构
if(表达式)
{
语句1;
}
else
{
语句2;
}
先判断表达式是否成立,如果成立,就执行语句1,否则,执行语句2;
2.3 多分支if选择结构
if(表达式1)
{
语句1;
}
else if(表达式2)
{
语句2;
}
else if(表达式3)
{
语句3;
}
……
……
else if(表达式n-1)
{
语句n-1;
}
else
{
语句n;
}
从上往下,依次去判断每个表达式是否成立,如果成立,就执行对应的语句
2.4 switch语句
switch(表达式) //表达式不能为float类型;
{
case 标号1: //标号必须为常量;
语句1;
case 标号2:
语句2;
case 标号3:
语句4;
case 标号n-1:
语句n-1;
default:
语句n;
}
注意:
当表达式等于标号的时候:执行冒号后面的语句!(如果都不相等,默认执行default后面的语句!)直到switch,case语句结束,或者遇到break语句结束!
结束条件:(停止输出冒号后面的语句的条件)
1、遇到break,跳出switch语句
2、switch,case语句结束
3 、循环结构
重复的去做一件事
三要素:循环的起始条件、循环的终止条件、循环变量的变化
3.1 for循环
for(表达式1 ;表达式2 ;表达式3)
{
//循环体;
}
表达式1:循环的起始条件
表达式2:循环的终止条件
表达式3:循环变量的变化
先执行表达式1;然后判断表达式2是否为真,如果为真,则执行循环体,然后执行表达式3,以此反复,直至表达式2为假,跳出循环!
思考:表达式1,表达式2,表达式3是否可以省略?
省略表达式1:在for循环之外:要给循环变量一个初始值
省略表达式2:死循环(相当于 while (1))
for(; ; ;)
{
}
省略表达式3:循环体内实现循环变量的变化
for (i = 0;i < N;)
{
语句;
i++; //在循环体内实现变量的变化
}
注意:表达式1,表达式2,表达式3都可以省略,但是分号不能省略
3.2 while语句
while(表达式)
{
//循环体;
}
判断表达式是否成立,如果成立,则执行循环体,否则,跳出循环
案例:用while语句实现1-100之和
2.3.3 do...while语句
do
{
//循环体
}while(表达式);
先执行循环体;判断表达式是否成立,如果成立,则执行循环体,否则,跳出循环;
案例:用do...while语句实现1-100之和
区别:
while语句:先判断,在执行,语句至少执行0次;
do...while语句:先执行,在判断,语句至少执行1次;
2.3.4 break和continue的区别:
(跳出离他最近的一个循环!)
break:
1、跳出switch、case语句
2、跳出循环
continue:跳出本次循环,进入下一次循环
2.3.5 死循环
while(1)
{
循环体;
}
for( ; 1 ; )
{
循环体
}
2.3.6 goto语句
无条件跳转语句
一般格式为:
goto 标号;
标号:
十一、数组(一维数组)
一组数据类型相同的元素组成的集合(一堆数据类型相同的数据组合在一起!)
特点:1、数据类型相同 2、地址连续(打印地址:%p)
存储类型 数据类型 数组名[元素的个数];
int a[5];
//相当于定义了一个数组:数组名为:a:数组中有5个元素,这五个元素都是int类型的
数据类型:数组中元素的数据类型
数组的数据类型:int [5]
数据类型:去掉变量名,剩下的就是数据类型!
开辟的内存空间的大小 = sizeof(数据类型)*元素的个数
计算数组元素的个数 = sizeof(arr)/ sizeof(arr[0])
1、指针
1.1 什么是指针?
char是一种数据类型,它是一种保存字符的数据类型(‘a’,‘b’)
int 是一种数据类型,它是一种保存整形数的数据类型(10,20)
float是一种数据类型,他是一种保存浮点数的数据类型(3.14 2.37)
指针是一种数据类型,它是一种保存地址的数据类型(%p能打印出地址编号)
1.2 什么是地址?
内存分配的最小单元是字节,每一个字节都有一个编号,这个编号就叫做地址!
地址的本质:内存单元的编号!
指针:指针就是地址
指针的本质:内存单元的编号
1.3 指针常量
char 定义的变量-----------保存字符常量
int 定义的变量----------保存整形常量
float 定义的变量-------保存浮点型常量
指针 定义的变量-------保存指针常量(地址:专门用来保存内存单元的编号)
1.4 指针变量(定义指针)
定义一个指针变量
存储类型 数据类型* 变量名;
int * p;
// * 用来表示p是一个指针变量
// 定义了一个指针变量p,这个p用来保存指针变量的地址
// 指针保存谁的地址è指针指向谁
数据类型:指针指向的数据类型
指针p的数据类型:int *;
指针指向的数据类型:去掉一个*,去掉变量名,剩下的就是指针指向的数据类型!
// int *p 指向的数据类型是int 型
注意:*和&互为逆运算;
p保存了a的地址,作用是什么?
间接访问a的值,进而间接改变a的值
1.5 指针的赋值
指针的赋值:相当于改变指针的指向;
注意:对指针变量进行赋值时,要注意类型匹配!
思考?(再熟悉概念)
1、什么是指针?
指针是一种数据类型,这种变量类型用来存放地址
2、地址是什么?
内存最小的分配单元是字节,每个字节都有相应的编号,这个编号就称地址
3、什么是指针变量?
用来存放指针类型的变量就是指针变量
4、指针变量如何定义?
存储类型 数据类型 * 变量名
存储类型 数据类型 * 变量名
int * p
5、如何给指针变量赋值?
改变指针的指向,赋值时要注意指针类型匹配
int a = 10;
int *p = &a;
char *p = &a; //错误,指针类型不匹配
6、指针变量赋值之后可以干什么?
间接访问变量的值,进而改变间接改变变量的值
int a = 10;
int *p = &a;
*(&a)= 30;
//此时a的值改变为30;
*p = 20;
//此时a的值改变为20;
注意:在32_OS和64_OS
在32_OS中:所有的指针都占4 Type(字节)
在64_OS中,所有的指针都占8 Type(字节)
注:我在51cto上上传过同样的一篇