目录
一个程序一定需要main函数吗(一定需要主函数)?可以多个main吗?
什么是c语言?
1.c语言是计算机语言(人和计算机交流的语言),如同中国人和外国人交流会使用英语一样。
2.计算机语言又有哪些?(相当于语言的种类如:日语 ,英语,德语等 )这里有C/C++ JAVA Python等都是计算机语言
3.计算机语言的发展:
早期计算机语言是二进制语言 ,因为机器是要通电的通电只有正电和负电的区别,故计算机中正电用1表达 负电用零表达原因其实就是计算机只能处理电信号而电信号只有两种状态所以用了二进制。因此早期的代码都是由一串0和1组成的序列表示代码很抽象非专业人士无法看懂。如果10100001这串二进制代表加法,那么你每次用加法真的很抽象。后来有人想到了用助记符用 ADD--10100001用 ADD 这个这个符号代表加法的二进制。由此就诞生了汇编语言。可以理解为有助记符的机械语言为汇编语言。
10100001 - ADD -助记符 - 汇编语言
由此产生了B语言 ,再B语言的基础上产生了C语言,C++到了C++的时候已经变成了高级语言了。(说白了就是门槛变低了 不再是科学家才会的东西)
任何语言在发展的过程中都会从成熟到成熟的转变C语言同意也是这样:
C语言------------>早期不是很成熟------------>成熟---------------->流行
C语言是由国际标准的:ANSIC- C89/C90 。有了国际标准后更能让人接受受众广。
第一个C语言程序
int main()
{
return 0;
}
所有的代码都是这个格式 也就是我们所说的main函数也称之主函数 ,那我们想要打印 hehe 这是我们就该引用printf这个打印函数(print--打印 f-function--函数 故printf为打印函数 ) 如下。
int main()
{
printf("hehe");
return 0;
}
又因为printf是C语言中自带的函数我想用这个函数是不是得向这个函数得主人申请那么此时需要向头文件去申请(#include<stdio.h>)include为包括得意思,stdio中 std----standrand标准化 ; i--input输入;o--output输出;.h为头文件得后缀 ,那么这个申请可以认为:包括一个含有标准输入输出得头文件 。而printf不就是打印嘛 打印不正好是输出。这样代码如下
#indlude<stdio.h> //std--标准化;input-输入;output-输出
int main()//主函数-程序得入口
{
printf("hehe");//printf--打印函数
return 0;
}
这里肯定会有人好奇为什么要main函数,main函数到底是干嘛的,这里我们可以编写好上面得代码按F10我们会发现,箭头出现在main函数得下面一行,再次按F10发现出现了hehe,这里我们是不是可以得出结论main函数是程序得入口。这里我们可以多打印几个hehe看看按F10之后会出现什么情况,这里读者可自己试试看。
#indlude<stdio.h> //std--标准化;input-输入;output-输出
int main()//主函数-程序得入口--有且只有一个
{
printf("hehe");//printf--打印函数
printf("hehe");
printf("hehe");
printf("hehe");
printf("hehe");
printf("hehe");
return 0;
}
一个程序一定需要main函数吗(一定需要主函数)?可以多个main吗?
一个程序一定是需要main函数得,如果没有main函数编译的时候就找不到程序的入口了,那既然如此可以写多个main函数嘛?显然不行如果多个main函数那么程序的入口就会多个那到底往哪个程序入口进入呢,显然多个main函数也是不行的。
这里便可得出结论:main函数是程序的入口并且只有唯一一个
main函数的框架,以及printf函数
//main函数的框架
int main()
{
//这里完成任务
//这里我想答应hello word
return 0;
}
这里我们分析下 return 0;是返回 0的意思这里的0是整型 而int也是整型的意思 而
main前面的int:表示mian函数调用返回一个整型 。而结尾的return 0;不就是返回一个0是不是前后呼应了
这里我们想打印hello word用 之前讲过的printf函数 printf的用法也简单如下:
printf("想打印的内容");但是我们注意printf是库函数--C语言本身提供给我们使用的函数相当于是别人的东西那需要和别人打招呼那么我们如何打招呼呢:#include<stdio.h>(包含标准输入输出的头文件)
//main函数的框架
#include<stdio.h>
int main()
{
//这里完成任务
//这里我想答应hello word
printf("hello word");
return 0;
}
数据类型
变成是为了解决生活中的问题,解决问题说白了其实就是处理数据,比如我的体重77.2公斤,我去菜市场买菜10.8元,我这个月工资5000元我们发现无非就是整数 小数。
因此C语言中也是如此数据有字符型整型和浮点型(小数):如下
char | 字符类型数据 |
short | 短整型 |
int | 整型 |
long | 长整型 |
long long | 更长的整型 |
float | 浮点型 |
double | 双精度浮点型 |
我们如何使用数据类型呢?假如我想打印一个字符 A 和一个整数100应该怎么写代码
#include<stdio.h>
int main()
{
char ch="A";
int a =100;
printf("%c\n",ch);
printf("%d\n", a);
return 0;
}
这里我们要知道在C中字符是要加双引号的
char ch="A"我们可以理解为向内存申请一个只能放字符名字为ch的空间放字符A。
int a=100;就可以认为向内存生气一个只能放整型名字为a的空间放整型100。
printf("%c\n",ch);在之前讲printf的时候我们说过大爷的内容是双引号里面的内容,这里我们可以理解为打印字符(%c字符型控制符)然后换行(\n为换行符)--打印谁的字符答应ch这个空间里的字符也就是A。
同理%d为整型十进制控制符 打印数字然后换行--打印谁的整型,当然答应a空间里面的整型啊。
到这里我是不是知道了数据的类型是干什么的吧:用来向内存申请空间类型存放同类的数据。
为什么整型 ,和浮点型有这么多种类?每种类型的大小?
整型有 int ,short,long,long long
浮点型 float,double
其实从文字上也可以看出这里我们short(短整型) 和int(整型)顾名思义短整型比整型短啊哈哈哈哈
不开玩笑这里我们写出代码:
#include<stdio.h>
int main()
{
printf("%d\n",sizeof(char));//1
printf("%d\n",sizeof(short));//2
printf("%d\n",sizeof(int));//4
printf("%d\n",sizeof(long));//4
printf("%d\n",sizeof(long long));//8
printf("%d\n",sizeof(float));//4
printf("%d\n",sizeof(double));//8
return 0;
}
这里肯定有人好奇sizeof是什么,sizeof(char)其实是字符型的大小,那 printf("%d\n",sizeof(char)); 这一行就是打印一个数字----字符型大小
同理 printf("%d\n",sizeof(short)); 用十进制这个数字打印短整型的大小。这里上面的代码会出现 1 2 4 4 8 4 8这几个数字就对应了各个类型的大小 这时肯定有疑问了为什么sizeof(int)和sizeof(long)都是4不应该长整型要比整型大吗 !这里记住sizeof(int)<=sizeof(long)即可,哈哈哈哈。
也会有人会疑问这个1 2 4 4 8 4 8到底是上面意思?其实这些数字都代表这多少字节也就是说:
char --一个字节 ;short--两字节;int--四字节;ong-- 四个字节;long long--八个字节 ;float--四个字节 ;double--八个字节
说到字节我们要知道计算机储存的最小单位为一个bit
bit-比特位
byte-字节=8bit
kb=1024byte
mb=1024kb
tb=1024mb
pb=1024tb
对于bit特别说明由于计算机是硬件----通电 只有两种状态一种正电(1)一种负电(0)如果我们想在计算机中存储1那么就需要一个比特位(bit)存放这个二进制,如果我们还需要存放0那么我们需要另外开辟一个bit位存放0这个二进制位
这里我们是不是可以总结为bit--比特位是用来存放一个二进制数的也是计算机存储的最小单位。
那么这个时候可能有人不懂说明是二进制了,在我们生活中我们基本上用的时进制较多
十进制的规则满10进1,有0 1 2 3 4 5 6 7 8 9这几个元素
二进制满二进一,有1 0这两个元素,当然时钟的话就是12进制满12进1
这里我们看short类型一共有两字节也就是16位那这个short的范围可以从:0000 0000 0000 0000~1111 1111 1111 1111也就是有2^16种可能也就是十进制可以表达0~2^16-1。因此此在生活中表达一个人的年龄时我们用int 来申请的话需要向内存申请四个字节而年龄的话不可能超过两百岁这里就用short就比较合适 。
所以我们可以总结:数据类型的多样化是为了节省空间,让不同数据都有所对于。
变量和常量
生活中有变量和常量,比如血型肯定是常量,时间肯定也是变量吧
接下来我们看看如何定义常量
int main()
{
100;//整型常量
3.14//浮点型常量
return 0;
}
这里单纯的常量显然毫无意义所以常量的用于定义变量反而有了意义
变量定义
数据类型+名称=常量;
这里我定义年龄为20敲出代码
int main()
{
shourt age=20;//向内存申请两字节存放20
float weight=90.7f//向内存生气四个字节存放小数这个加上f是因为默认小数是双精度又申请的是单精度
return 0;
}
局部变量和全局变量
全局变量:在大括号外的变量为全局变量
局部变量:在大括号内的变量为局部变量
int a=20;//全局变量
int main()
{
int a=10;//局部变量
printf("%d\n",a);
return 0;
}
这里发现运行上述代码编译器不会报错且输出显示为10,那么可以得出结论当局部变量和全局变量名一样时局部变量得优先级比全局变量高。
作用域和生命周期
局部变量得作用域和生命周期
#include<stdio.h>
int main()
{
int a=20;
{
int a=10;
}
printf("%d",a);
return 0;
}
运行结果为20,这个程序发现第一个变量a能被打印出来 而第二个变量a=10,没有答应出从这个简单得代码便可得出结论变量在哪个括弧内他得作用域就在哪里出了这个括弧就不是变量得作用域了。同样得就在这个括弧内又作用那么他得生命周期也就是在那个范围出了这个括弧其生命周期和作用域就没了。
全局变量得作用域及生命周期
分析以下代码
#include<stdio.h>
int a=100;
int main()
{
int b=200;
printf("%d %d",a b);
return 0;
}
运行后发现可以讲将局部变量b的200和全局变量a的100都能输出,那么我们就可以认为全局变量的作用域是整个代码,生命周期是main函数的生命周期。
常量
字面常量
int main()
{
100;//字面常量
return 0;
}
这个100就是所谓的字面常量,一般情况用于与变量一起使用。
const修饰的常属性常量
这是常量的用法就是将100赋值给变量a,最后的运行结果也会是100
#include<stdio.h>
int main()
{
int a=0;//初始化
a=100;//将100赋值给a
printf("%d\n",a);
return 0;
}
接下来试试让const修饰变量啊看看会如何。
#include<stdio.h>
int main()
{
const int a=0;//初始化
a=100;//将100赋值给a
printf("%d\n",a);
return 0;
}
我们发现编译会报错,而之前没加const的时候程序是可以编译的。哈哈哈哈原因是const能让这个变量a变不了让他具有常属性。既然如此那么具有常属性的变量a到底是常量还是变量呢?
#indlude<stdio.h>
int main()
{
int a=5;
int arr[a]={0};
return 0;
}
#indlude<stdio.h>
int main()
{
int a=5;
int arr[5]={0};
return 0;
}
看上面两个代码前者会报错因为数组里[ ]里的值应该为常量而不是变量a,而后者满足要求所以不会报错这个时候是不是又会说我们那用const修饰a让他具有常属性会怎么样我们写出代码
#indlude<stdio.h>
int main()
{
const int a=5;
int arr[a]={0};
return 0;
}
我们发现代码还会报错哈哈哈哈哈这样我们是不是就是知道了const修饰的常属性变量只是让变量具有了常属性但是他的本质还是变量,可以理解为伪娘虽然表面上是女生其实呢是个男生哈哈哈哈哈。
#include<stdio.h>
#define p 5
int main()
{
int arr[p]={0};
return 0;
}
这是可以运行的,就说明define修饰的字符常量
枚举常量就是能一一例举的常量比如性别:男,女,保密。三原色等
#include<stdio.h>
enum color
{
YELLOW,
RED,
BLUE
};
int main()
{
printf("%d\n",yellow);
printf("%d\n",red);
printf("%d\n",blue);
return 0;
}
这里以三原色为例子敲除代码如下并运行发现
也就是说枚举常量是有值的。
这里我们改变枚举常量的值给RED赋值2,看看会出现什么情况
#include<stdio.h>
enum Color
{
yellow,
red=2,
blue
};
int main()
{
printf("%d\n", yellow);
printf("%d\n", red);
printf("%d\n", blue);
return 0;
}
哈哈发现当RED为2时,下面的blue就变为3了。
字符串+转义字符+注释
字符串
在数据类型中有字符型char但是没有字符串型,那我们我们要定义字符串时可以用数组来定义
这里说明下在C中双引号引用字符串,单引号引用的是单个字符例如
”abc“表示的是字符串abc ,‘a’表示字符啊,‘a’‘b’‘c’表示三个字符a单个字符b单个字符c。
这里特别注意”a“与‘a’的区别双引号的a是字符串a,而单引号的a是字符a。那么代码如下
#include<stdio.h>
int main()
{
char arr1[]="abc";
char arr2[]={'a','b','c'};
printf("%s\n",arr1);
printf("%s\n",arr2);
return 0;
}
这里分别用字符串定义数组和用字符定义数组,(%s为打印字符串)看看输出的情况
发现arr2的输出出现了其他的东西这是为什么呢?这里我们打开监视
发现arr1这个数组里有四个元素,而arr2只有三个元素但是啊arr1打印的确实是abc那我们给arr2补个零会不会也变成abc
发现真的变成abc了那我们是可以认为当我们用字符串定义的时候字符串会自动在结尾处放个0只不过可以省略但是内存中确实有这个\0,而用字符定义数组的时候则不会默认有零出现所以要补0那字符定义的时候为什么会出现乱码呢?\0为字符串的结束标志,而字符定义的时候先答应出abc三个元素后因为后面没有结束标志\0所以就一直打印随机值知道遇到了\0猜停止了打印。
这里我们总结下字符串的结束标志是\0的转义字符,在计算字符串的长度或者输出时\0只是结束标志不算在长度内也不会输出实际的内容。
转义字符
转义字符就是转变原来的意思、
以向打印csdn为例我们可以编写以下代码
#include<stdio.h>
int main()
{
printf("csdn");
return 0;
}
运行结果如下,但是我把n改为\n会出现什么情况呢,会不会答应出csd\n呢?
代码如下:
#include<stdio.h>
int main()
{
printf("csd\n");
return 0;
}
我们发现打印出来的是csd且换行。这里是不是就能看出\n就是\将原来的n的意思转变了故\n就是一个转义字符------换行。其他转义字符功能如下:
这里我们着重说明下最后两个转义字符\ddd:ddd表示1-3个八进制数转化为十进制数所对于的ASCII值这里我们给出ASCII表
以/136为例136为八进制数那么把他转换为十进制也就是6*8^0+3*8^1+1*8^2=94对应ASCII表就是 ” ^“ 这个符号。这里我们验证以下编写代码
#include<stdio.h>
int main()
{
int a = 0136;
printf("%d\n",a);
printf("\136");
return 0;
}
\xdd中dd为两个十六进制数其意思为将dd这个16进制数转换为十进制所对应的ASCII值
以\xab为例3b的十进制值为11*16^0+3*16^1=59对应ASCII的值为”;“下面我们写上代码检验
#include<stdio.h>
int main()
{
int a=0x3b;
printf("%d\n",a);
printf("\x3b");
return 0;
}
注释
第一个是注释 第二个是取消注释
强调一下
1.字符串的结束标志是\0
2.\0的ASCII值为0,而‘0’的ASCII的值是32
选择语句
生活中处处都有选择拿个简单的说法好好学习就会有好成绩不好好学习就会变成死肥仔,那在c语言中如何使用选择语句呢
#include<stdio.h>
int main()
{
char input=0;
printf("你要好好学习吗(Y/N)?");
scanf("%c", &input);
if (input == 'Y')
printf("好offer\n");
else
printf("成为死肥宅");
return 0;
}
这就是常说的if else语句当然这是两种分支的情况不是好offer就是死肥宅 ,那如果出现三种分支呢?那又该如何呢?这些以后再说。
循环语句
循环语句其实就是表示循环:举个例子
S1:每天干两件事:到S2
S2:买彩票:中了彩票到S4,也可道S3;没中到S4
S3:学习 :变成大牛到S4,还是菜鸟到S2
S4:迎娶白富美
#include<stdio.h>
int main()
{
int list=0;
printf("为了好offer\n");
while(list<2000)
{
printf("我敲一行代码%d\n",list);
list++;
}
printf("好offer\n");
return 0;
}
函数
想求两个数的和
#include<stdio.h>
int main()
{
int a = 0;
int b = 0;
int sum = 0;
printf("请输入两个数字\n");
scanf("%d %d", &a, &b);
sum = a + b;
printf("a+b=%d",sum);
return 0;
}
这里我们用函数的方式
#include<stdio.h>
int ADD(int x, int y)
{
return x + y;
}
int main()
{
int sum;
int a, b;
scanf("%d %d", &a, &b);
sum = ADD(a, b);
printf("a+b=%d",sum);
return 0;
}
程序运行的逻辑在 sum=ADD(a,b)时就开始调用了ADD函数并将a值赋予了给x,b值赋予给了y最后返回x+y的值给sum这个变量。
数组
如果要存储1-10这些数应该怎么存储,难道创建10个变量吗!这也太捞了。有没有其他方法我们发现我们要存储的1-10这些数都是整型是一组相同类型的集合。那么我们就可以用数组来定义。
int arr[10];---------arr为数组民------------定义一个存放10个元素的整型数组
char ch[20];--------------定义一个存放20个元素的字符型数组
那我们想将1-10这些数放入arr中该如何放呢?如下
int arr[10]={1,2,3,4,5,6,7,8,9,10};
其在内存名称为arr有10个元素每个元素都有小标下标从0开始。如果我吗想要访问数组中第二个元素就是arr[1] ,想要访问第一个元素就是arr[0]
#include<stdio.h>
int main()
{
int arr[10]={1,3,7,8,84,13,12,24,77,10};
printf("%d\n",arr[4]);
return 0;
}
其实就是第五个元素84
那我们如何答应数组中所有的元素呢
#include<stdio.h>
int main()
{
int i = 0;
int arr[10] = { 1,3,7,8,84,13,12,24,77,10 };
while (i < 10)
{
printf("%-3d", arr[i]);
i++;
}
return 0;
}
操作符
算术操作符
+ - * / %
*为乘操作符
/除操作符在c中 10/3=3 是会把小数部分给去掉同理 1/2=0那如何让他显示小数呢,只要分母和分子有一个是小数的形式就可以有小数。
%去模操作符就是取余数操作符。
移位操作符
>> 右移操作符
<<左移操作符
a<<1 :意思为a左移动一位
int a=1;//变量a是四个字节也就是32bit放的就是下面这串二进制数列
0000 0000 0000 0000 0000 0000 0000 0001
00000 0000 0000 0000 0000 0000 0000 0010
向左移动一位空位补0,也就是说a<<变成了2
#include<stdio.h>
int main()
{
int a=1;
a<<=1;
printf("%d",a);
return 0;
}
逻辑操作符
& ^ |
&按位与:全1为1
001
101
001
^按位异或:相同为0相异为1
001
101
100
|按位或:有1为1
001
101
101
单目操作符,双目操作符,三目操作符
a+b;//双目操作符因为加号有两个操作数
单目操作符:
!逻辑反 真变为假 ,假变为真
&取地址操作符
sizeof()计算的是变量/类型所占的大小单位是字节
#include<stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8 };//这里int是指数组arr中的元素是int类型,如果arr[]中[]不填,那么元素的个数会和后面的个数一样
int a;
printf("%d\n", sizeof(a));//4
printf("%d\n", sizeof a);//4这里求a的大小发现与加()是等价的是不是就可以判断出sizeof()不是函数如果是函数一定要有()
printf("%d\n", sizeof(int));//4
//printf("%d\n", sizeofint);//err
printf("%d\n", sizeof(arr));//4*8=32 这里有八个元素,每个元素四个字节
printf("%d\n", sizeof(arr) / sizeof(arr[0]));//求出数组的大小,再除以每个元素大小是不是可以求出元素的个数。
return 0;
}
这串代码我们发现
第一点:
printf("%d\n", sizeof(a));//4
printf("%d\n", sizeof a);//4这里求a的大小发现与加()是等价的是不是就可以判断出sizeof()不是函数如果是函数一定要有()
第二点
printf("%d\n", sizeof(arr));//4*8=32 这里有八个元素,每个元素四个字节
printf("%d\n", sizeof(arr) / sizeof(arr[0]));//求出数组的大小,再除以每个元素大小是不是可以求出元素的个数。
~:二进制按位取反
int a=2;--->二进制位0000 0000 0000 0000 0000 0000 0000 0010
printf("%d",~a);打印出来会是多少呢这里,按位取反发现
a=~a;----->按位取反1111 1111 1111 1111 1111 1111 1111 1101
这里我们需要知道计算机的存储都是用补码存储的,而数据分为正数和负数,其中最高位表示符号位1代表负号,零代表正号,还需要知道正数的原码 反码补码都是一样的,而负数的原码 反码补码是不一样的原码符号位不动按位取反得到反码,反码加1得到补码。
这里~a的二进制是再计算机里存储的所以他本质是补码而要打印出来就必须是原码的形式输出的故需要讲补码转换位反码再转换到原码
~a补码 1111 1111 1111 1111 1111 1111 1111 1101
减去1(符号位不动)
~a反码1111 1111 1111 1111 1111 1111 1111 1100
取反(符号位不动)
~a原码1000 0000 0000 0000 0000 0000 0000 0011
这里算出应该输出位-3这里我们写入程序看看
#include<stdio.h>
int main()
{
int a=2;
printf("%d",~a);
return 0;
}
++ 有前置++,后置++
#include<stdio.h>
int main()
{
int a = 1;
int b;
b = a++;//后置++
printf("%d\n", b);
a = 1;
b = ++a;//前置++
printf("%d\n", b);
return 0;
}
这里我们发现(a初值始终是1)将a++(后置++)赋予b是打印是1,(a初值始终是1)将++a(前置++)赋予b发现打印出的是加1的值。这里将代码改下
#include<stdio.h>
int main()
{
int a = 1;
int b;
b = a++;//后置++
printf("%d %d\n", b,a);
a = 1;
b = ++a;//前置++
printf("%d %d\n", b,a);
return 0;
}
前置++:加好了用。后置++先用再加。 同样的--减减和++同理
(类型)强制类型转换
int a=3.14这样是错误的因为int是整型 而3.14是浮点型。int a=(int)3.14就可以将小数3.14强制转换成整型
、
关系操作符
> < = == !=
>:大于操作符
<:小于操作符
=赋值操作符
==等于操作符
!=不等于操作符
逻辑操作符
&&并且
| |或者
在C中真是非零,假是零,这里注意逻辑与&&和按位与&是不一样的:
#include<stdio.h>
int main()
{
int a=3;
int b=5;
int c=a&&b;//只有a和b同时是真那么c才是真
printf("%d\n",c);
return 0;
}
这里可以看出只有逻辑与只需要注意逻辑与两侧的真假即可两边都为真则真,也就是1。
同理逻辑或两个有一个为真,那就为真。
条件操作符
exp1?exp2:exp3(三目操作符)
exp1为真那么就exp2
exp2为假那么就exp3
比如 x>y?x:y可以理解为当满足x>y(真)为x,当x>y没有通过(假)为y
关键字
register:建议把什么定义成寄存器变量
int main()
{
register int a=10;//建议把a定义成寄存器变量
return 0;
}
struct
static :
1.static修饰局部变量:
#include<stdio.h>
void test()
{
int a=0;
a++;
printf("%d\n",a);
}
int main()
{
int i=1;
for(i=0;i<5;i++)
{
test();
}
return 0;
}
我们看见调试的结果是5五个1,原因i=0时,判断i<5进入for循环,调用一次test()函数打印一次a且a++后变成1故a为1,当跳出test()函数时a=1,也随之销毁。然后i++变成1再次进入循环,一下步骤一样。
那如果我们使永static会怎么样
#include<stdio.h>
void test()
{
static int a=0;
a++;
printf("%d\n",a);
}
int main()
{
int i=1;
for(i=0;i<5;i++)
{
test();
}
return 0;
}
发现调试的结果是1,2,3,4,5。这是为什么呢?
i=0,i<5进入循环调用test()函数,a++后a为1,输出1
i++变成1
i=1,i<5进入循环调用test()函数,a++后a为2,输出2
i++变成2
i=2,i<5进入循环调用test()函数,a++后a为3,输出3
i++变成3
i=3,i<5进入循环调用test()函数,a++后a为4,输出4
i++变成4
i=4,i<5进入循环调用test()函数,a++后a为5,输出5
i++变成5
结束循环。
static函数修饰局部变量后改变了其生命周期当变量出了其作用域也没有进行销毁
2.static修饰全局变量:
改变了变量的作用域,只能在自己所在的源文件内使用,出了源文件就没有办法再使用了
3.static修饰函数:
改变了函数的作用域,只能在自己所在的源文件内使用,出了源文件就没有办法再使用了
正常的函数是具有外部链接属性,也就是说函数在一个文件而另一个文件可以调用有函数的那个.C文件。但是static修饰函数后,改变了函数的链接属性,让他从外部链接属性变成了内部链接属性
typedef:类型定义--类型重定义
int main()
{
typedef unsigned int u_int;//将unsigned int定义为u_int
unsigned int num=20;
u_int num2=20;//u_int 和unsigned int一模一样
return 0;
}
#define定义常量和宏
1.#define定义常量
之前学过#define定义的标识符常量。比如圆周率为3.14
#define PAI 3.14
#include<stdio.h>
#define WWC 20
int main()
{
int arr[WWC];
return 0;
}
这个代码是没有人会问题的。
2.#define定义宏
在定义常量的基础上加了参数
#include<stdio.h>
#define MAX(X,Y)(X>Y?X:Y)
int main()
{
int a=2;
int b=8;
int max=MAX(2,8)
printf("%d\n",max);
return 0;
}
指针
指针说白了就是告诉你内存的房间号,好方便你去那个房间找东西呢?
由此就抛出了两个问题首先这个地址该怎么编,其次是空间多大比较合适。以32位的计算机为例,也就是32跟线那每根线都有两种状态,以二进制的形式这32位可以带表的状态有:
0000 0000 0000 0000 0000 0000 0000 0000 >>表示十进制0
0000 0000 0000 0000 0000 0000 0000 0001>>表示是进制1
…………………………………………………
1111 1111 1111 1111 1111 1111 1111 1111>>表示是进制2^32-1
也就是说或产生2^32种状态,那如果每个状态都表示一个地址的话,我们在内存开辟的一个个小房间就可以有对应的编号了
好了有了地址的编号?那我们每个编址对应的空间是多少呢?
如果每个空间都是一个bit,那2^32个地址就代表2^32bit——>2^32bit/8/1024/1024/1024=0.5GB如果一个地址为代表一个bit那内存只有0.5GB这也太小了把。
这里我们从不同角度来剖析看下,如果一个空间代表一位当我们存储一个整型变量是也就是这一个变量是不是要用去32个地址,这是不是有点太奢侈了就像是一瓶500ml的水就硬要用500个容积位1ml的容器来装。
那一个bit嫌小那一个地址大小为一个字节会如何我们0.5GB*8=4GB发现一个地址的空间可以放一个字节 存放字符型变量用一个地址,存放整型用四个地址,感觉还是很很合理。那我们看看一个地址对应的空间1kb会如何。发现这样会走进另外一个计算。综上所述一个地址所对应的空间为一个字节就很合适。
我们常向内存申请空间存放数据,那我们能知道这个存放空间的地址吗?如果知道了地址那能不能将这个地址也保存下来呢?这里我们写出代码并加以解释:
#include<stdio.h>
int main()
{
int a=10;//向内存申请四个字节存放10,既然有空间那必然有地址我们将地址打印下来
printf("%p\n",&a);//%p以十六进制输出地址 &a其中&为取地址操作符
int*p=&a;//int*表示的是p的数据类型是int*
printf("%p\n",p);
return 0;
}
存放地址的变量称之为指针变量那如何定义指针变量(类型*)变量名这里就是int*p其中int*是指针变量的类型 p为指针变量
这里还要注意&a表示取出a的地址称之为取地址操作符。
这里面的运行结果跟能说明变量p存放了地址所以p是指针变量。
那未来我们是不是可以通过指针变量里的地址来找到那个地址里面东西
*p对p进行解引用操作符,找到地址所指向的对象
#include<stdio.h>
int main()
{
int a = 10;//向内存申请四个字节存放10,既然有空间那必然有地址我们将地址打印下来
printf("%p\n",&a);//%p以十六进制输出地址 &a其中&为取地址操作符
int* p = &a;//int*表示的是p的数据类型是int*
printf("%p\n",p);
*p;
printf("%d %d\n",*p,a);
*p = 20;
printf("%d\n",*p);
printf("%d %d\n",*p,a);
return 0;
}
*p其实就是通过p里存放的地址——>找到了a——a=10
那么*p=20,就是通过p里存放的地址——>找到了a——>a=10——>将20赋值给a
在我们创建变量a时就会产生地址,我们把地址存入指针变量p(int*p)。而*p就是通过指针变量p找到a就是*p和变量a就是同一个。
结构体struct
struct Book
{
char name[20];//C语言程序设计
int price;//66元
};
int main()
{
struct Book s1={"C语言程序设计",66};
printf("%s %d\n"s1.name,s1.price);
b1.price=15;
printf("%s %d\n"s1.name,s1.price);
return 0;
}
结构体变量其实是描述复杂对象用的是我们自己设计的,这里面注意结构体变量是(变量名.成员名)
#include<stdio.h>
struct Book
{
char name[20];//C语言程序设计
int price;//100
};
int main()
{
struct Book b1 ={ "C语言程序设计",100 };
printf("书名:%s 价格%d\n", b1.name,b1.price);
//这里我们给b1进行了初始化肯定是向内存申请了空间那么一定是有指针的*p,且b1的类型是struct Book
struct Book*p=&b1;
printf("书名:%s 价格%d\n", (*p).name,(*p).price);//下面我们换一种写法
printf("书名:%s 价格%d\n", p->name ,p->price);
p->price = 200;
printf("修改后的价格:%d\n", b1.price);
}
这里也可以用指针变量来完成b1的类型是struct Book故指针变量定义成struct Book*p=b1
输出的时候我们可以先用解引用操作符*p然后加上其成员即(*p).name
或者p->name(指针变量所指向的对象)这样也十分好理解
结构体变量.成员
(*结构体指针).成员
结构体指针->成员