C/C++语言复习
1 | include<stdio.h> |
函数写在main
下面得时候,要在main
函数里面声明,例如 viod test();
调用test();
带返回值得函数都需加类型,没有返回值得用void 传递数组时,传递首地址,所以声明函数中数组可以不加大小
void test(int array[])
但是类型要一致 ,多维要加最高维度大小 int test(int array[][10])
寄存器变量 register
减少去内存读取数量
全局变量定义域一般从定义处开始到文件末,使用extern
可以把下面得全局变量扩展到此处。两个文件间使用扩展得话
就是一个文件定义全局变量,另一个文件使用extern
进行扩展链接 ,如果一个文件中全局变量被static
修饰,
则其他文件中不能用extern
扩展
static
修饰函数时不能被其他文件调用 extern
修饰函数可以被其他文件声明使用 是默认,可省
指针
-
& 取地址运算符。&a是变量a的地址
-
*
指针运算符(或称“间接访问”运算符),*p 代表指针变量 p 指向的对象。
1 |
|
1 | 输出: |
- 指针指向数组包括:
1 | int a[3]={1,2,3}; |
数组名赋值给指针只能代表首元素地址,并不能表示整个数组。
因为数组在内存中是顺序存储,所以可以采用p+1
的方式使指针指向下一个元素。注意:执行p+1
时并不是将p
的值(地址)简单的加1,而是加上一个数组元素所占用的字节数。所以p+1
意味着使p
的值(是地址)加上4个字节,所代表的地址实际上是(p+1)*d
(int d=4字节, float和long d=4字节, char d=1字节),二维数组名指针指向首行首元素,加1后相当于加了1行,地址加了一整行的大小,表示下一个元素使用 a[0]+1
指针数组:
1 |
|
例题:
1 |
|
对于字符串来说
1 | char str[]="asadad";//str[4]相当于*(str+4) |
对于字符串中字符的存取,可以用下标方法,也可以用指针方法,如:
1 |
|
-
注意:
-
字符数组由若干个元素组成,每个元素中放一个字符,而字符指针变量中存放的是地址(字符串第1个字符地址),绝不是将字符串放到字符指针变量中。
-
赋值方式。可以对字符指针变量赋值,但不能对数组名赋值
可以才采用一下方法对字符指针变量赋值:
1
2char *a;
a="test";//a并不代表字符串,而是第一个元素地址不能用以下方法对字符数组名赋值:
1
2
3char str[14];
str[0]='i';//对字符元素赋值,√
str="test";//× -
初始化含义。对字符变量赋值:
1
char *a = "test";
等价于
1
2char *a;
a="test";而对数组初始化:
1
char str[5]="test";
不等价于
1
2char str[5];
str[]="test"; -
使用输入时,不能直接将内容输入指针,指针必须指向一段地址:
错误:
1
2char *a;
scanf("%s",a);正确:
1
2
3char *a,str[5];
a=str;
scanf("%s",a); -
字符数组中各元素的值是可以被改变的(可以对它们再赋值),但字符指针变量指向的字符串常量中的内容是不可以被取代的(不能对它们再赋值)。如:
1
2
3
4char a[]="house";
char *str="house";
a[2]='r';//合法,r取代a数组元素a[2]的原值u
str[2]='r';//非法,字符串常量不能改变
函数指针:
1
2
3
4
5
6
7int test(int x,int y){
return x;
}
int (*p)(int,int);
p=test;//将函数入口地址赋给p
int a=2,b=3;
c=(*p)(a,b); -
-
利用函数指针向函数中传递函数
1
2
3
4
5void fun(int (*x1)(int),int(*x2)(int,int)){
int a,b,i=3,j=5;
a=(*x1)(i);
b=(*x2)(i,j);
} -
返回指针值的函数
1
int *a(int x,int y);//()优先级高于*
指针数组和多重指针:
-
一个数组其元素均为指针类型数据,称为指针数组,也就是说,指针数组中每个元素存放一个地址,相当于一个指针变量,如下所示:
1
int *p[4];
- 由于 [] 优先级高于“
*
”,所以 p 先和 [] 结合为一个数组,再和“*
” 结合成为一个指针数组,每个数组元素相当于指针变量,可指向一个整形变量。 - 注意:不要写成
int (*p)[4]
这是指向一维数组的指针变量 - 例题:定义一个指针数组 name,用各字符串对它进行初始化,即把各字符串中第1个字符的地址赋值给指针数组的各元素。然后用选择法排序,但不移动字符串,只改变数组的各元素指向,从小到大排序。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
int main(){
void sort(char *name[],int n);
void print(char *name[],int n);
char *name[]={"one","two","three","four","five"};
int n = 5;
sort(name,n);
print(name,n);
return 0;
}
void sort(char *name[],int n){
char *temp;
int i,j,k;
for(i=0;i<n-1;i++){
k=i;
for(j=i+1;j<n;j++)
if strcmp(name[k],name[j]>0)k=j; //不能写成if(*name[k]>*name[j])k=j;因为这样只比较了所指向字符串的第一个字符,而不是整个字符串
if(k!=i)
{temp=name[i];name[i]=name[k];name[k]=temp;}
}
}
void print(char *name[],int n){
int i;
for(i=0;i<n;i++)
print("%s\n",name[i]);//%s根据地址解析字符串,不用加*引用计算
} - 由于 [] 优先级高于“
-
**p
从右向左读相当于*(*p)
其中*p
表示指针变量 而前面加*
则可以表示指向指针变量的指针,例如:1
2
3
4
5
6
7
8
9
10
11
int main(){
char *name[]={"one","two","three","four","five"};
char **p;
int i;
for(i=0;i<5;i++){
p=name+i;
printf("%s\n",*p);//指向字符串时%s可以直接解析地址输出字符串,%d则输出地址
}
return 0;
}1
2
3
4
5
6
7
8
9
10
11
12
int main(){
int a[5]={1,3,5,7,9};
int *num[5]={&a[0],&a[1],&a[2],&a[3],&a[4]};
int **p,i;
p=num;
for(i=0;i<5;i++){
printf("%d\n",**p);//指向整型数组时p时指向指针型数据的指针变量
p++;
}
return 0;
}
动态分配内存
- C99允许使用基类型为
void
的指针类型。可以定义一个基类型为void
的指针变量(即void *
型变量),它不指向任何类型的数据。请注意:不要把 “指向void
类型” 理解为能指向 “任何的类型” 的数据,而应理解为 “指向空类型” 或 “不指向确定的类型” 的数据。在将它的值赋给另一指针变量时由系统对它进行类型转换,使之适合于被赋值的变量的类型。例如
1 | int a =3;//定义a为整型变量 |
-
注意:当把
void
指针赋值给不同基类型的指针变量(或相反)时,编译系统会自动转换,不必用户自己进行强制转换。例如:p3=&a;
相当于
p3=(void *)&a;
,赋值后p3
得到a
的纯地址,但并不指向a
,不能通过* p3
输出a
的值。
例题:建立动态数组,输入5个学生的成绩,另外用一个函数检查其中有无低于60分的,输出不合格的成绩。
思路:用malloc
函数开辟一个动态自由区域,用来存5个学生的成绩,会得到这个动态域第1个字节的地址,它的基类型是void
型。用一个基类型为 int
的指针变量 p
来指向动态数组的各元素,并输出它们的值。但必须先把malloc
函数返回void
指针转换为整型指针,然后赋给 p1
。
1 |
|
要区别指针和指针变量。指针就是地址本身。而指针变量是用来存放地址的变量。指针变量的值是一个地址。
指针变量可以有空值:
1 | p=NUll;//NULL是一个符号常量,代表整数0,malloc分配失败时也为NULL |
结构体
1 | struct Date{ |
结构体初始化:
1 |
|
对结构体中某一项初始化:
1 | struct Student b={.name="Zhang Fang"}; |
在引用结构体和使用时不能使用整体结构体进行赋值、存取以及运算,必须具体到元素,如果其中有嵌套其他结构体,要一级一级找到最低级的成员。
1 | student1.num |
结构体数组:
1 | struct Person{ |
结构体指针:
如果 p
指向一个结构体变量 stu
,以下三种用法等价:
stu
.成员名(如stu.num
);(*p)
.成员名(如(*p).num
);//不能写成*p.num
因为.
的优先级高于*
相当于*(p.num)
p->
成员名(如p->num
)
1 |
|
可以采用结构体指针做实参传入函数进行处理
链表
1 | struct Student{ |
例题:建立一个简单链表,有3个学生数据的结点组成,要求输出各个结点的数据。
1 |
|
例题:建立一个有3名学生数据的单项动态链表
1 |
|
共用体
使几个不同的变量共享一段内存的结构,称为“共用体”类型的结构。在结构体中占用的内存大小是所有的数据类型的大小之和。在共用体中占用的内存大小是所有数据中最大的数据类型的值。
1 | union Data{ |
引用共用体的方式:
- 只有先定义了共用体变量才能引用他,三个成员共用一个地址,但应注意,不能引用共用体变量,而只能引用变量中的成员。
1 | a.i |
- 在使用公用体时要注意,在每一瞬间,共用体中只能存放一个成员,储存单元只有唯一的内容。
1 | a.i=97; |
- 可以对共用体初始化
1 | union Data{ |
枚举类型
如果一个变量只有几种可能的值,则可以定义为枚举类型(enum),声明枚举类型用enum开头。
1 | enum Weekday{sun,mon,tue,wed,thu,fri,sat}; |
- 每个枚举元素都代表一个整数,C语言编译按定义时的顺序默认他们的值为0,1,2,3······。在上面的定义中,sun 的值为 0 ,mon 的值为 1,···sat 的值为 6。如果有赋值语句:
1 | workday=mon; |
typedef
使用typedef声明新类型(别名)例如:
1 | typedef int Integer;//指定用Integer为类型名,作用与int相等。 |
文件
- 打开文件
fopen
1 | FILE *fp;//定义一个指向文件的指针变量fp |
- 使用
fopen
时如果出错,如:用”r“打开一个不存在的文件,磁盘故障,磁盘已满无法建立新文件等。此时fopen
会返回一个空指针值NULL
1 | if((fp=fopen("file","r"))==NULL) |
- 关闭文件使用
fclose
,一般形式为fclose(文件指针)
:
1 | fclose(fp);//有返回值,成功返回0,否则返回EOF(-1)。 |
- 读写操作使用
fgetc(fp)
和fputc(ch,fp)
:
1 |
|
1 |
|
- 输入路径时使用
\\
防止转义字符如:D:\\test\\one.dat
格式化方式读写文件:
1 | fprintf(文件指针,格式字符串,输出列表); |
用二进制防止向文件读写一组数据:
1 | fread(buffer,size,conunt,fb); |
- 其中,
buffer
是一个地址,对fread
来说时存放文件读入的储存区地址。对fwrite
来说,是要把此地址开始的存储区中的数据向文件输出。size
表示要读写的字节数。count
要读写多少个数据项(每个数据项长度为size
)。fp
是FILE
类型指针。
在打开文件时指定用二进制文件,这样就可以用fread
和fwrite
读写任何类型的信息,例如:
1 | fread(f,4,10,fp);//其中f是一个float类型的数组名(代表数据首元素地址)。这个函数从fp所指向的文件中读入10个4字节的数据,存储到数组f中。 |
读结构体:
1 | struct Student_type{ |
rewind
函数的作用是使文件位置标记重新返回文件开头,此函数没有返回值。
1 | rewind(fp1); |
fseek
函数改变文件位置标记,使用形式 feek(文件类型指针,位移量,起始点)
1 | fseek(fp,100L,0);//将文件位置标记向前移动到离文件开头100字节处 |
ftell
标记当前位置
1 | i=ftell(fp);//存放当前位置 |
ferror
读写出错检查,返回0为未出错,如果是非零值则表示出错。
C++
- 可以进行
bool
运算使用基本运算符号表示可以判断
1 | //In C99 没有bool |
- 类型转换
1 | C Style:(type)value |
- 定义
1 | int y(1);//相当于int y=1; |
- 变量作用域,可在两个非嵌套块中声明两个
i
- 当局部变量与全局冲突时,可使用
::
访问全局变量
- 当局部变量与全局冲突时,可使用
1 |
|
-
重载函数,同名函数,传参类型不同,编译器会自动匹配。
-
默认参数,要后置,这样调用时不会有歧义。
1 | void test(int b,double a=1.0){}; |
###动态内存管理
- C++中通过运算符
new
申请动态内存- 如果申请成功,返回指定类型内存的地址;
- 如果申请失败,返回空指针(整数0,C++中废弃了NULL);
1 | new <类型名>(初值);//申请一个变量的空间 |
- 动态内存使用完毕后,要用delete运算符来释放。
1 | delete <指针名>;//删除一个变量的空间 |
- 常量指针 VS 指针常量
- 在前先读,在前不变,
const
在谁前面谁就不允许被改变。
- 在前先读,在前不变,
1 | const int * X; |
###C++数据类型
- C++中数据类型分布
Constructors
构造函数
1 | class Name{ |
项目属性参数C++中加-O0
表示不做任何优化
类的声明和使用
- 类的声明和实现:
1 | Test.cpp//函数实现::-》二元作用域分隔符,域分隔符 |
###C++指针
- 用指针访问对象
1 | Test test1; |
- 在堆区创建对象(不会在执行完后被从栈区销毁)
1 | Test *ptest1=new Test(); |
字符串
1 |
|
- 字符串运算符
数据封装
1 | Test2.cpp//函数实现::-》二元作用域分隔符,域分隔符 |
变量作用域和this指针
1 | class Test{ |
- 对象数组
1 | Test testarray[10];//相当于testarray[1].getNum() |