[黑马IOS自学第七篇]fets文件函数等,结构体,结构体数组,宏学习

本文深入讲解C语言的基础知识,包括fgets函数的使用方法及其特点,const关键字的不同应用场景,内存管理的基本概念及动态内存分配的技巧,同时介绍了结构体、枚举类型等高级特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.fgets函数


 fgets不能进行格式化输出输入

 代码如下

<span style="font-size:18px;">//fgets()
    /*
    文件操作相关函数
    从键盘上接收一个字符串保存到数组中
    
    
     scanf()缺点不能接收空格 
     gets(str)优点 :可以接收空格
    
    */
    char str[10] ;
   fgets(str,sizeof(str),stdin);//安全的,输入的字符串长度大于
    puts(str);
    //数组长度时,会将最后一个元素变为\0
    /*
    12345678abcd
    12345678a
    */
    
    for (int i = 0; i < 10 ; i++) {
       printf("%d",str[i]);
    }
    /*
    如果只输入8个第九个元素为空格
    aaaaaaaa
    aaaaaaaa
    
    97 97 97 97 97 97 97 97 10 0
    
    */
    int len =strlen(str);//不包含\0如果少就包含空格所以整体字符大一个
    printf("%d\n",len);
    
    if (str[len-1]=='\n') {
       str[len-1]='\0';
    }
    for (int i = 0; i < 10 ; i++) {
       printf("%d",str[i]);
    }
    printf("\n");
    
   fputs(str,stdout);//不会自动换行
    printf("\n");
   puts(str);//带换行

    /*
    总结果:
    aaa
    aaa
    
    97 97 97 10 0 95 -1 127 0 0 4
    97 97 97 0 0 95 -1 127 0 0
    aaa
    
    */

    return 0;

</span>

 


2).const使用

 const int Mx =10;

    //常量read only

    int *p =&Mx;

   *p = 100 ;//强制修饰常量

    printf("Mx = %d , *p =%d\n",Mx,*p);

    //Mx = 10, *p = 100


    const int Mx =10;

    //常量read only

    

    int *p =&Mx;

    //intializingint * with an expression of type const       int * discards qulifier

   *p = 100 ;//强制修饰常量

    printf("Mx = %d , *p =%d\n",Mx,*p);

    //Mx = 10, *p = 100

    

    //主要是看const*的位置

    //1.const修饰的指针变量指向可变 const *左边

    int a = 10 ;

    int b = 20 ;

    const int *p1 =&a;

               p1=&b;//指向可以改变

    *p1=1000;//read-onlyvariable is not assignable

    //p1指向的变量的值是不能改变

    

    const int *p2 =&b;

              p2 =p ;

    *p2=1000;//read-onlyvariable is not assignable

    

    //2.const修饰的指针变量变量指向的变量值可以变,指向不能变

    //const *的右侧指向的值可以改变,指向不可以

    int * const p3 = &a;

    *p3 =2000 ;

    p3=&b;//read-onlyvariable is not assignable

    

    //3.指向和值都不能改变

    //const *的两侧

    const int * const p4 = &a;

    *p4 = &b;//read-onlyvariable is not assignable

    *p4 = 1000;//read-onlyvariable is not assignable

 


二.内存管理的基本概念

 


2).动态即是运行的时候分配的


   

 

  

 

3).动态内存分配的好处

1、当你定义了一个指针,而且要往里面写数据时,必须要动态分配内存给他。
2、动态分配的内存在堆上,你有权利决定什么时候将他释放掉。
3、动态分配的内存请记得一定要释放掉,不然容易引起内存泄露。

管理用户分配的内存空间


2).常见的动态内存分配函数

 


 int *p = (int*)malloc(4*sizeof(int));//从内存的堆区分配16个字节的内存空间
    if (p != NULL){
         *p = 10 ;
         *(p+1) = 100 ;
         *(p+2) = 1000 ;
         *(p+3) = 10000 ;
       printf("%p\n",p);
       printf("%p\n",p+1);
       printf("%p\n",p+2);
       printf("%p\n",p+3);
       
       for (inti = 0 ; i< 4; i++) {
           printf("%d\n",*(p+i));
       }
 
    }
    
    /*
    0x100100480
    0x100100484
    0x100100488
    0x10010048c
    10
    100
    1000
    10000
    */

3).野指针和内存泄露


 

   int *p = (int*)malloc(4*sizeof(int));

    //该句话会造成内存泄露

 

    free(p);//释放内存空间 free空间的首地址 p为野指针

    //p =NULL;

    *p =100;

    printf("%d\n",*p);

    //还是*p还是存放了地址可以进行访问

    //但是逻辑上不能让他继续访问此时要p = NULL

    //再访问就会报错

    

    return 0;

 

p释放之前,先释放堆区的内存空间

指针被释放后再去使用,指针已经不存在,也会成为野指针

 

4).free函数的使用


 

 

5).指针函数

int* max(int a,int b){
    //ab 在 *max分配的内存空间里形参新分配的空间和实参地址不一样
    
    printf("%p\n",&a);
    printf("%p\n",&b);
    //returna>b?&a:&b;
    return NULL;
    
}
int* max2(int*a ,int* b){
    //形参和实参地址不一样实参和形参是地址传递,没有分配新的空间
    
    printf("%p\n",a);
    printf("%p\n",b);
    return *a>*b?a:b;
    
}
int main(intargc,const char* argv[]) {
    
    
    int a = 3 ,b= 4;
    printf("a =%p\n",&a);
    printf("b =%p\n",&b);
    //int*p=max(a,b);
    int *p=max2(&a,&b);
    printf("%p\n",p);
    /*
    a = 0x7fff5fbff78c
    b = 0x7fff5fbff788
    0x7fff5fbff78c
    0x7fff5fbff788
    0x7fff5fbff788
    */
    return 0;
 
 
 
char *printDay2(intn ){
    
    char *printDay[20];
    
    switch (n) {
       case 1:
           *printDay="MONDAY";
           break;
       case 2:
           *printDay="TUESDAY";
           break;
       case 3:
           *printDay="WEDNESDAY";
           break;
       case 4:
           *printDay="THURSDAY";
           break;
       case 5:
           *printDay="FRIDAY";
           break;
       case 6:
           *printDay="SATURDAY";
           break;
       case 7:
           *printDay="SUNDAY";
           break;
           
       default:
           *printDay="输入错误!";
           break;
    }
    
    return *printDay;
    
    
    
}
int * getMax (int*arr ,int len){
    
    int max = *arr ;
    for (int i = 1;i<len; i++) {
       if (*(arr+i)>max) {
           max=*(arr+i);
       }
    }
    return &max;
    //addressof stack memory associated with local variable 'max' returned
}
int main(intargc,const char* argv[]) {
    
    int arr[10]={11,22,3230,444,533,62,7,83,9,22};
    printf("%s\n",printDay2(9));
    printf("%d\n",*(getMax(arr,10)));
    return 0;
}
 


6).函数指针


定义一个指针变量存放函数名的指针就叫函数指针

 

#include<stdio.h>
 
int sum(int a ,int b)
{
    return a + b ;
}
 
 
int main(intargc,const char* argv[]) {
   
    //定义函数指针可以不写形参
    int (*p1)(int ,int);
    //初始化函数指针
    p1=sum;
printf("%d\n",p1(2,3));
printf("%d\n",(*p1)(2,3));
  //5
    return 0;
}

三.构造类型

数组类型,结构体类型,共用体类型

结构体:由若干成员组成

结构体定义完成后,计算机并不会给结构体分配内存空间

会在定义结构体变量后,分配内存空间

#include<stdio.h>
#include<string.h>
//1.先定义结构体
struct Student{
    
    int sno ;
    char name[20];//char*name;
    char sex ;
    int age;
    float score ;
};
structStudentstud1,stud2,stud3;
 
//2.定义一个学生结构体
struct stu{
    
    int sno ;
    char name[20];//char*name;
    char sex ;
    int age;
    float score ;
}stud5,stud6,stud7;
 
//3.匿名结构体
struct{
    int sno ;
    char name[20];//char*name;
    char sex ;
    int age;
    float score ;
    
}stud8,stud9;
 
 int main(intargc,const char* argv[]) {
 
     //成员变量访问方法
     stud1.age= 10 ;
     //stud1.name="zhangsan";//arraytype 'char[20]' is not assignable
     strcpy(stud1.name,"zhangsan");
     stud1.sex='M';
     printf("%s\n",stud1.name);
     
     //stud1.name占用多少字节
     printf("%ld\n",sizeof(stud1.name));
     //utf-8国际通用编码 xcode默认的中文编码一个汉字占用3字节
     //gb2312 gbk国际一个汉字占两字节
     //stud1.name 字符串长度
      printf("%ld\n",strlen(stud1.name));
     
     
     
     //1.结构体初始化
    //stud2={12,"zhangsans",'F',18,90.3f}; //expected expression
 
     struct Studentstud10={12,"zhangsans",'F',18,90.3f};
     
     
     //2.指定元素初始化
     struct Studentstud11={.name="zhangsans"};

2).结构体数据成员对齐的意义

 

 3).结构体对齐的含义




 4).内存之间大小的倍数,结构体大小的计算方法和步骤

 



#include<stdio.h>
struct Student{
    
    int sno ;//4
    char sex ;//1
    float score ;//4
};
struct Student2{
    
    short sno ;//2
    char sex ;//1
    float score ;//4
};
struct Student3{
    
    short sno ;//2
    char sex ;//1
    float score ;//4
    double d;//8
};
struct Student4{
    
    
   char sex[13] ;//4 16还空余3个
    char score[13] ;//3 12(12个字节实际存储10个)
    int d;//4
};
int main(intargc,const char* argv[]) {
   
    
    struct Studentstd1;
    printf("%ld\n",sizeof(std1));//12
    //计算结构变量再内存中占用的字节数的方法
    //1.先找对其模数,结构体变量中基本数据类型占字节数最大的那个
    //2.在计算结构体变量中各个成员占用字节和
    
    struct Student2std2;
    printf("%ld\n",sizeof(std2));//8
    
    struct Student3std3;
    printf("%ld\n",sizeof(std3));//16
    //double的位置如果在float之上结果为24
    
    
    struct Student4std4;
    printf("%ld\n",sizeof(std4));//32
    return 0;
}


函数外部定义的结构体类型类似全局变量

 全局作用域:从自定义的哪一行开始直到本文件结束为止


5).作用域分类

结构体根据作用于可以分为全局结构体,局部结构体

局部变量的结构体会覆盖全局的


6).结构体数组定义



#include<stdio.h>
#define LEN5
struct person {
    
    char name[8] ;
    char telNum[12];
    
};
int main(intargc,const char* argv[]) {
    
  
    struct personcontacts[LEN];
    
    for (int i = 0; i < LEN ; i++) {
       scanf("%s%s",contacts[i].name,contacts[i].telNum);
    }
    
    for (int i = 0; i < LEN ; i++) {
       printf("姓名:%s,电话:%s\n",contacts[i].name,contacts[i].telNum);
    }
 
    
    
    return 0;
}
 


 

 7).指向结构体变量的指针



8).指针访问结构变量属于间接访问

 

#include<stdio.h>
#include<string.h>
struct person// struct是关键字  person是结构体名
{
    
    char name[8] ;
    char telNum[12];
    char *id;
    int age ;
    
}per1; //结构体变量名
 
int main(intargc,const char* argv[]) {
    
    
   structperson *p = &per1;//p是结构体指针
    //结构体指针间接访问成员值的方法
    //1).(*p).age; (*p)相当于per1
    //2).p->agep是结构体指针的时候写法
    (*p).age =10;
    (*p).id="2332";
    strcpy(p->name,"sdsd");
   // strcpy((*p).name,"sdsd");
    printf("%s\n",(*p).name);
    //incompatiblepointer to integer conversion to 'char' from char[5]
   //(*p)->age =100;
    //memberreference type 'struct person' is not a pointer ,maybe you
    //meant touse '.' to fix it
    return 0;
}


// main.c
// 结构体嵌套
//
// Created by CHINGWEI_MACPC on 15/11/6.
//  Copyright © 2015年 itcast. All rights reserved.
//
 
#include<stdio.h>
struct Time {
    
    int hour ;
    int second ;
    int minite ;
};
struct Date
{
    
    int month;
    int day ;
    int year ;
    struct Timetime ;
    
};
struct Student
{
    
    char name[8] ;
    int age ;
    float score ;
    struct Datebirthday;
    
    //可以嵌套自己类型的结构体指针
   //struct Student stu; //错误书写
    //structStudent *stu;
 
};
 
 
int main(intargc,const char* argv[]) {
 
    struct Studentstu1={"mike",18,89.5f,{2,12,2006,{10,23,13}}};
    printf("姓名:%s,年龄:%d,成绩:%f,生日:%02d/%02d/%d,时间:%02dh:%02dm:%ds\n",
          stu1.name,stu1.age,stu1.score,stu1.birthday.day
           ,stu1.birthday.month,stu1.birthday.year,stu1.birthday.time.hour,stu1.birthday.time.minite,stu1.birthday.time.second);
    
    
    struct Person// struct 是关键字 person是结构体名
    {
       
       char name[8] ;
       int age ;
       
       struct Person*children;
       
    };
    //结构体嵌套指针的使用
    struct Personkim={"kim",20,NULL};
    
   structPerson p1 ={"小白",38,&kim};
    
   structPerson p2 ={"小白",38,&kim};
    
    printf("名字:%s,年纪:%d,儿子:%s\n",p1.name,p1.age,(*p1.children).name);
   
    //便于理解方法2 p2.children->name
    printf("名字:%s,年纪:%d,儿子:%s\n",p2.name,p2.age,p2.children->name);
    
    return 0;
}
 


结构体成员值作为函数参数



#include<stdio.h>
struct Student
{
    
    char name[8] ;
    float score ;
    
};
void xiugai(floatscore )
{
   score=2.2f;
}
void printScore(structStudent stu)
{
    
    stu.score=2.2f;
    
    
}
int main(intargc,const char* argv[]) {
   
    struct Studentstu1={"liu",12.3f};
    
    //1.结构体成员变量的成员值作为函数参数是值传递
    xiugai(stu1.score);
    printf("%s,%f\n",stu1.name,stu1.score);
    
    //2.用结构体变量作为函数的参数也是值传递
    printScore(stu1);
    printf("%s,%f\n",stu1.name,stu1.score);
    return 0;
}

结构体指针作为函数参数

将地址传递给函数

#include<stdio.h>
struct Student
{
    
    char name[8] ;
    float score ;
    
};
void printScore(structStudent *stu)
{
    
    (*stu).score=2.2f;
    
    
}
int main(intargc,const char* argv[]) {
    struct Studentstu1={"liu",12.3f};
    //liu,2.200000
    printScore(&stu1);
    printf("%s,%f\n",stu1.name,stu1.score);
    
    
    return 0;
}

枚举类型,基本数据类型,不是构造类型,因为不能再分解为任何基本类型


 

#include<stdio.h>
enumweek2{KMon1,KTue1,KWed1=5,KThur1,KFri1,KSta1,KSun1};
int main(intargc,const char* argv[]) {
    
    
    //定义变量 1.
    enum week1{KMon,KTue,KWed,KThur,KFri,KSta,KSun}iWeek1;
    //纠正型变量
    //2.
    enum week2iWeek2;
    
   //赋值
    iWeek1=KMon;//0
    iWeek2=KFri1;//7
    printf("%d\n",iWeek1);
    printf("%d\n",iWeek2);
    return 0;
}
 
 
#include<stdio.h>
int sum(int a ,int b ){
    
    return a+b;
}
int main(intargc,const char* argv[]) {
    
   
    //1.基本数据类型
    typedef intINTERGER;
    
    //2.用在数组,给数组起别名
   typedefint ARRAY[5];//相当于
    ARRAY arr1 ={5,4,5,6,7};
    for (int i = 0; i < 5 ; i++) {
       printf("%d\n",arr1[i]);
    }
    //3.给结构体起别名 1)
    struct Person {
       int age ;
       char *name;
       
    };
    typedef struct Person P;
    P person2={22,"nmle"};
    printf("%d,%s\n",person2.age,person2.name);
    
    //3.给结构体起别名 2)
    typedef struct Car {
       int age ;
       char *name;
       
    }MYCAR;
    MYCAR car1 = {22,"sdsd"};
    printf("%d,%s\n",car1.age,car1.name);
 
     //3.给结构体起别名 3)
    typedef struct  {
       int age ;
       char *name;
       
    }IPHONE;
    IPHONE iP = {22,"sdsd"};
    printf("%d,%s\n",iP.age,iP.name);
    
    //4.给枚举起别名
    //
    typedef enumSex{Kse1,Kse2,Kse3}Isex;
    
    typedef enum  {Kw3,Kw2,Kw1}weekday;
    
    typedef enum Sex S ;
    
    S s1 ,s2;
    
    s1=Kse2;
    s2=Kse3;
    
   //5.给函数指针
   
    typedef int(*FUN)(int,int);
    FUN f1,f2;
    f1=sum;
    f2=sum;
    printf("%d\n",f1(2,3));
    printf("%d\n",f2(4,3));
  
    return 0;
}
 


预处理命令编译之前的工作

#开头的预处理命令

无参宏定义方法


 

#include<stdio.h>
#define LEN5
#define X (x*y+2*3)//最好加一个括号
#define Y  x*y+2*3
 
#define PI3.14
#define R4 
#define AREA PI*R*R//宏的嵌套
#define INT1 int//起别名
 
int main(intargc,const char* argv[]) {
   
   #undef LEN
    int a[R+4];//int a[6]
    int x=1 ,y=1;
    //1.宏的作用域 #undef宏名取消宏定义
    printf("X*X = %d\n",X*X);//49
    printf("Y*Y = %d\n",Y*Y);//13
    
    
    //2.宏的嵌套
    printf("%.f\n",AREA);
    
    
    //3.起别名
    INT1 a1 = 12;
    printf("a1 = %d\n",a1);
    return 0;
}
 
无参数宏
#include<stdio.h>
#defineMAX(x,y) x+y
#defineequaL(m,n) m=x+y;n=x*y;
//1.宏名和形参之间不能有空格
int main(intargc,const char* argv[]) {
    // insertcode here...
    int r = 1 ;
    printf("%d\n",MAX(r, r));//2
    
    
    int x = 2 , y =3;
    int i ,j ;
    equaL(i, j);//4
    //         a+3+y,a-1+y
    printf("%d,%d\n",i,j);
    
    return 0;
}
 
 
// 有参宏应用
 
#include<stdio.h>
#defineMAX(a,b) a>b?a:b
int main(intargc,const char* argv[]) {
   
    
    printf("Max(32,444)=%d\n",MAX(32, 444));
    return 0;
}
 
 
//  typedef和define的区别
//
// Created by CHINGWEI_MACPC on 15/11/9.
//  Copyright © 2015年 itcast. All rights reserved.
//
 
#include<stdio.h>
#defineINT1 int 
typedefint INT2;
#defineINT3 int*
typedefint* INT4;
int main(intargc,const char* argv[]) {
    //宏定义变量
    int num = 10;
    INT1 a ,b ;
    a=10;
    b=10;
    printf("a = %d\n",a);
    
    //别名定义变量
    INT2 a1,b1;
    a1=100;
    b1=100;
    printf("a1 = %d\n",a1);
    
    //宏定义变量
    INT3 a3 ,b3 ;//只有 int *a3, 只有a3是指针变量
   a3=#
    b3=num;
    printf("a3 = %d,b3=%d\n",*a3,b3);
    
    //别名定义变量
    INT4 a4,b4;//a4,b4都是指针变量
   a4=#
   b4=#
    printf("a4 = %d,b4=%d\n",*a4,*b4);
    
    
    
    return 0;
}


 

 

  条件编译:

       发生在预处理阶段,在编译之前做的事情

       

       核心:根据条件编译指定的代码

       条件不同:编译的部分也不同,生成的目标文件也不同 .o大小不同

 

 */

#include<stdio.h>
#define  score100
int main(intargc,const char* argv[]) {
#if  score <60
    printf("Grade :F");
#elif score <=69
    printf("Grade : D");
#elif score <=79
    printf("Grade : C");
#elif score <=89
    printf("Grade : B");
#else
    printf("Grade : A");
#endif
    printf("\n");
    return 0;
}

 

 

只编译一部分,


 



 
// 条件编译指令
//
// Created by CHINGWEI_MACPC on 15/11/9.
//  Copyright © 2015年 itcast. All rights reserved.
//
 
#include<stdio.h>
#define DEBUG11
int main(intargc,const char* argv[]) {
    int a =0 ;
#ifdefDEBUG1
    a = 10 ;
#else
    a=10000;
#endif
    printf("%d\n",a);
    printf("%d\n",DEBUG);
#ifndef DEBUG2//如果没有定义宏
    a= 100 ;
#else
    a=-1;
#endif
    printf("%d\n",a);
    return 0;
}
 
 
 
#include<stdio.h>
#define DEBUG11
#if DEBUG1 ==1
//显示调试信息
#defineLog(format,...) printf(format,## __VA_ARGS__);
//...表示可变参数          //##可以有一个或者多个
#else
//不显示调试信息
#defineLog(format,...);
#endif
 
void test2(){
    
    Log("test------->%-5.2f ,%d,%d\n",10.3f,3,30);
}
void test(){
    
    Log("test ----- >%d\n",10);
}
int main(intargc,const char* argv[]) {
    
    Log("xxxxxxx----->%d\n",10);
    test();
    test2();
    return 0;
}
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值