c语言复习

C/C++语言复习

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
31
32
33
34
35
include<stdio.h>
基本头函数
include<string.h>
字符串处理函数
int main(void) {
int a[10];
int j=1;
for(int i = 0;i<10;++i){//第三个函数体最后循环结束时才运行,++i和i++一样

a[i]=++j;
printf("%d\n",a[i]);
printf("%d\n",i);
};

char c[4]={'a','b','\0','d'};//单个字符用‘’\0表示结束,“”超过一个字符

printf("%c",getchar());
char str[13];
scanf("%s",str);//c语言中如果输入是数据变量则不需要加&引用,数组本身就是引用地址
int a ;
scanf("%d",&a);
char c[]={"China\n12223"};//会在字符组后自动 添加\0
printf("%s",c);
puts(c);//输出已经定义得字符组

gets(c);//从键盘获取char数组字符+1位返回值时c得起始地址,puts和gets只能输出和输入一个字符串
puts(c);
char c[20]={"China\n12223"};//会在字符组后自动 添加\0
char str[]={"\nxxx"};
printf("%s",strcat(c,str));//strcat可以链接两个字符串,且第一个字符串要足够大可以容纳下1,2两个数组,不满得位置都是\0
char str1[10],str2[]="China";
printf("%s",strcpy(str1,str2));//将字符串2复制到1中也可以strcpy(str1,"China")
strcmp(str1,"China");//比较两个字符串相等=0左大为正数,右大为负数
strlen("asdasd");//统计字符串完整长度,不包括\0
//strlwr将字符串中大转小 strupr 小转大

函数写在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
2
3
4
5
6
7
8
9
10
11
# include<stdio.h>
int main(){
int a=10;
int *p=&a;//相当于 int *p; p=&a;
printf("%d\n",a);//变量a的值
//p=&a;
printf("%d\n",*p);//间接访问变量a的值
*p=2;
printf("%d\n",p);//变量a的地址
return 0;
}
1
2
3
4
输出:
10
10
6487572
  • 指针指向数组包括:
1
2
3
4
int a[3]={1,2,3};
int *p;
p=&a[1];//得到a[1]元素的地址
p=a;//相当于p=&a[0]获得数组a首元素a[0]的地址

数组名赋值给指针只能代表首元素地址,并不能表示整个数组。

因为数组在内存中是顺序存储,所以可以采用p+1的方式使指针指向下一个元素。注意:执行p+1时并不是将p的值(地址)简单的加1,而是加上一个数组元素所占用的字节数。所以p+1意味着使p的值(是地址)加上4个字节,所代表的地址实际上是(p+1)*dint d=4字节, float和long d=4字节, char d=1字节),二维数组名指针指向首行首元素,加1后相当于加了1行,地址加了一整行的大小,表示下一个元素使用 a[0]+1


指针数组

1
2
3
4
5
6
7
8
9
10
# include<stdio.h>
int main(){

int a [4]={1,2,3,4};
int (*p)[4];
p=&a;//指向一维数组,不能写成“p=a;”,因为这样表示p是&a[0],指向a[0]。“p=&a;”表示p指向一维数组(行),(*p)[3]是p所指向的行中序号为3的元素。
printf("%d\n",(*p)[3]);

return 0;
}

例题:

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
# include<stdio.h>
int main()
{void average(float *p,int n);
void search(float (*p)[4] ,int n);

float a[3][4]={{1,2,3,4},{2,2,3,4},{3,2,3,4},{4,2,3,4}};
average(*a,12);//传入参数为*a 即a[0],也就是&a[0][0],即a[0][0]的地址。
serach(a,2);//传入实参a,因为对应float (*p)[4]是包含4个元素的一组数组的指针变量,所以p指向的是a[0],第0行的地址。p+n是a[n]的起始地址,*(p+n)+i是a[n][i]的地址,*(*(p+n)+i)是a[n][i]的元素值 a+i=a[i]=*(a+i)=&a[i]=&a[i][0]
return 0;
}

void average(float *p,int n)
{
float *p_end;
float sum=0,aver;
p_end=p+n-1;
for(;p<=p_end;p++)
sum=sum+(*p);
aver=sum/n;
printf("average%5.2f\n",aver);//5.2是指结果总长是五位数(注意小数点也算一位数长),就是小数点前两个数字,不足就用空格表示,小数点后保留两位,不足四舍五入!
}

void search(float (* p)[4],int n)
{
int i;
printf("第%d行\n",n);
for (i=0;i<=4;i++)
printf("%5.2f",*(*(p+n)+i));//等价*(p[n]+i)等价*(&p[n][i])
printf("\n");
}

对于字符串来说

1
2
char str[]="asadad";//str[4]相当于*(str+4)
char *str="asdasdd";//相当于 char *str;str="asdasdd";字符串并没有被放入指针,而是“asdasdd”的第一个字符的地址赋值给了指针变量str

对于字符串中字符的存取,可以用下标方法,也可以用指针方法,如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# include<stdio.h>
int main()
{
char a[]="paniford",b[20];
int i;
for (i=0;*(a+i)!='\0',i++)
*(b+i)=*(a+i);//将a[i]给b[i]
*(b+i)='\0';//在最后加\0 !!注意!!使用‘’对单个char
printf("string a is: %s\n",a);//输出a中全部有效字符,%s输出字符串时不用*计算双重时加一个*
printf("string b is;");
for (i=0;b[i]!='\0',i++)
printf("%c",b[i]);//逐个输出b组中全部有效字符
printf("\n");
return 0;
}
  • 注意:

    • 字符数组由若干个元素组成,每个元素中放一个字符,而字符指针变量中存放的是地址(字符串第1个字符地址),绝不是将字符串放到字符指针变量中。

    • 赋值方式。可以对字符指针变量赋值,但不能对数组名赋值

      可以才采用一下方法对字符指针变量赋值:

      1
      2
      char *a;
      a="test";//a并不代表字符串,而是第一个元素地址

      不能用以下方法对字符数组名赋值:

      1
      2
      3
      char str[14];
      str[0]='i';//对字符元素赋值,√
      str="test";//×
    • 初始化含义。对字符变量赋值:

      1
      char *a = "test";

      等价于

      1
      2
      char *a;
      a="test";

      而对数组初始化:

      1
      char str[5]="test";

      不等价于

      1
      2
      char str[5];
      str[]="test";
    • 使用输入时,不能直接将内容输入指针,指针必须指向一段地址:

      错误:

      1
      2
      char *a;
      scanf("%s",a);

      正确:

      1
      2
      3
      char *a,str[5];
      a=str;
      scanf("%s",a);
    • 字符数组中各元素的值是可以被改变的(可以对它们再赋值),但字符指针变量指向的字符串常量中的内容是不可以被取代的(不能对它们再赋值)。如:

      1
      2
      3
      4
      char a[]="house";
      char *str="house";
      a[2]='r';//合法,r取代a数组元素a[2]的原值u
      str[2]='r';//非法,字符串常量不能改变

    函数指针:

    1
    2
    3
    4
    5
    6
    7
    int 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
    5
    void 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
    #include<stdio.h>
    #include<string.h>
    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
    #include<stdio.h>
    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
    #include<stdio.h>
    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
2
3
4
5
6
7
8
9
10
int a =3;//定义a为整型变量
int *p1 = &a;//p1 指向int型变量
char *p2;//p2 指向char型变量
void *p3;//p3为无类型指针变量(基类型为viod型)
p3=(void *)p1;//将p1的值转换为 void* 类型,然后赋值给 p3
p2=(char *)p3;//将p3的值转换为 char* 类型,然后赋值给 p2
printf("%d",* p1);//合法,输出a的值
printf("%d",* p2);//合法,输出a的值
p3=&a;
printf("%d",* p3);//错误,p3是无指向的,不能指向a
  • 注意:当把void指针赋值给不同基类型的指针变量(或相反)时,编译系统会自动转换,不必用户自己进行强制转换。例如:

    p3=&a;

    相当于p3=(void *)&a;,赋值后p3得到a的纯地址,但并不指向a,不能通过* p3输出a的值。

例题:建立动态数组,输入5个学生的成绩,另外用一个函数检查其中有无低于60分的,输出不合格的成绩。

思路:用malloc函数开辟一个动态自由区域,用来存5个学生的成绩,会得到这个动态域第1个字节的地址,它的基类型是void型。用一个基类型为 int 的指针变量 p 来指向动态数组的各元素,并输出它们的值。但必须先把malloc 函数返回void指针转换为整型指针,然后赋给 p1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# include<stdio.h>
# include<stdlib.h>
//包含malloc函数的stdlib.h
int main(){
void check (int *);//声明函数可省指针
int *p1,i;
p1=(int *)malloc(5 * sizeof(int)); //开辟动态内存区,将地址转换成 int *型,然后放在p1中,malloc函数的返回值是void * 类型,要把它赋给p1,应先进行类型的转换,把该指针转换成int*型。
//p1=malloc(5 * sizeof(int));//也合法,编译系统会自动转换
for(i=0;i<5;i++)
scanf("%d",p1+i);
check(p1);
return 0;
}

void check(int *p){
int i;
printf("They are fail:");
for(i=0;i<5;i++)
if(p[i]<60)printf("%d",p[i]);
printf("\n");
}

要区别指针和指针变量。指针就是地址本身。而指针变量是用来存放地址的变量。指针变量的值是一个地址。

指针表示

指针表示2

指针变量可以有空值:

1
p=NUll;//NULL是一个符号常量,代表整数0,malloc分配失败时也为NULL

结构体

1
2
3
4
5
6
7
8
9
10
11
12
13
struct Date{
int month;
int day;
int year;
}birthday;//等价
struct Student{
int num;
char name[20];
char sex;
int age;
struct Date birthday;
char addr[30];
};

结构体示意图

结构体初始化:

1
2
3
4
5
6
7
8
9
10
11
# include <stdio.h>
int main(){
struct Student{
long int num;
char name[20];
char sex;
char addr[20];
}a={10101,"xiaohong",'M',"123123beijing"};//定义结构体变量a并初始化
printf("NO.:%ld\n name:%s\n sex:%c\n address:%s\n",a.num,a.name,a.sex,a.addr);
return 0;
}

对结构体中某一项初始化:

1
struct Student b={.name="Zhang Fang"};

在引用结构体和使用时不能使用整体结构体进行赋值、存取以及运算,必须具体到元素,如果其中有嵌套其他结构体,要一级一级找到最低级的成员。

1
2
student1.num
student1.birthday.month

结构体数组:

1
2
3
4
5
struct Person{
char name[20];
int count;
}leader[3]={"li",0,"zhang",0,"wang",0};
struct Person leader[3]={"li",0,"zhang",0,"wang",0};//等价

结构体指针:

如果 p 指向一个结构体变量 stu ,以下三种用法等价:

  • stu.成员名(如 stu.num);
  • (*p).成员名(如 (*p).num);//不能写成*p.num因为.的优先级高于* 相当于*(p.num)
  • p->成员名(如 p->num)
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# include <stdio.h>
# define N 2//不能加=
struct Student{
long int num;
char name[20];
char sex;
int age;
}a={10101,"xiaohong",'M',22},b[3]={10101,"xiaohong",'M',22,10102,"xiaohong2",'M',27,10103,"xiaohong3",'M',21};

int main(){
void print(struct Student stu);
void input(struct Student stu[]);
struct Student max(struct Student stu[]);

struct Student *p=&a,*q=b;//等价于struct Student *p,*q;p=&a,q=b;
struct Student stu1[N],*t=stu1;

input(t);
print(t[0]);
print(t[1]);
print(max(q));
print(*p);
printf("%5d %-5s %2c %4d\n",p->num,p->name,p->sex,p->age);

return 0;
}

void input(struct Student stu[]){
int i ;
printf("请输入两位学生信息:学号、姓名、性别(M|W)、年龄\n");
for(i=0;i<N;i++){
scanf("%d %s %c %d",&stu[i].num,&stu[i].name,&stu[i].sex,&stu[i].age);
}
}

void print(struct Student stu){//只传值
printf("%d %s %c %d\n",stu.num,stu.name,stu.sex,stu.age);
}

struct Student max(struct Student stu[]){//传地址,返回地址 函数类型要与返回类型一致
int i ,m=0;
for (i =0;i<3;i++){
if (stu[i].age>stu[m].age)m=i;
};
return stu[m];
}

可以采用结构体指针做实参传入函数进行处理


链表

1
2
3
4
5
struct Student{
int num;
float score;
struct Student *next;//结构体指针指向结构体变量
}

例题:建立一个简单链表,有3个学生数据的结点组成,要求输出各个结点的数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# include<stdio.h>
struct Student{
int num;
float score;
struct Student *next;//结构体指针指向结构体变量
};
int main(){
struct Student a,b,c,*head,*p;
a.num=101;a.score=90;
b.bum=102;b.score=89.5;
c.num=103;c.score=70.5;
head = &a;
a.next=&b;
b.next=&c;
c.next=NULL;
p=head;
do{
printf("%ld %5.1f\n",p->num,p->score);
p=p->next;
}while(p!=NULL);
return 0;
}

例题:建立一个有3名学生数据的单项动态链表

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# include<stdio.h>
# include<stdlib.h>
# define LEN sizeof(struct Student)
struct Student{
int num;
float score;
struct Student *next;//结构体指针指向结构体变量
};
int n;
struct Student *creat(void){ //定义函数,此函数返回一个指向链表头的指针,括号中的*不能省,因为返回的head是一个指针类型,
struct Student *head,*p1,*p2;
n=0;
p1=p2=(struct Student *)malloc(LEN);//开辟一个新单元LEN表示结构体Student的长度
scanf("%d,%f",&p1->num,&p1->score);//输入时%d,%f如果有,号会优先赋值运行,使用空格会使全部输入完成才向下运行
head=NULL;
while(p1->num!=0){//输入0,0表示结束
n=n+1;
if(n==1)head=p1;
else p2->next=p1;
p2=p1;
p1=(struct Student *)malloc(LEN);//括号中的*不能省,否则将强制转换为struct Student类型,而不是指针类型了
scanf("%d,%f",&p1->num,&p1->score);//输入时%d,%f如果有,号会优先赋值运行,使用空格会使全部输入完成才向下运行
}
p2->next=NULL;
return(head);
}

int main(){
struct Student *pt;
pt=creat();
//while(pt!=NULL){
// printf("\n num:%ld \nscore:%5.1f\n",pt->num,pt->score);
// pt=pt->next;
//}
// do{
// printf("\n num:%ld \nscore:%5.1f\n",pt->num,pt->score);
// pt=pt->next;
// }while(pt!=NULL);

for(int i=0;i<n;i++){
printf("\n num:%ld \nscore:%5.1f\n",pt->num,pt->score);
pt=pt->next;
};
return 0
}

共用体

使几个不同的变量共享一段内存的结构,称为“共用体”类型的结构。在结构体中占用的内存大小是所有的数据类型的大小之和。在共用体中占用的内存大小是所有数据中最大的数据类型的值。

1
2
3
4
5
6
union Data{
int i;
char ch;
float f;
}a,b,c;
union Data a,b,c;//等价

引用共用体的方式:

  • 只有先定义了共用体变量才能引用他,三个成员共用一个地址,但应注意,不能引用共用体变量,而只能引用变量中的成员。
1
2
3
4
a.i
a.ch
a.f
printf("%d",a.i);
  • 在使用公用体时要注意,在每一瞬间,共用体中只能存放一个成员,储存单元只有唯一的内容。
1
2
3
4
a.i=97;
printf("%d",a.i); //(输出整数97)
printf("%c",a.ch);//输出‘a’,是ASCII码值对应的字符
printf("%f",a.f);//输出实数0.000000
  • 可以对共用体初始化
1
2
3
4
5
6
7
union Data{
int i;
char ch;
float f;
}a={1,'a',4.5};//错误,不能初始化3个成员
union Data a={16};//正确,对第1个成员初始化
union Data a={.ch='j'};//C99允许对指定一个成员初始化

枚举类型

如果一个变量只有几种可能的值,则可以定义为枚举类型(enum),声明枚举类型用enum开头。

1
2
3
4
5
enum Weekday{sun,mon,tue,wed,thu,fri,sat};
enum {sun,mon,tue,wed,thu,fri,sat}Workday,weekend;//可以不声明有名字的枚举类型,而直接定义变量
Weekday=mon;//合法
Weekday=sun;//合法
Weekday=monday;//非法,不是枚举类中所有的变量
  • 每个枚举元素都代表一个整数,C语言编译按定义时的顺序默认他们的值为0,1,2,3······。在上面的定义中,sun 的值为 0mon 的值为 1,···sat 的值为 6。如果有赋值语句:
1
2
3
4
5
6
workday=mon;
//相当于
workday=1;
//可以使用printf输出
printf("%d",workday);//输出为整数1
enum Weekday{sun=7,mon=1,tue,wed,thu,fri,sat}Workday,weekend;//也可以自定义,指定sun为7,mon为1,以后顺序加1

typedef

使用typedef声明新类型(别名)例如:

1
typedef int Integer;//指定用Integer为类型名,作用与int相等。

文件

  • 打开文件fopen
1
2
FILE *fp;//定义一个指向文件的指针变量fp
fp=fopen("a1","r");//将fopen函数的返回值赋给指针变量fp

  • 使用fopen时如果出错,如:用”r“打开一个不存在的文件,磁盘故障,磁盘已满无法建立新文件等。此时fopen会返回一个空指针值 NULL
1
2
3
4
5
if((fp=fopen("file","r"))==NULL)
{
printf("无法打开此文件\n");
exit(0);//关闭所有文件,中止程序
}
  • 关闭文件使用fclose,一般形式为 fclose(文件指针)
1
fclose(fp);//有返回值,成功返回0,否则返回EOF(-1)。
  • 读写操作使用fgetc(fp)fputc(ch,fp):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include<stdio.h>
# include<stdlib.h>
int main(void) {
FILE *fp;
char ch,filename[10];
printf("文件名:");
scanf("%s",filename);
fp=fopen(filename,"w");//使用“w”写时如果不存在则创建,存在相同则删除原有重新创建
ch =getchar();//用来接收输入的回车符
printf("请输入字符串(以#结束):\n");
ch=getchar();
while(ch!='#'){
fputc(ch,fp);//向磁盘文件输出第一个字符
putchar(ch);//将输出的字符显示在屏幕上
ch=getchar();//再接收字符
}
fclose(fp);//关闭文件
putchar(10);//向屏幕输出换行符
return 0;
}
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
31
32
#include<stdio.h>
# include<stdlib.h>
int main(void) {
FILE *in,*out;
char ch,infile[10],outfile[10];
printf("输入读入文件名");
scanf("%s",infile);
printf("输入输出文件名");
scanf("%s",outfile);
if((in=fopen(infile,"r"))==NULL){
printf("无法打开此文件");
exit(0);
}
if((out=fopen(outfile,"a"))==NULL){//向文件2追加
printf("无法打开此文件");
exit(0);
}
//while(!feof(in)){ //如果未遇到输入文件的结束标志,等价于ch!=EOF,
// ch=fgetc(in);//从输入文件读入一个字符,暂放在变量ch中
// fputc(ch,out);//将ch写到输出文件中
// putchar(ch);//将ch显示在屏幕上
//}
while((ch = fgetc(in)) != EOF){ // 多执行一次会使末尾多ÿ
fputc(ch,out);
putchar(ch);
}
putchar(10);//显示完全部字符串后换行
fclose(in);
fclose(out);
return 0;

}
  • 输入路径时使用\\防止转义字符如:D:\\test\\one.dat

格式化方式读写文件:

1
2
3
4
5
6
7
fprintf(文件指针,格式字符串,输出列表);
fsacnf(文件指针,格式字符串,输入列表);
例如:
fprintf(fp,"%d,%6.2f",i,f);
输出:
34.50
fsacnf(fp,"%d,%6.2f",&i,&f);

用二进制防止向文件读写一组数据:

1
2
fread(buffer,size,conunt,fb);
fwrite(buffer,size,count,fp);
  • 其中,buffer是一个地址,对fread来说时存放文件读入的储存区地址。对fwrite来说,是要把此地址开始的存储区中的数据向文件输出。size表示要读写的字节数。count要读写多少个数据项(每个数据项长度为size)。fpFILE类型指针。

在打开文件时指定用二进制文件,这样就可以用freadfwrite读写任何类型的信息,例如:

1
fread(f,4,10,fp);//其中f是一个float类型的数组名(代表数据首元素地址)。这个函数从fp所指向的文件中读入10个4字节的数据,存储到数组f中。

读结构体:

1
2
3
4
5
6
7
8
9
struct Student_type{
char name[10];
int num;
int age;
char addr[30];
}stud[40];

for(int i=0;i<40;i++)
fread(&stud[i],sizeof(struct Student_type),1,fp);
  • rewind函数的作用是使文件位置标记重新返回文件开头,此函数没有返回值。
1
rewind(fp1);
  • fseek函数改变文件位置标记,使用形式 feek(文件类型指针,位移量,起始点)

1
2
3
fseek(fp,100L,0);//将文件位置标记向前移动到离文件开头100字节处
fseek(fp,50L,1);//将文件位置标记向前移动到离当前位置50字节处
fseek(fp,-10L,2);//将文件位置标记从文件末尾向后退10个字节
  • ftell标记当前位置
1
2
i=ftell(fp);//存放当前位置
if (i==-1L)printf("error\n");
  • ferror读写出错检查,返回0为未出错,如果是非零值则表示出错。

C++

  • 可以进行bool运算使用基本运算符号表示可以判断
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//In C99 没有bool
typedef int BOOL;
# define TRUE 1;
# define FALSE 0;
C++

# include <iostream>
//using namespace std;//不建议引入完全名词空间
//using std::cout;
//using std::endl;//可以省略前面std::的书写直接用 cout<<"hello world C++!"<<endl;
int main(){
bool isAlpha;
isAlpha =false;
if(!isAlpha){
std::cout<<"isAlpha="<<isAlpha<<std::endl;
std::cout<<std::boolalpha<<"isAlpha=" <<isAlpha<<std::endl;
}

return 0;
}
  • 类型转换
1
2
3
4
5
6
C Style:(type)value
printf("%d",(int)2.5);

C++ Style:static_cast<type>
cout<<static_cast<double>(1)/2;//double/double输出0.5
cout<<1/2;//int/int输出0
  • 定义
1
2
3
4
5
6
int y(1);//相当于int y=1;
int x;
int& rx=x;//引用别名&靠近类型
const int SIZE=10;
const int* p1;
p1=&SIZE;//不能改变其值 *p1=2;
  • 变量作用域,可在两个非嵌套块中声明两个i
    • 当局部变量与全局冲突时,可使用::访问全局变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# include<iostream>
using std::cout;
using std::endl;
int v1=10;
int main(){
int v1=5;
cout<<"局部变量v1:"<<v1<<endl;
cout<<"全局变量v1:"<<::v1<<endl;
return 0;
}
void function1(){
int x = 1;
int y = 1;
for (int i =1;i<5;i++){
x+=i;
}
for (int i =1;i<5;i++){
y+=i;
}
cout<<"x="<<x<<"y="<<y<<endl;
}
  • 重载函数,同名函数,传参类型不同,编译器会自动匹配。

  • 默认参数,要后置,这样调用时不会有歧义。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void test(int b,double a=1.0){};
test(3);
test(3,4.0);


int add(int x, int y =10){
return x+y;
}
int add(int x){
return x+100;
}
int main(){
add(1);//歧义,两个都可以匹配
return 0;
}

###动态内存管理

  • C++中通过运算符new申请动态内存
    • 如果申请成功,返回指定类型内存的地址;
    • 如果申请失败,返回空指针(整数0,C++中废弃了NULL);
1
2
new <类型名>(初值);//申请一个变量的空间
new <类型名>[常量表达式];//申请数组
  • 动态内存使用完毕后,要用delete运算符来释放。
1
2
delete <指针名>;//删除一个变量的空间
delete []<指针名>;//删除一个数组空间

  • 常量指针 VS 指针常量
    • 在前先读,在前不变,const在谁前面谁就不允许被改变。
1
2
const int * X;
int * const y;


###C++数据类型

  • C++中数据类型分布

  • Constructors构造函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Name{
public://表示公共可以被其他调用内部,默认是private
int test;

Name(){
test =1
}

Name(double newTest){
test=newTest;
}

int getArea(){
return test*2;//直接访问了类中的成员变量test,并没有传
}
};//不能忘

项目属性参数C++中加-O0表示不做任何优化


类的声明和使用

  • 类的声明和实现:
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
Test.cpp//函数实现::-》二元作用域分隔符,域分隔符
# include "Test.h"

Test::Test(){
num=1;
}

Test::Test(double newNum){
num=newNum;
}

double Test::getNum(){
return num*3;
};

Test.h//类声明,包括成员声明和函数声明
Class Test{
public:

double num;

Test();

Test(double);

double getNum();
}

TestMain.cpp//主函数
# include<iostream>
# include "Test.h"

using std::cout;
using std::endl;

int main(){
Test test1;
Test test(5.0);

cout<<"test1的数据:"<<test1.num<<endl;
cout<<"test2的数据:"<<test2.num<<endl;

test2.num=10;
cout<<"test2的数据改变后:"<<test2.num<<endl;

return 0;
}

###C++指针

  • 用指针访问对象
1
2
3
4
5
Test test1;
Test *ptest=&test1;

cout<<"test1的数据:"<< (*ptest).num <<endl;
cout<<"test1的数据:"<< ptest->num <<endl;
  • 在堆区创建对象(不会在执行完后被从栈区销毁)
1
2
3
4
Test *ptest1=new Test();
Test *ptest1=new Test(5.0);
//程序结束时动态对象会被销毁,或者
delete ptest1;//用delete显式销毁

字符串

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
# include 
string newString;//构造一个空字符串
streing mssage("hello world");
char charArray[]={'H','e','l','l','o','\0'};
string massage(charArray);

//追加新值append
string str("test");
str.append("qwe");//向后添加
str.append("qwezxc"31);//从3号index位开始,向后2个字符zx添加进去
str.append("qwezxc"3);//将qwez向后加
str.apped(3,'G');//向后加GGG

//赋新值assign
str.assign("newchar");

at(index);//返回当前字符串中index位字符
clear();//清空字符串
erase(index,n);//删除字符串从index开始的n个字符
empty();//检测字符串是否为空,return 1
compare();//比较字符串s1.compare(s2),相等=0
substr(index,n);//字符串从index开始的n个字符,只有一个整数时为从该位置开始到末尾的所有字符
find("co",n);//查找子串,n为起始位置
insert();//插入字符串
replace();//替换字符串中子串
str.replace(3,4,"C++");//从3号位置开始替换后面的4个字符串 C++3个后面还有个'\0'一共4个字符
  • 字符串运算符


数据封装

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
31
Test2.cpp//函数实现::-》二元作用域分隔符,域分隔符
# include "Test.h"
Test::Test(){
num=1;
}

Test::Test(int newNum){
num=newNum;
}

int Test::getNum(){
return num*3;
}

void Test::setNum(int newNum){
num=newNum;
}


Test.h//类声明,包括成员声明和函数声明
Class Test{
public:
double num;
Test();
Test(int);
int getNum();
void setNum(int);

private:
int num;
};//不能忘

变量作用域和this指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Test{
public:
Test();
Test(double num){//局部变量与私有变量冲突
//num=num;
this->num=num;//this引用当前函数的调用对象,私有变量
}
private:
double num;//或使用规范,私有类变量后加_
double num_;

public:
void setNum(double);
}

  • 对象数组
1
2
3
4
5
6
Test testarray[10];//相当于testarray[1].getNum()
Test testarray[3]={
Test(3);//匿名函数赋值
Test(4);
Test(5);
};