C语言学习资料.docx
《C语言学习资料.docx》由会员分享,可在线阅读,更多相关《C语言学习资料.docx(28页珍藏版)》请在冰豆网上搜索。
C语言学习资料
C语言程序设计
数据类型/运算符/表达式
1、基本类型:
1.1整形(int\4、shortint\2、longint\4/unsigned、signed)
1.2字符型(-128~127)
1.3浮点型(单、双)
float\4:
(有效位数6~7)f=123.4f;
double\8(小数默认):
(有效位数15~16)
longdouble\16:
(有效位数18~19)
字符串:
'\0'字符系统自动加上。
1.4枚举类型
2、构造型:
2.1数组类型
2.2结构体类型
2.3共用体类型
3、指针类型:
4、空类型:
常量:
在程序运行中,其值不能被改变;
变量:
初始化与赋值(c语言无明显差异、c++有明显差异)
表达式(与语句区分):
i=j=2;//表示将j=2的结果赋给i;
5%+/-7=5;-5%+/-7=-5;
运算符:
初等运算符:
单目运算符:
算数运算符:
关系运算符:
(<><=>=高)(==!
=低)
逻辑运算符:
(!
(单目运算符高)->&&->||)
a&&b&&c//先判断a,若a不为0,才判断后面;
a||b||c//先判断a,若a不为1,才判断后面;
条件运算符:
赋值运算符:
逗号运算符:
i=1,2,3,4,5;//结果表达式的结果为5;
i=(1+2,2,3,4,5);//结果表达式的结果为5,i=5;
强制转换符:
(类型)(表达式/变量)
符号扩展:
最高位0,全补0;最高位1,全补1;
各类数据混合运算:
由高到低(char->int->unsigned->long\float->double)
标示符
存储方式
大端模式:
字数据的高字节存储在低地址中,而字数据的低字节则存放
在高地址中。
小端模式:
字数据的高字节存储在高地址中,而字数据的低字节则存放
在低地址中。
visualc++小端模式
关键字
sizeof(关键字不是函数)sizeof(int);sizeof(i);
sizeofi;//正确,等价
sizeofint;//错误
doublea[10]={1,2,3,4,5,6,7,8,9,0},*p=NULL;
sizeof(a)=80;sizeof(a[100])=8;sizeof(p)=4;
sizeof(&a)=80;sizeof(&a[0])=4;sizeof(*p)=8;
sizeof(int)*p):
bool变量与“零值”比较
boolbTestFlag=False;
if(bTestFlag);if(!
bTestFlag);
float变量与“零值”比较
flaotfTestVal=0.0;
flaoteps=e-6;
if((fTestVal>=-eps)&&(fTestVal<=eps));
指针变量与“零值”比较
int*p=NULL;
if(NULL==P);if(NULL!
=P);
case后面只能是整形或字符型的常量或常量表达式;
constint*p;//p可变,p指向的对象不可变
intconst*p;//p可变,p指向的对象不可变
int*constp;//p不可变,p指向的对象可变
constint*constp;//指针p和p指向的对象都不可变
先忽略类型名(编译器解析的时候也是忽略类型名),我们看const离哪个近。
“近水楼台先得月”,离谁近就修饰谁。
constinta=10;//一般不能改a的值,但可通过指针改变;
int*p=(int*)&a;*p=90;b=a;=>b=90;//C++中不能改;
union型数据所占的空间等于其最大的成员所占的空间。
对union型的成员的存取都是相对于该联合体基地址的偏移量为0处开始,也就是联合体的访问不论对哪个变量的存取都是从union的首地址位置开始。
大小端模式对union的影响:
typedef的真正意思是给一个已经存在的数据类型(注意:
是类型不是变量)取一个别名,而非定义一个新的数据类型。
枚举与#define宏的区别:
1),#define宏常量是在预编译阶段进行简单替换。
枚举常量则是在编译的时候确定其值。
2),一般在编译器里,可以调试枚举常量,但是不能调试宏常量。
3),枚举可以一次定义大量相关的常量,而#define宏一次只能定义一个。
typedef与#define的区别
typedefintINT2011;unsignedINT2011i;//错误,typedef不支类型扩
展,define可以用;
#defineaint[10]与typedefinta[10];
volatile
C程序
n个源程序文件(预处理命令、数据声明、n个函数)
函数:
函数首部、函数体(数据声明、执行语句)
形式:
顺序程序设计、选择程序设计(if\switch\?
:
)、
循环(for\while\goto)
c语句:
控制语句(if、for、while、goto、switch、continue、break、return)
函数调用语句printf.
表达式语句a=2;
符合语句{..}
空语句;
输入输出函数:
#include
(putchar、
getchar:
'\n'结束标志/EOF(window(ctrl+Z)/Linux(ctrl+D))
printf、scanf、
puts、gets(字符数组名):
'\0')
输入缓冲区
输入输出格式:
printf(l,m,n,-)
%d%+/-md%0nd%ld%o%x\X%u
%c%s%+/-m.ns%ms
%f%e\E%+/-m.ne%g\G
97%%//输出97%;
scanf(l,h,*,域宽//%d%d空格、Enter、Tab//字符Enter、Tab、%5c)
?
//scanf("%s%c",a,&b);
inti=08;(错误)以"0"开头,八进制;”x”,十六进制;
字符函数:
#include
strcat(字符数组1,字符数组2);
//连接后存入字符数组1,原字符数组1后'\0'取消;
只在新符数组1最后中保留;
strcpy(字符数组1,字符数组2)//2->1;
charstr1[10]="hello!
",str2[20]="2008ok!
";intn;
strcpy(str1,"china"+2);=>str1=i;
strncpy(str1,str2,5);=>str1="2008!
";
strcmp(字符串1,字符串2)//比较字符串大小;
strlen(字符数组)//字符长度,实际长度;
n=strlen(str1);=>n=6;
n=sizeof(str1);=>n=10;
strlwr(字符串);//小写;
strupr(字符串);//大写;
memcpy(b,a,sizeof(a));//将数组a中的元素拷贝数组b中;
p=strtok(str,st);//str[]=”youareok!
”;st[]=”\n,\0,\t..”;
char*p;
while(p){puts(p);p=strtok(NULL,st);}
*a与b互换
1)、a=a+b;b=a-b;a=a-b;
2)、a=a^b;b=b^a;a=a^b;
*Pi/4=1-1/3+1/5-1/7+...
数组
inta[10]={0};//所有元素为0;
chara[10]={'\0'};//所有元素为'\0';
chara[10]={'c','p','u'};//其元素余'\0';
字符串在内存中自动加'\0';
chara[]="hello";//长度为6,不为5;
chara[]={'h','e','l','l','o','\0'};//长度为6,与上等价;
chara[]={'h','e','l','l','o'};//长度为5,与上不等价;
根据需要最后是否加'\0';
例:
charc[]={"helloworld!
"};想用ok!
取代;
若不加'\0',就是ok!
loworld!
c语言只能逐一引用数组元素;
数组名[常量表达式];
inta[3][4]={{1}{0,1}{0,0,1}};//其元素余为0;
a[3][4][5]
函数
定义函数时不指定函数类型,系统会隐含指定函数类型为int型;
C语言,实参向形参的数据传递是“值传递”,单向传递,只能实参传形参;
P=f(i,++i);//自右向左(一般);
C语言不能嵌套定义,可嵌套调用;
保护现场,恢复现场;
voidf1(inta)
{
Printf(“%-8d”,a);f(a+1);
}
Voidmain()
{
f
(1);
}
数组形参:
inta[][4];inta[3][4];
局部变量:
全局变量:
变量的存储类型:
程序区(代码段)、静态存储区(数据段/全局数据区)、
动态存储区(栈区)、自由存储区(堆区)
字符串常量区
数据类型
数据的存储类别(静态存储类、动态存储类)
auto
staticintc;未赋初值(未模式清零或空字符)//只能本文件使用;
//static修饰的变量总是放在内存的静态存储区,即使函数
调用结束,这个静态变量的指不能被销毁;
还可用以修饰函数;
register(本函数有效)//存取速度比内存快的多,register变量必须是
一个单个的值,并且其长度小于等于整型的长度,而且其变量
可能不放在内存中,所以不能用“&”来获取register变量的
地址;
extern//staticinti=0;(无法用extern外部链接)
内部函数
staticintfun(inta,intb);//只能限于本文件;
外部函数externintfun(inta,intb);
时间函数:
#include
标准库函数:
#include
itoa(3423413,str,10/16);
atoi(str);
预处理命令
宏定义//先换后运算,只作字符替换,不分配内存空间;无类型
#definePI3.1415926
#defines(r)((r)*(r))*PI
文件包含#include<文件名>系统配置
#include”文件名”当前目录=>系统配置
#include”C:
\c++\file.h”
条件编译#ifdef标示符//标示符已定义,执行程序段1;
程序段1
#else
程序段2
#endif
#ifndef标示符//标示符未定义,执行程序段1;
程序段1
#else
程序段2
#endif
#if表达式\程序段1\else\程序段2\#endif
例:
#ifndefxxxxxxxxxxxxxx
#definexxxxxxxxxxxxxx
……
#endif
指针
&
*
[]
指针:
数据类型,占4个字节;//指针的类型、指针指向的类型;
内存:
在程序运行期间,所申请空间的集合;
地址:
内存的编号;//地址存储数据的类型;
*p:
以p中所存储的内容为起始地址,以p的基类型所占据的内存字节数作为偏移量,来访问此空间;
在被调函数中,通过对形参指针的间接访问,可以改变主调函数中实参指针所指向的变量值;
数组与指针
inta[10]={1,2,3,4,5,7,6,8,9,0},*p,i,b[10],*q;
inta2a[3][4]={1,2,3,4,5,6,7,8,9,0,11,10};
p=a;<=>p=&a[0];
p+/-1;//p+/-1*d,d基类型大小;
a[i]<=>p[i]<=>*a(i+1)<=>*p(i+1);
memcpy(b,a,sizeof(a));//将数组a中的元素拷贝数组b中;
(*p++)++;//正确,*p++代表a[0];
*(p++)++;//错误,p++为表达式;
指针变量/数组名均可作形参或实参;
p=(int*)(&a+1);=>*(p-1)=0;//inta[10]<=>int*&a[10];
=>int[10]*&a;=>int(*)[10];基类型为int[10];
\\q=&a;
p=a+1;=>*(p-1)=1;//int*a;
//&a表示整个数组a的地址,所指向的类型是int[10];
a表示数组a的首元素地址,所指向的类型是int;
p=a2a[0];p=*a2a;p=&a2a[0][0];//0行0列元素的地址;
数组指针(指向数组的指针)int(*p1)[4];
p1=a2a;p1=&a2a[0];//0行地址;
字符指针char*string="helloworld!
";
char*string1="helloworld!
";
charstr[]="2011/11/12/s";
p[3]=T;//错误;p[3]是常量l;在程序运行期间不能被改变;
string与string1的值相等;
string指向常量不能改变,指向变量能改变;
函数指针(指向函数的指针)
函数名代表入口地址;
intmax(int,int);int(*p)(int,int);p=max;
c=(*p)(a,b);<=>c=p(a,b);等价
缓冲区溢出漏洞;
只需要知道函数入口地址均可访问;
例:
int(*pfn)(char*);
pfn=(int(*)(char*))0x....函数入口地址;
free(p)只是标记此空间可在被分配,但原内存空间的数据仍在,被分配后释放;
指针函数(返回指针值的函数)
指针数组(每一个元素都是指针变量)
指向指针的指针
typedefint(*AP)[20];
APa[10];
voidmain(intargc,char*argv[])
结构体与共用体
共用体用相同的内存空间,以最大的为所占的内存空间,一改全改;
枚举类型
枚举值是常量,不是变量;
位运算
位段
文件
符号
国际C语言乱码大赛(IOCCC)
#include
main(t,_,a)char*a;{return!
0t<3?
main(-79,-13,a+main(-87,1-_,
main(-86,0,a+1)+a)):
1,t<_?
main(t+1,_,a):
3,main(-94,-27+t,a)&&t==2?
_<13?
main(2,_+1,"%s%d%d\n"):
9:
16:
t<0?
t<-72?
main(_,t,
"@n'+,#'/*{}w+/w#cdnr/+,{}r/*de}+,/*{*+,/w{%+,/w#q#n+,/#{l+,/n{n+,/+#n+,/#;\
#q#n+,/+k#;*+,/'r:
'd*'3,}{w+Kw'K:
'+}e#';dq#'l\q#'+d'K#!
/+k#;q#'r}eKK#}w'r}eKK{nl]'/#;#q#n'){)#}w'){){nl]'/+#n';d}rw'i;#\
){nl]!
/n{n#';r{#w'rnc{nl]'/#{l,+'K{rw'iK{;[{nl]'/w#q#n'wknw'\
iwk{KK{nl]!
/w{%'l##w#'i;:
{nl]'/*{q#'ld;r'}{nlwb!
/*de}'c\
;;{nl'-{}rw]'/+,}##'*}#nc,',#nw]'/+kd'+e}+;#'rdq#w!
nr'/')}+}{rl#'{n'')#\
}'+}##(!
!
/")
:
t<-50?
_==*a?
putchar(31[a]):
main(-65,_,a+1):
main((*a=='/')+t,_,a+1)
:
0main(2,2,"%s"):
*a=='/'||main(0,main(-61,*a,
"!
ek;dci@bK'(q)-[w]*%n+r3#l,{}:
\nuwloca-O;m.vpbks,fxntdCeghiry"),a+1);}
//注释符号
A、char*s="abcdefgh//hijklmn";
B、int/*...*/i;
C、//Isita\
validcomment?
D、in/*…*/ti;
//A,B,C正确;D错误;用空格代替原来的注释;””之间//也是字符;
/*这是*/#/*一条*/define/*合法的*/ID/*预处理*/replacement/*指*/list/*令*/
///*…*/这种形式的注释不能嵌套/*这是/*非法的*/*/因为/*总是与离它最近的*/匹配
y=x/*p//错误;/*会被当作注释的开始;
\表示断行用作接续符(不能有空格),还能被用作转义字符的开始标识。
#def\
ineMAC\
RO这是一条合法的\
宏定义
0x01<<2+3;//表达式的结果是32;+优先于<<;
程序解析
1、
intmain()
{
chara[1000];
inti;
for(i=0;i<1000;i++)
{
a[i]=-1-i;
}
printf("%d",strlen(a));
return0;
}
结果:
255字符串长度到'\0'结束,a[255]=0;
2、
unsignedi;
for(i=9;i>=0;i--)
{
printf("%u\n",i);
}
死循环,i为无符号数;
3、
-0/+0在内存中的存储方式:
4、
#include
intmain()
{
inta[5]={1,2,3,4,5};
int*ptr1=(int*)(&a+1);
int*ptr2=(int*)((int*)a+1);
printf("%x,%x",ptr1[-1],*ptr2);
return0;
}
结果:
5,2;
程序陷阱
贪心法y=x/*p/*p是一个指向除数的指针/;=>编译器处理成y=x;
011与11的区别:
前者8进制为9,后者10进制位11;
char*p="a";//正确;char*p='a';//错误;
switch语句中的break;
*p++:
表示(*p)++;和1/2*a:
表示(1/2)*a;
死循环:
intFactorial(intn)
{
if(n<=0)return0;
elsereturnn*Factorial(n-1);
}//n!
的值增长很快,只对有限的n有效;
自减运算符副作用:
intFactorial(intn)
{
if(n<=0)return0;
elsereturnn*Factorial(--n);
}//--n对第二个n有影响;
C语言系统函数模拟
1、malloc/free
#include
#include
#include
#defineMSIZE10000
staticcharmBuf[MSIZE];
staticchar*pTop=mBuf;
void*Malloc(intn)
{
if(mBuf+MSIZE-pTop>=n)
{
pTop+=n;
returnpTop-n;
}
elsereturn0;
}
voidFree(char*p)
{
if(p>=mBuf&&ppTop=p;
}
intmain()
{
char*pchar=NULL;
charstrName[801];
pchar=Malloc(10);
puts("Enteryourname:
");
while((strlen(pchar)<800)&&strlen(gets(strName)))
{
strcat(pchar,strName);
printf("%s\n",pchar);
}
Free(pchar);
pchar=NULL;
return0;
}
经典程序
闰年
公约数\公倍数
水仙花数
完数
素数
杨辉三角
魔方阵
鞍点
字符\行数\单词\数字
递归
字符串逆序
#include
#include
voidReverseDisplay(void)
{
intc;
if((c=getchar())!
='\n')
ReverseDisplay();
printf("%c",c);
}
intmain(void)
{
printf("enterstring:
\n");
ReverseDisplay();
printf("\n");
return0;
}
单词逆序
#include
#include
#defineMAXWORD80
intGetWord(char*s)
{
intc;
while((c=getchar())!
=''&&c!
='\n')
{
*s++=(char)c;
}
*s='\0';
returnc;
}
voidReverseDisplay(void)
{
charw[MAXWORD];
if((GetWord(w))!
='\n')
ReverseDisplay();
printf("%s",w);
}
intmain(void)
{
printf("enterstring:
\n");
ReverseDisplay();
printf("\n");
return0;
}
皇后问题
#include
#include
#defineN80
#defineFALSE0
#defineTRUE1
voidOutSolution(intn,intx[])
{
staticintnum=0;
inti,j;
printf("第个%d解:
\n",++num);
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
if(x[i]==j)
printf("Q|");
else
prin