目录
1、C语言简介
1.1、程序的入口:main函数
main()
{
/*代码语句*/
}
1.2、程序的返回值:return 值/数据类型;
main()
{
/*代码语句*/
return 0; //0:表示程序正常退出
}
1.3、头文件
1)什么是头文件?
答:头文件是一种包含在源代码文件中的文件,它包含了程序中所需的函数、变量和类型等的声明。
2)有什么作用?
答:为了方便管理和重用代码,它可以被多个源文件共享,从而实现代码的重用和模块化。
3)头文件的种类?
答:头文件可以分为系统头文件和用户头文件两种类型,系统头文件是由编译器提供的,而用户头文件是由程序员自己编写的。
#include <stdio.h>//<>代表引用的头文件是系统头文件,编译器将从系统默认的路径中查找该文件;
#include "123.h"//""代表引用的头文件是用户头文件,编译器将从当前源文件所在目录开始查找该文件。
4)如何引用头文件?
在C/C++中,#include是一个预处理指令,用于将指定的头文件包含在源文件中,以便在程序中使用头文件中定义的函数、变量和类型等。
#include <stdio.h> //系统提供的头文件
#include "123.h" //自己准备的头文件
int main(int argc,char* argv[])
{
printf("Hello,World\n");
return 0;
}
5)系统头文件里有什么?
函数和变量的声明:头文件通常包含函数和变量的声明,以便在编译时可以让编译器知道它们的存在和类型。这些函数和变量的定义通常在其他源文件中,编译器会将它们与头文件中的声明进行链接。
宏定义:头文件可能包含一些宏定义,这些宏可以用于简化代码,提高代码可读性和可维护性。
数据类型定义:头文件可能包含自定义的数据类型定义,这些类型可以在整个程序中使用。
内联函数定义:头文件可能包含内联函数的定义,这些函数通常在头文件中定义,因为它们需要在编译时进行展开。
模板定义:头文件可能包含模板的定义,这些模板可以用于实现泛型编程。
全局变量声明:头文件可能包含全局变量的声明,以便在其他源文件中使用。
6)系统头文件在哪里?
在 Linux 系统中,头文件通常位于 /usr/include
目录下。
可以使用 find
命令来查找系统中的头文件,例如:
find / -name "*.h"
1.4、命令行传递参数
1)什么是命令行传递参数?
在Ubuntu终端中输入命令执行程序的语句是:./Test0
运行结果:Hello World!
但有的时候也可以是这样:./Test0 aaa bbb
运行结果:Hello World!
2)为什么两种运行结果一样?
答:因为命令行输入的aaa、bbb传递到程序之中,没有对其进行处理。
3)如何在命令行向程序传递参数?
int main() //第一种写法
int main(void) //第二种写法
int main(int argc,char *argv[]) //第三种写法
/*
* argc; argument count:命令行传递的参数的个数
* argv[]; argument value:用数组记录每一个参数是什么
*/
前两种写法都是代表不接受任何参数,就算是再命令行输入参数,程序也不会接收。
第三种写法就可以实现在命令行输入参数,程序能够接收处理。
#include <stdio.h>
int main(int argc,char* argv[])
{
printf("argc = %d\n",argc);
printf("argv[0] = %s\n",argv[0]);
printf("argv[1] = %s\n",argv[1]);
return 0;
}
运行结果:
在ubunt终端上输入:./test01 aaa
运行结果:
argc = 2 //传入参数的个数
argv[0] = ./test01 //第一个参数
argv[1] = aaa //第二个参数
1.5、用命令行传递参数的作用?
答:在程序中,对于一些易变的值,用命令行传递参数,可以减少频繁的修改代码,重新编译.........
2、编译问题
2.1、写完代码后,点击编译,编译器在做什么?
答:编译器在检查我们写完的代码在语法上有没有错误。
2.2、点击编译之后会有什么结果?
结果一:编译出错
n error(s),n warning(s)
//代码行出现中文字符 ; 类型赋值不对,数量不匹配等等,不找出问题修改完成,error的个数≠0,
//结果:无法生成可执行的二进制文件
结果二:编译警告
0 error(s),n warning(s)
//例如:使用到printf函数,但是没有包含到stdio.h头文件
//结果:编译不会有报错,但是会报警告,不清零警告也可以生成可执行的二进制文件
结果三:编译通过
0 error(s),0 warning(s)
//没有语法错误,没有缺少内容,
//结果:编译完成之后,直接生成一个可执行的二进制文件
2.3、编译通过:0警告、0报错。那代码就可以实现设计效果?
答:不一定,因为编译通过没有只能说明代码没有语法错误,但在逻辑上是否出错编译器是无法检查出来。
就像每个字都没写错,但是每个字组合在一起能不能成为一首诗,不一定。
2.4、不同编程语言各自的编译器模式
对于编译器而言,有两种编译模式:
编译模式:C/C++、Go语言... ...下,代码给到编译器中,根据运行平台直接进行编译成可执行的二进制文件。
优点:性能快,效率高,
缺点:换一个平台需要重新编译
解析模式:Java、C#、Lua... ...下,代码在给到编译器前需要经过一个解析器,再由编译器进行编译成可执行的二进制文件。
优点:跨平台,减少编译次数,
缺点:牺牲性能,效率
3、数据类型
3.1、什么是数据类型?
答:数据类型是描述一个变量在内存中占用了多少个字节的空间。
3.2、数据类型的种类有哪些?
答:一共有两种数据类型:基本数据类型、非基本数据类型。
//基本数据类型:在Linux环境下,系统本来就存在的数据类型,可以直接使用。
char a,short b,int c,long d,float e,double f,bool g;
//非基本数据类型:在Linux环境下,此类数据类型并不存在,在使用之前需对该数据类型进行声明,再使用
char argv[]; //数组
int* p; //指针
struct T t; //结构体
3.3、基本数据类型可以存放什么数据?
char a; //字符型,-2^7~2^7-1
short b; //短整型,-2^15~2^15-1
int c; //整型,-2^31~2^31-1
long d; //长整型,-2^63~2^63-1
float e; //单精度浮点数,小数点后6位
double f; //双精度浮点数,小数点后15位
注意:C语言有字符串,但是没有字符串类型
3.4、如何获取数据类型在内存中占用的空间有多少字节数?
答:使用到sizeof();计算数据类型在空间中占用的字节数,返回值是一个长整型数据
#include <stdio.h>
int main(int argc,char* argv[])
{
printf("%ld\n",sizeof(char)); //1
printf("%ld\n",sizeof(short)); //2
printf("%ld\n",sizeof(int)); //4
printf("%ld\n",sizeof(long)); //8
printf("%ld\n",sizeof(float)); //4
printf("%ld\n",sizeof(double)); //8
return 0;
}
3.5、总结:
1)如果在程序中声明了一个int类型的变量,那么这个变量在内存中就占用了4个字节
2)基本数据类型在内存中占用的空间字节大小还与操作系统有关。
4、如何定义变量
4.1、定义公式?
答:数据类型 变量名;
数据类型:基本数据类型中的任意一个。
变量名:有一套规则。
① 由一个或多个字母、数字或下划线组成
② 第一个字符必须是字母或下划线
③ 不能与任何关键字相同
4.2、定义变量的意义
数据类型:决定了这个变量在内存中需要开辟多少字节。
变量名:用一个名称去代表这个变量在内存中所在的地址。
4.3、定义一个整型变量,名称为a
答:int a;
4.4、int a;这句话是什么意思?
答:在内存中连续申请4个字节的空间,然后用变量名a去间接访问这片空间。
5、内存分配的原则
5.1、在创建变量时,内存给变量分配的空间一定是连续的。
例如:给int a;分配了四个字节的空间,在空间中一定是0x0000~0x0003,不会是0x0000~0x0002+0x0004
5.2、内存给变量分配的空间,一定是空闲的,之前的变量已经申请过的空间,就不会被再次申请给新变量。
5.3、内存给变量分配的空间,地址是不确定的。
#include <stdio.h>
int main (int argc,char* argv[])
{
int a;
printf("%p",&a); //%p:输出地址符,&:取地址符
return 0;
}
5.4、 总结:连续、空闲、不确定
6、变量赋值、生命周期和作用域
6.1、变量的赋值
1)定义一个变量之后,这个变量就可以用来存放数据。那么怎么把想要存储的数据赋值给这个变量?
答:使用变量赋值符" = ",对变量进行赋值,作用就是把等号右边的值赋值给等号左边的变量。
2)变量赋值的方式?
第一种: 定义变量的同时完成变量初始化
int x = 100; //这个100,就存储在内存中用x代表的空间中
printf("%d",&x); //结果:100
第二种: 先定义变量,再完成变量初始化
int x ; //先在内存中开辟一个空间,代号为x,里面存储的数值为随机数
printf("%d",&x); //结果:随机数
x = 100; //将100替换掉原本的随机数
printf("%d",&x); //结果:100
6.2、变量的生命周期、作用域
1)什么是变量的生命周期?
答:变量从什么时候开始出现在内存空间中,以及什么时候在内存空间中被释放、
2)什么是变量的作用域?
答:这个变量能在程序中起作用的区域。
3)根据作用区域可以将变量分为几种?
答:可分为全局变量、局部变量。
7、全局变量与局部变量
7.1、什么是全局变量与局部变量?
答:程序中不在函数体内部定义的变量就是全局变量,在函数体内部定义的变量就是局部变量。
int x = 100;//全局变量
func()
{
int y = 100;//局部变量
/*代码语句*/
}
7.2、全局变量与局部变量的生命周期有什么区别?
答:区别在于变量什么时候申请内存空间、什么时候释放。
全局变量:在程序开始执行的时候申请内存空间、在程序结束时释放
局部变量:在程序执行至该函数体,在函数体内部申请空间、函数体执行后释放
#include<stdio.h>
int a = 100; //全局变量开始申请内存空间
int b = 200; //全局变量开始申请内存空间
func()
{
int c = 300; //局部变量开始申请内存空间
int d = 400;
return 0; //返回,释放局部变量c、d
}
int main(int argc,char* argv[])
{
return 0; //返回,释放全局变量a、b
}
7.3、全局变量与局部变量的作用域有什么区别?
答:区别在于变量在哪些地方可以使用。
全局变量:在程序中任何位置都可以使用。
局部变量:在程序执行至该函数体,在函数体内部使用。
7.4、全局变量和局部变量的初始值有什么区别?
答:区别在于初始值固定与随机。
全局变量:默认都是0。
局部变量:默认都是随机值。
7.5、关于全局变量和局部变量的一些问题?
1)形式参数属于局部变量还是全局变量?
答:局部变量。
2)能不能在不同的函数中定义名字相同的变量?
答:可以。
3)全局变量和局部变量可以同名吗?
答:可以。
8、变量被定义在内存什么区域
8.1、内存区域是怎么分布的?
答:内存区域分为以下几个:栈区.stack、数据段.bss、数据段.data、常量区.rodata
全局变量是在程序执行开始执行时申请内存空间、程序结束时释放空间
#include<stdio.h>
int a; //未初始化的全局变量
int b = 100; //已初始化的全局变量
func()
{
int c; //未初始化的局部变量
int c = 100; //已初始化的局部变量
return 0;
}
int main(int argc,char* argv[])
{
func();
return 0;
}
暂时先掌握内存空间分布的4个区域