重学C语言之计算机二级准备(下)

结构体与共同体:

typedef说明一个新类型:作用是为一种数据类型定义新的名字,不可以创建新的类型;

  1. 与#define不同,typedef仅限于数据类型,而不是能是表达式或具体的值
  2. #define发生在预处理,typedef发生在编译阶段

结构体变量的定义和初始化: 

//结构体定义格式:

结构体 结构体名称

{

            结构体成员列表 (可以是不同数据类型 基本类型 构造类型 指针类型)

}; 

三种方式:

1、先声明结构体类型再定义变量名 struct stu{};  struct stu Mike

2、在声明类型的同时定义变量 struct stu{}Mike; 

3、直接定义结构体类型变量(无类型名)struct  {}Mike;

结构体成员的使用

struct stu s1;  strcpy(s1.name,"abc"); s1.age = 18;printf("s1.name = %s, s1.age = %d\n", s1.name, s1.age);

//指针变量的方式:

struct stu s1; strcpy((&s1)->name,"test"); (&s1)->age = 22;printf("s1.name = %s, s1.age = %d\n", (&s1)->name, (&s1)->age);

结构体数组:

struct stu boy[5] = { 。。。结构体成员内容}; //结构体数组的初始化

//结构体数组成员的打印输出

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

{

printf(" name=%s,  score=%f\n", boy[i].name, boy[i].score);

// printf(" name=%s,  score=%f\n", (boy+i)->name, (boy+i)->score);

}

void BubbleSort(student * ss,int len)

{
        int
i , j =0;

        student temp;

        for(i = 0;i < len -1;i++)

            {          for(j = 0;j < len - i -1;j++)

                                {

                                        temp = ss[j];

                                        ss[j] = ss[j+1];

                                        ss[j+1] =temp;

                        }

}

}

结构体的嵌套使用:

// struct 技能  (格式)

{名称 伤害 范围 效果 等待时间}

// struct 人物信息

{ 等级 经验 MP HP struct 技能 skill[4] ;}

struct person

{

char name[20];

char sex;

};

struct stu

{

int id;

struct person info;

};

共用体(union)

  1. 联合union是一个能在同一个存储空间存储不同类型数据的类型;
  2. 联合体所占的内存长度等于其最长成员的长度倍数,也有叫做共用体;
  3. 同一内存段可以用来存放几种不同类型的成员,但每一瞬时只有一种起作用;
  4. 共用体变量中起作用的成员是最后一次存放的成员,在存入一个新的成员后原有的成员的值会被覆盖;
  5. 共用体变量的地址和它的各成员的地址都是同一地址

union TEST{ int a,float b, char c};//定义共用体变量 union TEST tmp; 

printf("%p, %p, %p\n", &(tmp.a), &(tmp.b), &(tmp.c));

printf("%lu\n", sizeof(union Test));//共用体大小为最大成员类型的大小

//一个成员赋值会影响带动其它成员的值

链表:

链表无需一次性分配一块连续的存储空间,只需分配N块节点的存储区域,通过两个指针建立关系;(便于插入和删除某个元素)

typedef strcut _LINKNODE{ int id ;//数据域struct _LINKNODE* next;//指针域}linknode;

链表的初始化:

link_node* init_linklist(){

//创建头结点指针

link_node* head = NULL;

//给头结点分配内存

head = (link_node*)malloc(sizeof(link_node));

if (head == NULL){

return NULL;

}

head->data = -1;

head->next = NULL;

//保存当前节点

link_node* p_current = head;

int data = -1;

//循环向链表中插入节点

while (1){

printf("please input data:\n");

scanf("%d",&data);

//如果输入-1,则退出循环

if (data == -1){

break;

}

//给新节点分配内存

link_node* newnode = (link_node*)malloc(sizeof(link_node));

if (newnode == NULL){

break;

}

//给节点赋值

newnode->data = data;

newnode->next = NULL;

//新节点入链表,也就是将节点插入到最后一个节点的下一个位置

p_current->next = newnode;

//更新辅助指针p_current

p_current = newnode;

}

遍历链表:

顺序输出单向链表各项结点数据域中的内容:

if(head == NULL)
    {
        return;
    }
    link_node*p_current1 = head->next;
    while(p_current1 != NULL)
    {
        printf("%d ",p_current1->data);
        p_current1 = p_current1->next;
    }
    printf("\n");

插入节点:

void insert_linklist(link_node* head,int val,int data)

if (head == NULL){

return;

}

//两个辅助指针

link_node* p_prev = head;

link_node* p_current = p_prev->next;

while (p_current != NULL){

if (p_current->data == val){

break;

}

p_prev = p_current;

p_current = p_prev->next;

}

//如果p_current为NULL,说明不存在值为val的节点

if (p_current == NULL){

printf("不存在值为%d的节点!\n",val);

return;

}

//创建新的节点

link_node* newnode = (link_node*)malloc(sizeof(link_node));

newnode->data = data;

newnode->next = NULL;

//新节点入链表

newnode->next = p_current;

p_prev->next = newnode;

删除节点:

void remove_link(link_node*head,int val)

    if(head == NULL)
    {
        return ;
     } 
     link_node* p_pre = head;
     link_node* p_cur = p_pre->next;
     while(p_cur != NULL)
     {
         if(p_cur->data == val)
         {
             break;
         }
         p_pre = p_cur;
         p_cur = p_pre->next;
     }
     if(p_cur == NULL)
     {
         return;
     }
     p_pre->next = p_cur->next;
     free(p_cur);

位运算:

  1. 与运算(&)(AND):对两个操作数的每一位进行与操作,只有当两位都为1时,结果才为1,否则为0。

  2. 或运算(|)(OR):对两个操作数的每一位进行或操作,只有当两位都为0时,结果才为0,否则为1。

  3. 异或运算(^)(XOR):对两个操作数的每一位进行异或操作,当两位相同时,结果为0;当两位不同时,结果为1。

  4. 取反运算(~)(NOT):对操作数的每一位进行取反操作,即将0变为1,将1变为0。

  5. 左移运算(<<):将操作数的二进制数向左移动指定的位数,右侧空出的位置用0填充。

  6. 右移运算(>>):将操作数的二进制数向右移动指定的位数,左侧空出的位置用符号位填充(如果是有符号数),或者用0填充(如果是无符号数)。

位移运算符:

左移运算符:相当于函数去乘以2来运算 例如:从二进制来看 10 << 1  0000 1010 —— 00010100 

右移运算符:相当于函数去除以2来运算;

位运算的应用:通过异或来改变交换a和b的值例如:a=10,b=20

传统方式:temp = a; a = b;b = temp; 

位运算:a = a^b; b = a^b; a=a^b;  

位运算赋值运算符:

位运算和赋值运算符可以组合成复合赋值运算符,如:&=,|=,>>=,<<=,^=等等,a>>=2相当于a = a>>2.      

文件操作:

在C语言中用一个指针变量指向一个文件,这个指针称为文件指针。

FILE是系统使用typedef定义出来的有关文件信息的一种结构体类型结构中含有文件名、文件状态和文件当前位置等信息

文件的打开与关闭:

第一个参数的相对路径:文件名称加扩展名;fopen(“passwd.txt”,“r”);

//打开当前目录(test)下的文件:  fopen(“./test/passwd.txt”,“r”);

//打开当前目录上一级目录(相对当前目录)passwd.txt文件 fopen(“../passwd.txt”,"r");

//绝对路径:打开C盘test目录下一个叫passwd.txt文件  fopen(“C:/test/passwd.txt”,“r”);

打开模式

含义

r或rb

以只读方式打开一个文本文件(不创建文件,若文件不存在则报错)

w或wb

以写方式打开文件(如果文件存在则清空文件,文件不存在则创建一个文件)

a或ab

以追加方式打开文件,在末尾添加内容,若文件不存在则创建文件

r+或rb+

以可读、可写的方式打开文件(不创建新文件)

w+或wb+

以可读、可写的方式打开文件(如果文件存在则清空文件,文件不存在则创建一个文件)

a+或ab+

以添加方式打开文件,打开文件并在末尾更改文件,若文件不存在则创建文件

文件的关闭: fclose(FILE *fp);关闭先前fopen()打开的文件。此动作让缓冲区的数据写入文件中,并释放系统所提供的文件资源。

FILE * fp = NULL;

fp = fopen("abc.txt", "r");

fclose(fp);

文件的读写:

写文件:int fputc(int ch,FILE*stream);将ch转换为unsigned char后写入stream指定的文件中

    FILE *fp;
    fp = fopen("abc.txt","w");
    if(fp == NULL)
    {
        printf("open test fail!\n");
        return EOF; 
    }
    char buf[]="this is a Test"; 
    int i = 0;
    int n = strlen(buf);
    for(i=0;i<n;i++)
    {
        int ch = fputc(buf[i],fp);
        printf("ch=%c\n",ch);
    }
    fclose(fp);
    return 0;

读文件:  int fgetc(FILE *fp);

    char ch;
    while ((ch = fgetc(fp)) != EOF)
    {
    printf("%c", ch);
    }
    printf("\n");    
    fclose(fp);

int fputs(const char*str,FILE*stream)将str所指定的字符串写入到stream指定的文件中,字符串结束符 '\0'  不写入文件。
char*fgets(char*str,int size,FILE*stream);从stream指定的文件内读入字符,保存到str所指定的内存空间,直到出现换行字符、读到文件结尾或是已读了size - 1个字符为止,最后会自动加上字符
'\0' 作为字符串结束。

char buf[100] = 0;char *p = fgets(buf, sizeof(buf), fp);

文件结尾:

EOF表示文件结束符(end of file)。在while循环中以EOF作为文件结束标志,这种以EOF作为文件结束标志的文件,必须是文本文件。在文本文件中,数据都是以字符的ASCII代码值的形式存放。我们知道,ASCII代码值的范围是0~127,不可能出现-1,因此可以用EOF作为文件结束标志

按照格式化文件 fprintf fscanf

fprintf(fp,"%d %d %d\n",1,2,3);根据参数format字符串来转换并格式化数据,然后将结果输出到stream指定的文件中,指定出现字符串结束符 '\0'  为止。

fscanf(fp,"%d %d %d\n",&a,&b,&c);从stream指定的文件读取字符串,并根据参数format字符串来转换并格式化数据。

按照块读写文件fread、fwrite

fwrite:unsigned int  fwrite(const void*ptr,unsigned int size,unsigned int nmemb,FILE *fp);

ptr:准备写入文件数据的地址

size: 此参数指定写入文件内容的块数据大小

nmemb:写入文件的块数,写入文件数据总大小为:size * nmemb

stream:已经打开的文件指针

fread:unsigned int  fread(const void*ptr,unsigned int size,unsigned int nmemb,FILE *fp);

ptr:存放读取出来数据的内存空间

size: 此参数指定读取文件内容的块数据大小

nmemb:读取文件的块数,读取文件数据总大小为:size * nmemb

stream:已经打开的文件指针

返回值:

成功:实际成功读取到内容的块数,如果此值比nmemb小,但大于0,说明读到文件的结尾。

文件的定位:

int fseek(FILE *stream, long offset, int whence);移动文件流(文件光标)的读写位置;

stream:已经打开的文件指针

offset:根据whence来移动的位移数(偏移量),可以是正数,也可以负数,如果正数,则相对于whence往右移动,如果是负数,则相对于whence往左移动。如果向前移动的字节数超过了文件开头则出错返回,如果向后移动的字节数超过了文件末尾,再次写入时将增大文件尺寸。

whence:其取值如下:

SEEK_SET:从文件开头移动offset个字节

SEEK_CUR:从当前位置移动offset个字节

SEEK_END:从文件末尾移动offset个字节

long ftell(FILE *stream);获取文件流(文件光标)的读写位置。

void rewind(FILE *stream);把文件流(文件光标)的读写位置移动到文件开头

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MAX梁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值