c语言知识点3

155 阅读6分钟

c语言知识点3

1.结构体

也可以在定义结构体的同时定义结构体指针:

struct stu{    
    char *name;  //姓名    
    int num;  //学号    
    int age;  //年龄    
    char group;  //所在小组    
    float score;  //成绩
} stu1 = { "Tom", 12, 18, 'A', 136.5 }, *pstu = &stu1;

注意,结构体变量名和数组名不同,数组名在表达式中会被转换为数组指针,而结构体变量名不会,无论在任何表达式中它表示的都是整个集合本身,要想取得结构体变量的地址,必须在前面加&,所以给 pstu 赋值只能写作:

struct stu *pstu = &stu1;

而不能写作:

struct stu *pstu = stu1;

应该注意,结构体和结构体变量是两个不同的概念:结构体是一种数据类型,是一种创建变量的模板,编译器不会为它分配内存空间,就像 int、float、char 这些关键字本身不占用内存一样;结构体变量才包含实实在在的数据,才需要内存来存储。下面的写法是错误的,不可能去取一个结构体名的地址,也不能将它赋值给其他变量:

struct stu *pstu = &stu;  //错误
struct stu *pstu = stu;   //错误

2.枚举

【示例】判断用户输入的是星期几。

#include <stdio.h>
int main(){    
    enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun } day;    
    scanf("%d", &day);    
    switch(day){        
    case Mon: puts("Monday"); break;        
    case Tues: puts("Tuesday"); break;       
    case Wed: puts("Wednesday"); break;        
    case Thurs: puts("Thursday"); break;        case Fri: puts("Friday"); break;        
    case Sat: puts("Saturday"); break;        
    case Sun: puts("Sunday"); break;        default: puts("Error!");    }    
    return 0;
}

运行结果:
4↙
Thursday

需要注意的两点是:

  1. 枚举列表中的 Mon、Tues、Wed 这些标识符的作用范围是全局的(严格来说是 main() 函数内部),不能再定义与它们名字相同的变量。

  2. Mon、Tues、Wed 等都是常量,不能对它们赋值,只能将它们的值赋给其他的变量。

枚举和宏其实非常类似:宏在预处理阶段将名字替换成对应的值,枚举在编译阶段将名字替换成对应的值。我们可以将枚举理解为编译阶段的宏。

,Mon、Tues、Wed 等都不是变量,它们不占用数据区(常量区、全局数据区、栈区和堆区)的内存,而是直接被编译到命令里面,放到代码区,所以不能用&取得它们的地址。这就是枚举的本质。

3.共用体

结构体和共用体的区别在于:结构体的各个成员会占用不同的内存,互相之间没有影响;而共用体的所有成员占用同一段内存,修改一个成员会影响其余所有成员。

结构体占用的内存大于等于所有成员占用的内存之和(成员之间可能会存在缝隙),共用体占用的内存等于最长的成员占用的内存,修改一个成员会影响其余所有成员。共用体同一时刻只能保存一个成员的之,如果对新的成员赋值,就会把原来的值覆盖掉。

4.typedef与define区别

typedef 在表现上有时候类似于 #define,但它和宏替换之间存在一个关键性的区别。正确思考这个问题的方法就是把 typedef 看成一种彻底的“封装”类型,声明之后不能再往里面增加别的东西。

  1. 可以使用其他类型说明符对宏类型名进行扩展,但对 typedef 所定义的类型名却不能这样做。如下所示:
#define INTERGE int  
unsigned INTERGE n;  //没问题  
  
typedef int INTERGE;  
unsigned INTERGE n;  //错误,不能在 INTERGE 前面添加 unsigned
  1. 在连续定义几个变量的时候,typedef 能够保证定义的所有变量均为同一类型,而 #define 则无法保证。例如:
#define PTR_INT int *  
PTR_INT p1, p2;

经过宏替换以后,第二行变为:

int *p1, p2;

这使得 p1、p2 成为不同的类型:p1 是指向 int 类型的指针,p2 是 int 类型。

相反,在下面的代码中:

typedef int * PTR_INT  
PTR_INT p1, p2;

p1、p2 类型相同,它们都是指向 int 类型的指针。

5.const和指针

const 也可以和指针变量一起使用,这样可以限制指针变量本身,也可以限制指针指向的数据。const 和指针一起使用会有几种不同的顺序,如下所示:

const int *p1;
int const *p2;
int * const p3;

在前面两种情况下,指针所指向的数据是只读的,也就是 p1、p2 本身的值可以修改(指向不同的数据),但它们指向的数据不能被修改;在最后一种情况下,指针是只读的,也就是 p3 本身的值不能被修改。

当然,指针本身和它指向的数据都有可能是只读的,下面的两种写法能够做到这一点:

const int * const p4;
int const * const p5;

const 和指针结合的写法多少有点让初学者摸不着头脑,大家可以这样来记忆:const 离变量名近就是用来修饰指针变量的,离变量名远就是用来修饰指针指向的数据,如果近的和远的都有,那么就同时修饰指针变量以及它指向的数据。

5.fopen函数的打开方式

调用 fopen() 函数时必须指明读写权限,但是可以不指明读写方式(此时默认为"t")。

读写权限和读写方式可以组合使用,但是必须将读写方式放在读写权限的中间或者尾部(换句话说,不能将读写方式放在读写权限的开头)。例如:

  • 将读写方式放在读写权限的末尾:"rb"、"wt"、"ab"、"r+b"、"w+t"、"a+t"

  • 将读写方式放在读写权限的中间:"rb+"、"wt+"、"ab+"

整体来说,文件打开方式由 r、w、a、t、b、+ 六个字符拼成,各字符的含义是:

  • r(read):读
  • w(write):写
  • a(append):追加
  • t(text):文本文件
  • b(binary):二进制文件
  • +:读和写

5.1关闭文件

文件一旦使用完毕,应该用 fclose() 函数把文件关闭,以释放相关资源,避免数据丢失。fclose() 的用法为:

int fclose(FILE *fp);

fp 为文件指针。例如:

fclose(fp);

文件正常关闭时,fclose() 的返回值为0,如果返回非零值则表示有错误发生。

6.以数据块的形式读写文件(fread、fwrite)

示例:从键盘输入两个学生数据,写入一个文件中,再读出这两个学生的数据输出在屏幕上。

#include <stdio.h>

#define N 2

struct stu{
    char name[10];
    int num;
    int age;
    float score;
}boya[N], boyb[N], *pa, *pb;

int main{
    FILE *fp;
    int i;
    pa = boya;
    pb = boyb;
    if((fp = open("D:\\demo.txt", "wb+")) == NULL){
    puts("Fail to open file!\n");
    exit(0);
    }
    
    printf("Input data:\n");
    for(i = 0; i < N; i++, pa++){
        scanf("%s %d %d %f", pa->name, &pa->num, &pa->age, &pb->score);
    }
    
    fwrite(boya, sizeof(struct stu), N, fp);
    rewind(fp);
    fread(boyb, sizeof(struct stu), N, fp);
    
    for(i=0; i < N; i++, pb++){
        printf("%s %d %d %f", pb->name, pb->num, pb->age, pb->score);
    }
    
    fclose(fp);
    return 0;
}

问:用scanf输入数据,pa->name前面为什么不加取地址符&? 答:数组名本身就是首元素的地址。在结构体中,name是一个字符数组直接使用数组名就可以得到首元素的地址。

参考引用:c.biancheng.net/c/150/ c语言中文网