C语言学习笔记_第1页
C语言学习笔记_第2页
C语言学习笔记_第3页
C语言学习笔记_第4页
C语言学习笔记_第5页
已阅读5页,还剩28页未读, 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

知识点一标准输入输出函数

#include<stdio.h>

〃这是一个头文件,文件内部包含了很多C语言运行过程中必要的库函数头文件有很多

个,很多时候,调用的库函数都需要包含特定的头文件才能使用

//main函数为所有c语言程序的入口函数。就是说所有c语言的程序,都是从main函

数开始执行的,如果main函数不存在,在c语言的编译器在编译过程中就会报错

intmain(intargc.char**argv){

〃现在需要向标准输出流输出一个"helloworld"

〃想要完成这个操作,可以直接调用库函数printf来实现

printf(”helloworld'n")"\n为转义符,转义符并不会将他本身的样子打印到终端上

去,而是会将他转义之后所代表的内容打印到终端上去。退格键的转义符为\b,tab键的转义

符为\t

return0;

}

格式化字符串输出示例:

转换字符谕出示例

%dor%i有符号十进制整数printf("%d心%i意\n”,3,2);

%c单个字符printf("少林功夫好(y/n)~%c\n”,V);

%s字符串printf(“爱我的人%s,我爱的人%s\n”,"呵呵呵”,"老美了”);

%f浮点数,默认精确到6位小数printf(“圆周率:%.2f\nM,3.1415926);

%%打印一个百分号printf(”手游占中国网络游戏海外发行细分市场的65%%”);

转义序列小结:

转义序列名称描述

\a蜂鸣警报在一些系统中警报不起作用

\b退格将光标回退一格

\f换页将光标移到下一页的开始处

\n换行将光标移到下一行的开始处

\r回车将光标移到当前行的开始出

\t水平制表将光标移到下一个水平制表位置

\v垂直制表将光标移到下一个垂直制表位置

单引号

V用于打印单引号'双引号、问号'反斜

V双引号线等字符(由于这些字符用于定义字符

\?问号常量,是printf函数的一部分,若直接使

用会造成混乱)

w反斜线

变量的使用:

teinclude<stdio.h>

tntmain(tntargc.char**argv){

〃申请一个变量:根据需求,先写出变量的具体类型,然后在类型的后面跟上变量的名

字(注意要满足规则)

tnta=5;

tntb=10;

p「tntf(”a的值是:%d,b的值是:%d\n",a,b);

〃此处需要使用格式点位符:格式点位符能够取代一个变量所占据的位置,然后通过告

诉系统,当前时间我这个变量的具体是多少,最终将这个值赋值给格式点位符。

return0;

scanf函数的使用:

概述:

C函数库包含了多个输入函数,Scanf是最能用的一个,可以读取不同格式的数据

回基本用法

转换字符串含义

intnum;%d把输入解释成有符号整型

printf(“请输入数量:");%c把输入解释成字符型

scanf("%d",&num);

%s把输入解释成字符串

%f把输入解释成单精度浮点数

i、格式辛符串的用法巧P行nd函数次母%lf把输入解释成双精度浮点数

2、读取总本类型的点附,变詈甫裳加&将号)

说明:

।scant"%d-%d-%d",&a,&b,&c|;//&这个叫取地址符,其作

用为直接取到变量地址值

注意:当发生scanf调用的时候,scanf会做2件事情:

①scanf会跑到缓存区域去查看缓存区是否有数据,有则执行第二步;没有则会将系统

挂起,并等待用户输入数据,完成后继续第二步。

②scanf会读取缓存区最靠前的数据,如果能够被96d吸收则吸收,并将值赋值给变量,

如果不能吸收,则数据依旧在缓存区内部,则直接退出。

在输入函数scanf后可以使用循环while(getchar()!='\n')来清除缓存区域的回车符号。

回使用size。他算符可以获得数据类型占用内存空间的大小

使用O或Ox打印八进制或十六进制数。

intx=100:

printf("dec=%d:octal=%o:hex=?%x\n".x.x(x);

printf("dec=%d:octal=%#o:hex=%#x\n',x,x,x);

dec=100:octal=144:hex=64

0dec=100:octal=0144:hex=0x64

知识点二gcc编译过程

gcc编译过程,总共有4个阶段。

例如:现在要编译demo.c文件

1、预处理阶段

语法:gcc-Edemo.c-odemo.i

其中:-E:为gcc预处理指令,只做预处理,其他部分不做

-。:为将文件指定生成文件名

①去注释〃:为单行注释,仅对该行生效/**/多选注释,会将其包含的内容全部注释。

②头文件展开:

③宏替换:de行ne是傻瓜式替换,系统并不会对优先级进行处理。所以,当进行宏定义

的时候,如果该宏牵涉到优先级计算,用户需要自己通过小括号来标定优先级。

注意:typedef与#define的区别

#define在预处理阶段生效,它会直接执行简单的宏替换,将de币ne的内容替换成定义

的内容;而typedef在编译阶段生效,它的作用是将typedef的内容取一个别名,那么在编

译阶段,那个别名就会按照正确的名字进行编译。

#include<stdio.h>

#definex3+3

#definef(x)(x+x)

#defineINTint

typedefinttit;

intmain(intargc,char**argv){

INTa=3;

titb=5;

pctntf("你好,世界!\n");

printf("%d\n",f(5)*f(5));

return0;

)

④标记行号

注意:预处理只做以上部分,程序中如果有语法错误,并不会在预处理阶段体现出来。

2、编译阶段(整个编译过程的核心阶段)

语法:gcc-Sdemo,i-odemo.s

这个阶段会对待编译文件的词义,语义,语法进行分析,优化并确保正确。当以上所有

内容都正确时,生成$文件-汇编文件。

3、汇编阶段

语法:gcc-cdemo.s-odemo.o

将汇编语言,转换成计算机能够识别的二进制语言。

4、链接阶段

语法:gccdemo.o-odemo

链接动态库和静态库

将demo.o这个二进制文件使用-。参数指定生成名字为demo的可执行文件。

zhu@ubuntu:~/cyuyin/day2$gcc-EdemoZ.c-odemo2.i

zhuQubuntu:~/cyuytn/day2$gcc-Sde(no2.i-odemo2.s

zhu@ubuntu:~/cyuyin/day2$gcc-cdemo2.s-odemo2.o

zhu@ubuntu:~/cyuy3Mgg#$.95£心皆2.0de

注意:

使用gccdemo2.c-odem2生成指定文件名的可执行程序。

知识点三变量

1、变量:

在程序运行中,随时可能改变的量

在程序运行中,如果不使用变量来编程,那么每一次数值的改变,都需要重新修改程序

并编译。而使用变量的话,只需要对变量重新动态赋值,就可以达到目的。

名字:a大小:4空间上的值:5空间上的地址:OXfffOOl

____/1

地址由系统随机分配

___7

2、变量的类型

短整型short

C语言包含的数据类型如卜图所示:整整型int

型

‘数值类型《长整型long

单精度型float

浮点型

基本类型双精度型double

〔字符类型char

,数组

C<结构体struct

构造类型I共用体union

据、

类I枚举类型enum

型

指针类型

(空类型void

1)、整型:

①普通整型:int-2八31~2A31-1用%d进行格式占位,在32/64位系统中占据4个字节

大小

②长整型:long-2人63~2A63-1用%Id进行格式占位,在32/64位系统中占据8个字节

大小

③短整型:short-2^15-2^15-1用%d进行格式占位,在32/64位系统中占据2个字节

大小

#注意:1K=1O24BlB=8bit(位)

L计算机中,不存在减法操作,如果需要执行减法计算,则通过加上一个数的负数来

实现。

1计算机中所有的二进制数据都是补码的形式存在于计算机中:

什么是补码:

•源码:人为的从十进制转换成二进制的数。

•反码:在源码的基础,符号位不变,其它位取反。

•补码:在反码的基础上+1。

以上概念只针对负数,而正数的补码为源码本身。

sizeof():用来测量一个变量/一个数据类型在内存空间中占据的字节大小。

2)、字符型char使用虹来进行格式占位

字符型变量能够储存所有单个的数据,包含但不限于2~2人~乙0~9,!,?。由于有一些特殊

字符在程序中无法通过可视化操作来表示出来,所以我们人为的为所有字符编制了一个带有

序号的表格,这个表格就是ASCII码表

3)、浮点型:储存所有的小数数据

单精度浮点型-float,使用蜥进行格式占位,在内存占4个字节,最高位为符号,第2

到9位为指数位,10到32位为尾数位,float一般精确到小数位后6位,即保证6位有效。

双精度浮点型-double,使用%lf进行格式占位,在内存占8个字节,最高位为符号,第

2到12位为指数位,13到64位为尾数位。double类型一般精确到小数位后12位,即保证

12位有效。

注意:

①浮点型数据不涉及位运算。

②浮点型的数据不能直接进行大小的比较

我们可以使用%g来占位浮点型数据,这样只会打印出有效位。还可以使用%.nf来打印

小数点后n位数据,使用这种占位符打印的数据,在显示的时候会四舍五入(即数据本身没

有发生改变)。

9returnpswd-data>-0.0O0001|&&pswd-

data<0.000001"/这才是一个double数据代表==0的正确表述方式

4)、空类型void

5)、自定义类型

6)、指针类型

指针是一个值为内存地址的变量(或数据对象)。正如char■类型变量的值是字符,int类

型的变量的值是整数,指针变量的值地址。在C语言中,指针有许多用法。要创建指针变

量,先要声明指针变量的类型。

3、变量命名规则

i.禁止数字开头命名变量(语法上的禁止)

ii.禁止以系统关键字命名变量(语法上的禁止)

iii.变量的名字需要有其意义

当一个变量的意义有多重修饰时,可以采用以下两种规则命名:

•下划线命名法:

•驼峰命名法

•匈牙利命名法

•帕斯卡命名法

知识点四运算符

1、算术运算符%

/:除数不能为0;

%:对除法操作结果取余数,两个数据不能为浮点型,如果需要对浮点型数据进行取余操

作,可以对原数据进行强制类型转换,将两个double类型的数据(在运算过程中)转换

成int类型。

强制类型转换(int)a(目标类型)变量

2、赋值运算符:=,+=,-=,/=,*=……

例如:a=a+b;代表将b+c的运算结果赋值给a。'=’会将等号的右值赋值给左值。

a-=b;等价于a=a-b代表将a-b的运算结果赋值给a。

赋值运算符的优先级非常的低。所以当有赋值运算符存在的时候,都是先计算右值,再

赋值给左值的。

3、比较运算符:>,<,>=,<=,==,!=

正如之前所说,每一个表达式,都会产生一个计算结果。如果表达式成立的计算结果为

1(也就是真),不成立的计算结果为0(也就是假)。

4、单目运算符(自增运算符)++,一

如果对inta=0进行自增操作,有收下两种方式

a++==a+=l==a=a+l后加加:先赋值,后运算(这里所谓的赋值对象,

为a++这个表达式本身,先将a=0的值赋值给a++,然后再执行自增操作,得到a=l.)

++a==a+=l==a=a+l前加加:先运算,后赋值(先将a=0进行自增运算,

再将得到的a=l的结果赋值给++a表达式本身)

注意:无论是使用a++不是++a,a的值都会自增1。

5、逻辑运算符:&&.||.!(与,或,非),

对于逻辑与(&&),当参数两者都是真的时候,表达式结果为真;其它情况为假。

对于逻辑或(||),当参数两者任意一个为真的时候,表达式结果为真,其它情况为假,

(有一真,则为真)。

对于逻辑非(!),真则为假,假则为真。

当三个变量进行大小比较的时候:

6、三目运算符

用来计算两个数据之中较大/较小的数量哪一个。即,计算完成后,整个表达式的计算结

果应该是进行比较的两个数其中之一。

例如:inta=2,b=3;intbigger=0;bigger=(a>b)?a:b;

括号内结果为逻辑真假,?可以理解成是否成立。如果括号逻辑为真,则整个表达式

取‘:’的左值,反之则取右值。

7、位运算符:位运算符都是针对二进制数进行位运算

①按位与-&:都为1,则为1,其它情况为0

②按位或-I:有1为1,全0为0。

③按位取反一:1为0,。为1;

④按位异或-人:相同为0,不同为1.

inta=10;

intb=8;a和b可以是相等的,但是

a—3AR•

b=a^b;他们却不能是同一个个体

a=aAb;

⑤左移<<

右移>>

a&=~(l<<n),将a从右往左数,第n+1盏灯关闭。

a|=(l«n),将a从右往左数,第n+1盏灯打开。

知识点五语法结构

[、顺序结构

代码从上到下,从左到右依次执行。

2、分支结构

代码根据给定的条件,直接跳转到与条件相符合的分支中,继续执行。

①判断语句-if语句

讲法格式:if(逻辑){

语句;

}

如果“逻辑”为真,则执行“语句”,逻辑不成文则跳过整个if语句,继续执行if语句

之后的代码。

②二选一选择语句:if(逻辑){语句1;}else{语句2;}

如果“逻辑”为真,贝IJ执行“语句r,逻辑为假则执行“语句2”,完成后继续执行选

择语句后面的代码。

③多选一选择语句:if(逻辑1){语句1;}elseif(逻辑2){语句2;}……elseif(逻辑n){语句

n;}else{语句0;}

系统会从“逻辑V开始,逐条向下执行代码,直到找到某一个逻辑为真,则直接执行

该逻辑对应的语句,剩余的逻辑不再判断。如果说多选一语句中存在复数个正确的逻辑,系

统只会执行每一个正确的逻辑对应的语句。如果所有逻辑都为假,直接执行“语句0”。

Switchcase语句:

语法:

switch(表达式){

case常量1:

语句1;

break;

case常量2:

语句2;

break;

case常量n:

语句n;

break;

default:

语句0;

break;

}

解释:“表达式”可以是一个变量,可以是一个算数表达式,可以是拥有返回值的函数。

这个“表达式”不管存放什么形式的数据,最终必须导出一个结果,这片结果可以是任意的

数据类型。通常情况下,一般都是整型变量或者字符型变量。

当“表达式”的值与某一个case后面常量相等时,则直接跳转到该case分支中,执行

对应的语句,其它case中语句不再执行。

如果有多个case满足条件,则只会执行第一个满足条件的case语句。

如果没有case满足条件,则跳转到default执行“语句0”(default)

注意:

Lswitch-case语句,只负责跳转进入,不负责跳出。跳出功能由break负责。

』switch-case语句中,case分支中不能申请变量。

,break语句只能跳出分支与循环结构。

3、循环结构

代码根据给定的条件是否成立,如果条件成立执行循环体内部的语句,如果条件不成立,

执行循环体外部语句。

循环三要素:①循环条件,②循环变量的初始化,③循环变量的改变方式

注意:

/循环条件必须与一个变量挂钩,否则循环条件不变的话,要么无限循环,要么从不

循环。

/循环条件必须随着每一次循环进行改变,来保证第一次循环都可能结束循环。

/循环旨在用来解决一些重复操作的计算,使得代码的重复率降低,提高编程效率。

/当程序本身不确定某一个计算具体要执行多少次的时候,但是却又明确程序循环退

出点在哪。此时,就可以使用循环来解决问题。

1)、for循环语句

语法:for(表达式1;表达式2;表达式3){语句1}

释义:

“表达式r是循环变量的初始化,也就是循环变量从哪一个点开始做改变。

“表达式2”循环条件,满足该条件,则进入循环,执行语句1。直到某次循环的时候,

条件不满足,则退出循环。

“表达式3”循环变量的改变方式,

注意:如果循环中,嵌套了一个判断语句,判断语句中存在一个break,如果执行该break,

无法当前循环条件是否满足,都会直接退出循环。

如果循环语句没有那么在循环体后紧跟着的1条代码,属于这个循环体。if语句

同理。

2)、while循环语句

语法:while(逻辑判断){语句};

解释:当“逻辑判断”为真时,则会执行循环体“语句”,直到'‘逻辑判断”为假。

这里的循环准备条件需要写在while语句之前,不能像for语句一样可以直接写for里

面。

注意:

循环变量的改变方式注意一定写在“语句内部”

3)、dowhile循环语句

语法:d。{语句;}while(逻辑判断)

解释:先执行一次“语句”,再进行“逻辑判断”,“逻辑判断”如果为真,则会循环执

行“语句”,直到“逻辑判断”主假。

dowhile和while的最大区别在于,dowhile不管逻辑是否为真,至少执行一次循环语

句。

d。while一般使用的环境:在项目中,可能存在这样的边界条件,使得第一次循环可能

不满足循环条件,但是之后的所有循环直到结束为止都是满足条件。此时如果使用while循

环,就不会进入循环。可以使用dowhile来解决这种问题。

continue关键字:可能使用在循环语句当中。

解释:当循环过程中,遇到continue关键字,则会直接结束本次循环,开始下一次循环

(也就是说,一旦遇到continue,那么continue之后所有循环体代码不再执行,重新从循

环的开关开始执行。)

变量的作用域以及生命周期:

i.生命同期范围,通常都在一个“0”内八

ii.当一个变量生命周期结束后,则无法再访问该变量。

iii.在相同作用域内,变量名不能重复。但是在不同作用域内,变量名允许重复。遇到

这种情况,系统会访问最近的作用域内的变量(就近原则)。

随机函数的使用:

①把相关的函数引用

#include<time.h>^n#include<stdlib.h>

②产生时间因子:Srand(time(O))

③产生一定范围内随机数

inta=rand()%99+l;由于rand会产生非常大的一个随机数,不能保证它的范围在

1~99之间,所以可以直接对该随机数取余99,那么结果就是0~98之间的数,再+1之

后,结题就是1~99之间的数了。

gdb调试工具:

1)、一个调试C语言的工具。当程序逻辑正确,没有错误时,则gdb会直接运行

完成程序。当程序中存在逻辑错误会导致程序运行中断,则使用gdb运行程序的时候,

gdb会记录程序中断点并停留。

2)、如何使用gdb来调试一个C语言程序?

必须生成一个可调试的可执行文件。使用指令:gcc文件名-g(参数)来生成一个

可调试可执行文件(a.out)。

使用gdb打开该可执行文件:gdb./a/out

3)、gdb中的调试指令:

①r-开始运行程序。

②b行号/函数名:将程序停止在相对应的行号或者函数处。如果说,有多个.c文

件参与编译,那么断点的格式为:b文件名:行数/函数名

③P:可以使用p+变量名来打印当前变量的值。

④n:使代码向下执行一行。

⑤c:全速执行剩余的代码。

⑥q:退出gdb调试

⑦s:进入函数内部查看函数逻辑

⑧I:查看当前行周围的代码

gdb调试的编译选项gdb调试流程

/调试命令:

gcc(-g1其它选项][文件名]K/^list):杳看所载入的文件

I4(break):设置断点,程序运行

7\,到断点即可停止

J:infob:查看设置的断点情况

</r(run):从第一行开始运行代码,

调试的是Q.或者指定行开始,可在r后面加

@我行史而不是源代码))上行号

玄枳演文件进行编译pn:查看变量n的值

一定要加上选项”-g”,这n(next):单步运行下一行代码(遇

样编译出I制的赤四即执行文件才GDB到函数不会进入函数)

TheGNUProject

包醯画1塾Debuggers(step):单步运行下一行代码(遇

到函数会进入函数)

c(continue):恢复程序的运行,

执行剩余的程序

知识点六函数

1、函数的使用目的:

当我将某一个功能封装成一个函数的时候,那么我修改该功能的时候,只需要修改该函

数。如果程序中,该功能出现若干次,那么我只要修改一次函数,所有功能实现处都会改变。

即,函数提高了我的代码的重构效率,指提高了工作效率。提高了代码的重用性。

注:函数中功能的覆盖性可以广泛。但是函数的功能越单一越好。举例说明:一个函数,

如果是用来验证是否为质数,那么只验证是否为质数,不输出。

2、函数的定义:将某一个特定的功能,打包封装后,称为函数。那么在该函数外部,

如果需要实现这个特定功能,只需要调用封装好的函数即可。

3、函数的三要素:、

①函数名:

一个函数的名字,注意,在C语言中,函数名绝对不能重复。

②函数返回值类型:

什么叫函数的返回值:如同所有的表达式都会得到一个运算结果。那么对于函数,

当发生调用函数时,调用函数的语句就是一个表达式,这个表达式得到的运算结果,仅仅取

决于函数的返回值(如果我们想将一个特定的值给到函数表达式本身。那么只要在return后

面写上该特定值,当函数调用完成后,函数表达式本身的值就是该特定值)。

③函数的参数列表:

一个函数在运算过程中,如果需要使用外部的变量,则可能通过参数列表的形式,来得

到这个外部变量的值。

注意:

①函数定义的时候,参数列表称为形参。

②函数调用的时候,参数列表称为实参。

③发生函数调用的时候,会将实参的值赋值给形参。

④函数调用完成时,形参并不会赋值给实参。而是会将返回值赋值给函数表达式本身

⑤可变参数函数:参数的数量根据实际需求,动态改变。

但是注意:无论怎么改变,必须有一个固定参数(第一个参数)。

linclude<stdarg.h>〃可变参数的相关头文

voidshow_array(constdouble

double*new_d__array(intn,

intmain()

double*Pl;

double*P2;

Plnewd_array(5Z1.2,2.3,3.4,4.5,5.6);

P2new_d_array(4,100.Oz20.00,8.08,-1890.0);

show_array(pl,

show__array(p2,笨、函数调用时,必须指明参数个数,即第

free(pl);参数要写明

free(p2);

return0;

voidshow_array(constdoublear[]rintn)

(-

double*new_d_array(intn,...)

va_listap;〃声明对象来保存参数

int1;

double*pt;

va_start(ap,n);〃把ap初始化为一个参数列表

pt=(double*)malloc(n*sizeof(double));

for(i=0;i<n;i++)

pt[i]=va_arg(aprdouble);〃访问参数列表中的每个

va_end(ap);

可变参数的函数使用:1

关闭回显system("sty-echo");〃函数会将输入的字符在终端上执行。

打开回显system("sttyecho");

使用system函数时需要使用#include<stdlib.h>

4、递归函数

函数自己调用自己

递归函数的3要素:

A自己调用自己

上要有明确的退出点,否则就会造成栈溢出

1每一次递归,必须逐渐趋近于递归退出点。

递归的思想:在某些复杂的问题中,我们并不知道这个问题的解是多少。此时可以将该

问题分解成逻辑相似的简单问题去解决。如果这个简单的问题依旧无法解决,继续分解。当

分散到最低层的时候,我们需要给最低层问题一个确切的解。此时由于最低层已经解决,那

么依赖于低层问题的上一层问题也能解决,依次逐层向上解决,直到解决最高层问题为止。

注意在递归函数中,严禁使用static.如果递归函数中使用static变量来完成逻辑计算,

那么当你第一次递归函数的时候,能够算出正确的结果。但是当第二次调用这个递归函数的

时候,结果肯定是错误的。

递归和循环的区别:

循环在时间复杂度上会很高,但是其空间复杂度一定会很低。

递归在空间复杂度上会很高,但是其在时间复杂度上不一定会低。当设计合理时,递归

的时间复杂度会非常非常的低。

对一个地址(一个十六进制的数)前面加上代表着系统会跑到该地址上,将该地

址值上的值取出来使用。

例如:0x01上保存的值为2

此时,我有一个地址变量p==0x01

那么,此时,*p==2;

printf("%.*lf\n",nzres);

程序的分文件:

第一步,编写相关头文件(.h)

示例代码:

#ifndcf_hcad_h

#define_head_h

#include<stdio.h>

intadd(inta4ntb);〃函数原型

#endif

第二步,在主文件中包含相关自定义的头文件(main所在函数中)

#inelude"hcad.h"

第三步,编写函数实现文件(.C)

#includc"hcad.h"

intadd(intajntb){retruna+b;}

知识点七硬件

lx内存(ram)

a)掉电则数据丢失

b)读取速度很快

c)随机访问:申请内存的时候随机申请内存空间;访问内存的时候,直接访问。

2、硬盘(rom)

a)掉电数据不会丢失

b)访问速度慢于内存

c)模块化访问

3、内存空间的分类

a)栈内存空间:

①linux系统栈空间默认大小10mb(我们的ubuntu默认的栈空间大小大概在2m左右),

②栈内存空间都是先进后出的。

③栈内存中保存的变量都叫自动变量,自动变量的特点,申明时,自动申请内存空间,

结束时自动释放内存空间。(申请空间代表用户向系统申请一片内存空间的使用权限。释放

空间代表系统回收了该内存空间的使用权限。)

④绝大多数的栈内存都是从高地址向低地址生长,这就是意味着先申请的数据,会存放

在高地址,后申请的会在低地址。无论是向你低地址生长,还是向高地址生长,系统都会满

足用户的一般逻辑思维。就是说,在申请某些数据结构的时候(可以存放复数数据的结构),

写在前面的数据总归在低地址。

注意:

L根据栈特性,我们可以认为自动变量就是局部变量。

2.严禁在函数内部返回一个局部变量的地址。

局部变量属于函数内部,不属于main函数,当函数调用完毕,局部变量被系统回收,

该地址使用权不属于用户,而主函数内部却可以通过地址的方式直接访问到该地址,这就变

成了一个非法操作。所以系统会提示警告。在编程过程中,需要尽量避免出现这种情况。

3.针对以上情况,存在着一种情况,可以向外返回一个局部变量的地址,并且运行不报

错。那就是栈内存入侵。

b)堆内存空间

堆内存空间上的数据都是由用户手动申请空间,并且手动释放。(只要申请了不释放,

那么在哪里申请,怎么返回都是合法的。)

调用函数时,在函数中定义的变量是在堆内存中

c)静态存储区

静态存储区中,存放了静态变量,静态存储区存在于整个程序的运行过程之中。

static关键字,能够修饰局部变量和全局变量,

static修饰局部变量的时候,会将该变量存储到静态存储区内去。达到延长生命周期的效果。

注意:

static仅仅延长了变量的生命周期,并没有扩展变量的作用域。

extern:可以引用外部全局变量

当static修饰全局变量的时候:限制作用域,此时这个全局变量的作用域被限制在当前

文件内。

d)常量存储区

主的数中a的内存管理

:dd函数中,形参a的严存管理主函数中a的内存管理ad函数中a的内存管

名:a名:a

名:&a名:a

大小:4大小:4

大小:8大小:8im*类型

值:2值:2

值:0x01值:0x01

地址:

0x01侬止:0x02地址:0x10

*a(*0xuI)=2

用了一个不属于我的地址

本书设定编译器中(limits.h>的内容如代码清单7-1所示.

代码清单7-1

ttdefineUCHARMAX255U*unsignedchar

WdefineSCHAR_MIN-128*signedchar'jit

^defineSCHAR二MAX+127*signedcharIjh

"defineCHAR_MIN0*char-J/ti,pl'-;•

^defineCHAR^MAXUCHAR_MAX♦charTj/ii).(■[•

^defineSHRTMIN-32768*shortint二小」,

*defineSHRTMAX+32767*shortint。派人•

^defineUSHRT_MAX65535U•unsignedshort

ttdefineINT__MIN-32768•int!';/d•

^defineINT_MAX+32767♦int!;公大々*

*defineUINT_MAX65535U*unsignedint/:公,•

♦defineLONG-MIN-2147483648L*longint♦

^defineLONG二MAX+2147483647L*longintifjM,舟•

^defineULONG_MAX4294967295UL•unsignedlong:;

知识点八数组

1)、数组:是一个能够存放若干个相同数据类型的数据结构

注意:在声明数组的时候,想要往数组内存放什么数据类型,那么就必须给这个数组声

明成对应的数据类型。

2)、数据的声明及定义:

数组的数据类型+数组名[数组的容量尸{实际数据(每一个实际数据使用‘,‘分隔开小

示例:

①:intarr[5]={0,1,2,3,4};

②:intarr[5]={4};将数组中的第0个元素初始化为4,其它元素初始化成0;

③:intarr[5]={0};将数组中的所有元素初始化成0;

注意:

①在声明数组的时候,可以不规定数组长度,但是必须初始化数据。如:intarr[]={(),

1,2,3,4};因为系统在运行到数组声明部分时,必须向内存空间申请一片固定大小的内存。那

么数据的声明部分没有给到系统数组的大小是多少,那么系统就会去数组的定义部分,查找

数组的实际的长度,用来向系统申请空间大小。

所以说,系统会优先查看数组声明部分的容量,再去查看数组实际定义的长度来申请内

存空间。如果声明和定义都没有约定数组的容量,那么导致编译报错。

②当数组的容量使用一个变量去声明的时候,则此时不能定义数组。因为变量的值可能

发生改变,当数组使用变量去声明长的时候,系统肯定不会知道数组的确切长度是多少,此

时如果给该数组做了明确的定义,可能导致定义的长度比实际数组容量要大。所以系统禁止

使用变量声明容量的时候同时去定义该数组。

3)、数组的访问

数组名[数组元素位置];

示例:

有一个数组intarr[5]={0,1,2,3,4};如要访问第1个元素和第2个元素,使其相加,导出

结果:arr[l]+arr[2]==3(数组的下标是从。开始计算的);

4)、访问整个数据结构

访问整个数据结构这个思想,在所有数据结构中都是通用的,并且是所有功能的基础。

我们把访问整个数据结构的过程称作:遍历——对一个数据结构中的所有数据,全都并

且仅访问一次。

所有数据结构都会面临如下课题:

数据结构的增、删、改、查、排、遍历

数组名本身是一个地址,这个地址和该数组首元素的地址是一样的。

SLEEP(3)LinuxProgrammer^Manual

NAME

sleep-sleepforthespecifiednumberofseconds

SYNOPSIS・一

/Include<unistd.h>

unsignedtntsleep(unstgnedtntseconds);

DESCRIPTION

4)、二维数组

intarr[m][n];表示二维数组有n列m行即由m个有n个元素的一维数组组

成。示例:intarr[2][3]={{l,2,3},{4,5,6}};

逗号运算符:可以用来将一个表达式隔开成若干个表达式,使得每一个表达式独立运算,

但是整个表达式的值取最末尾表达式的值。

5)、数组的排序:

①冒泡排序:逻辑最简单,代码也最简单,但是时间复杂度最高(效率最低)。

使用比较运算符,当发现两者之间的最大值出现,就立即进行换位。

②选择排序:比冒泡难一点,但是效率高。

使用比较运算符,查找出第一位置的元素并记录好下标,当遍历完毕后再把找到的元素

进行换位。

③快速排序:代码难度最为高的一种排序方式,但是效率非常高。

6)、字符数组

字符数组能够和整形数组一样的使用方式,但是字符数组有其特殊的使用方式。

6.1字符数组的声明及定义:

①如同其它数组一样定义:

charstr[20]={'h'e'1'1'o'};

②字符数组特有的定义方式:

charstr[20]=whellow;

6.2字符数组的使用:

①如同整型数组一样输入输出

charstr[20]={'h'e'/TTo'};

fbr(inti=0;i<5;i++)

{scanf(“%c",&strR]);printf("%c”,str[i]);}

②字符数组特有的输入输出

charstr[20]={0};

scanf(a%sw,str);//scnaf中%(1要求是int*类型,%c要求的是char*类型,%s要求的是

char*类型,

printf("%s\n",str);〃scnaf中%(1要求是int类型,%c要求的是char类型,%s要求的是

char类型,

注意:在字符数组中,系统默认会在每一个字符数组/字符串的结尾位置,加上结束

符'\0'(也就是空字符)。

由于以上特性,我们在设计字符数组的时候,最大容量最低要求要比实际长度多1.

6.3字符数组的函数:#include<string.h>

①strlen,用来测量一个字符数组的实际长度,

参数列表:目标字符数组

返回值:返回字符串的长度。

②strcpy(sl,s2);,用来实现字符数组的拷贝,

功能:复制字符串s2到字符串slo是字符数组/字符串之间唯一的相互赋值的方法。

使用该函数的时候,目标字符数组尽量比源字符的容量要大。

③strcmp(s1,$2);

如果si和s2是相同的,则返回0;如果sl<s2则返回小于0;如果sl>s2则返回大

于0o是比较ascii的值。返回的是两者的差值

④strcat,用来拼接两个字符数组/I个字符数组和1个字符串

参数列表:字符数组1,字符数组2/字符串

返回值:将更新后的"字符数组1”返回

⑤strtok用来分隔字符串

参数列表:待分隔的字符串,分隔字符串

返回值:分隔后取出来的第一个字符串;

⑥mcmcpy用法:

参数列表:目标指针,源指针,需要复制的数量

函数功能:将源指针上的内容,复制到目标指针指向内存空间上,复制的内存空间

大小,为第三个参数。

返回值:将更新后的目标指针返回。

知识点九指针

1、指针的概念:

指针的全称:指针变量(相对应的有指针常量。),是一个变量,该变量可以用来保存一

个数据。保存的数据是一个十六进制的地址,给一个指针进行赋值操作的时候,称为“指向”O

2、定义及声明:

①一个完整的指针定义方式:

变量类型+“*”+变量名

②指针变量的大小:

一个指针在32位系统中,占4个字节大小,在64位系统中,占8个字节大小。

3、指针的取值操作:*

对一个地址进行取取*操作,就会直接取到该地址空间上的值。

同理,对一个指向一片地址空间的指针进行取*操作,同样会取到那片地址空间上的值。

使用指针是特别注意,一个指针指向的数据是哪一个数据,以及一个指针取*后是哪一

个数据。

4、指针变量的类型:

所有数据类型,都可以变成该数据类型的指针。

♦int*代表int类型的指针

♦char*代表char类型的指针

♦int**代表int*类型的指针

♦void*代表通用指针

通用指针可以作为左值接受任何类型的指针数据。但是通用指针有一个缺点:它不可以

直接取值。通用指针保存的数据,系统并不会知道这个数据具体是什么数据类型,所以带该

地址进行取*操作的话,系统不知道需要分配多少缓存空间。所以,在对void*通用指针进行

取*之间,需要对该通用指针明确数据类型。

对一个通用指针明确数据类型:强制类型转换。

void*不代表空指针,而代表通用指针,将指针设置为空指针应用NULL来代表,或者用

0。

*((int*)pl));

5、指针与函数的关系:

①函数参数使用指针传参的形式:将地址传给函数内部,函数外部与函数内部变量同步

发生改变。

但是依旧会发生实参给形参赋值的操作:这个操作代表了形参保存了实参的值,由于实

参是一个变量的地址,所以形参实际上保存的就是该变量的地址。所以在函数内部对该地

址进行改变的地里,实参也在改变。

②函数名本身也是一个指针,它不能作为左值,只能作为右值。

函数指针可以用来接受一个函数名,接受之后,调用这个指针,就相当于在调用该函数。

函数指针声明方式:指向函数的返回值类型+指针变量+(指向的函数的参数列表的具

体格式);

double(*cal[5])(void*,void*)={add,pos,mul,div,mod};

6、指针与数组的关系:

数组名本身就是一个指针,但是需要注意的是,数组名这个指针不能作为左值去指向其

它地方,它只能作为右值给其它指针赋值。数组名这个指针是一个常量。

指针的偏移:

通过对已知的指针进行+或-操作,来实现访问到与已知指针相关的其它内存空间。

指针偏移的量(即一个指针+1后,地址增加的绝对值):它根据数据类型的大小模块化

偏移。

数组名指向数组首元素的地址。

一个用来存放指针的数组,称为指针数组。那么一个用来指向数组的指针,就称为数组

指针。我们严格意义上说的数组指针,它是一个指向二维数组的指针。

intarr2[2][3]={

{1,2,3}.

{4,5,6}

};

/*申请一个指针指向该数组*/

int(*pl)[3]=arr2;

二维数组和指针数组的区别:

指针小结:

1.指针是一个变量,

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论