美文网首页
C语言复习(二)

C语言复习(二)

作者: Elijah_cs | 来源:发表于2019-07-09 13:44 被阅读0次

    字符串

    在C语言中,字符串实际上是使用null结尾的以为字符数组,因此,一个以null结尾的字符串,包含了组成字符串夫人字符,

    char greeting[6] = {'H','E','L','L','O','\0'};
    char greetin[] = "hello";

    在内存中的表示如图:


    char

    字符串操作函数:

    strcpy(s1,s2) //复制字符串s2到s1
    strcat(s1,s2) //链接s2到s1的末尾
    strlen(s1) //返回字符串的长度

    结构体

    定义结构:

    struct tag {
    member-list
    member-list
    ...
    } variable-list;
    

    tag是结构体标签,member-list是标准的变量定义,例如int i, variable-list结构变量,

    //此声明声明了拥有3个成员的结构体,分别为整型的a,字符型的b和双精度的c
    //同时又声明了结构体变量s1
    //这个结构体并没有标明其标签
    struct 
    {
        int a;
        char b;
        double c;
    } s1;
    //此声明声明了拥有3个成员的结构体,分别为整型的a,字符型的b和双精度的c
    //结构体的标签被命名为SIMPLE,没有声明变量
    struct SIMPLE
    {
        int a;
        char b;
        double c;
    };
    //用SIMPLE标签的结构体,另外声明了变量t1、t2、t3
    struct SIMPLE t1, t2[20], *t3;
    //也可以用typedef创建新类型
    typedef struct
    {
        int a;
        char b;
        double c; 
    } Simple2;
    //现在可以用Simple2作为类型声明新的结构体变量
    Simple2 u1, u2[20], *u3;
    

    在上面的声明中,第一个和第二声明被编译器当作两个完全不同的类型,即使他们的成员列表是一样的,如果令 t3=&s1,则是非法的。
    结构体的成员可以包含其他结构体,也可以包含指向自己结构体类型的指针,而通常这种指针的应用是为了实现一些更高级的数据结构如链表和树等。

    //此结构体的声明包含了其他的结构体
    struct COMPLEX
    {
        char string[100];
        struct SIMPLE a;
    };
    //此结构体的声明包含了指向自己类型的指针
    struct NODE
    {
        char string[100];
        struct NODE *next_node;
    };
    

    把结构体作为参数

    把结构作为函数参数,传参方式与其他类型的变量或指针类似

    struct tag
    {
    ...
    } ;
    void function(struct tag var_name); //引用结构体作为参数
     struct tag myData;
    function(myData);  //函数
    

    指向结构体体的指针

    结构体指针的声明:

    struct tag *stu_ptr;
    struct tag var;  //声明一个结构体变量
    stu_ptr = &var; //得到这个变量的地址,现在stu_ptr指向了var
    stu_ptr->data; //通过->来访问结构体的变量
    

    位域

    有些信息存储时,并不需要占用一个完整的字节,而只需要占用几个二进制位,可用位域来处理。
    位域的定义和结构体相类似:

    struct Tag_name
    {
    //类型说明符 位域名称:位域长度
    int a:8;
    in  b:2;
    ...
    } var_name;
    

    位域的储存

    • 一个位域储存在同一个字节,如果一个字节剩下的空间不够储存另一个位域时,则会从下一个单元储存该位域,也可以有意使得从某位域储存,例如
    struct bs{
        unsigned a:4;
        unsigned  :4;    /* 空域 ,作为填充或者调整位置 */
        unsigned b:4;    /* 从下一单元开始存放 */
    }
    //a占用4第一字节的前四位,后四位填充0表示不使用,b从第二个字节开始占用4位
    
    • 由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过8位二进位。如果最大长度大于计算机的整数字长,一些编译器可能会允许域的内存重叠,另外一些编译器可能会把大于一个域的部分存储在下一个字中
    • 位域的使用与结构体类似,也可以用指针,看demo:
    #include<stdlib.h>
    struct bs 
    {
        int flag:4;
        int b:2;
    };
    int main()
    {
        struct bs data,*ptr;
        data.flag = 15;
        data.b = 1;
        printf(" before %d %d\n",data.flag,data.b);
        ptr = &data;
        ptr->flag = 5;
        ptr->b = 0;
        printf("after %d %d\n",data.flag,data.b);
        return 0;
    }
    

    共用体

    共用体是一种特殊的数据结构,允许在相同的内存位置储存不同的数据类型,一个共用体带有多个成员,但是只有一个成员带有值,定义如下:

    union tag
    {
    member definition;
    ...
    member definition;
    }   var;
    //a example
    union Data
    {
    int i;
    float f;
    char str[20];
    } data;
    

    在这个共用体中,Data类型的变量可以储存一个整数,一个浮点数,或者一个字符串,该共用体占用的内存应该足够储存共用体最大的成员,即char str[20],dta数据将占用20个字节

    输入和输出

    scanf和printf时最基础的,还有getchar,putchar,gets,puts等。
    int getchar(void) 函数从屏幕读取下一个可用的字符,并把它返回为一个整数。这个函数在同一个时间内只会读取一个单一的字符。您可以在循环内使用这个方法,以便从屏幕上读取多个字符。
    int putchar(int c) 函数把字符输出到屏幕上,并返回相同的字符。这个函数在同一个时间内只会输出一个单一的字符。您可以在循环内使用这个方法,以便在屏幕上输出多个字符。
    char *gets(char *s) 函数从 stdin 读取一行到 s 所指向的缓冲区,直到一个终止符或 EOF。
    int puts(const char *s) 函数把字符串 s 和一个尾随的换行符写入到 stdout。

    递归

    递归指的是在函数的定义中使用函数自身的方法,语法格式如下:

    void recursion()
    {
    statement;
    ...
    recusion();  //函数调用自身
    statement;
    }
    int main()
    {
    recursion();
    }
    #include<stdio.h>
    #include<stdlib.h>
    int recursion(int dt)
    {
        if(dt == 1)
            return 1;
        else 
            return dt*recursion(dt-1);
    }
    int main()
    {
        printf("%d \n",recursion(3));
        return 0;
    }
    

    在使用递归的时候,一定要注意函数退出的条件!
    递归是一个简洁的概念,同时也是一种很有用的手段。但是,使用递归是要付出代价的。与直接的语句(如while循环)相比,递归函数会耗费更多的运行时间,并且要占用大量的栈空间。递归函数每次调用自身时,都需要把它的状态存到栈中,以便在它调用完自身后,程序可以返回到它原来的状态。未经精心设计的递归函数总是会带来麻烦。

    可变参数

    有时,可能会碰到这样的情况,希望函数带有可变数量的参数,而不是预定义数量的参数。C 语言为这种情况提供了一个解决方案:

    int func(int num,...)//num代表要传递的参数的个数
    {
    >...
    }
    int main()
    {
    func(2,3);
    func(2,3,4);
    }
    

    实现可变参数,需要使用stdarg.h头文件,步骤如下:

    • 定义一个函数,最后一个参数为省略号,省略号之前可以设置自定义参数
    • 在函数中创建一个va_list类型变量,该类型实在stdarg.h中定义的。
    • 使用int参数和va_start宏来初始化va_list变量为一个参数列表,宏va_start是在stdarg.h头文件定义的
    • 使用va_arg和va_list变量来访问参数列表的每个项
    • 使用va_end来清理赋予va_list的变量的内存
    #include<stdlib.h>
    #include<stdarg.h>
    double ave(int num, ...)
    {
        va_list valist;
        double sum = 0.0;
        int i;
        //为num个参数初始化
        va_start(valist,num);
        for(i = 0 ;i<num;i++)
        {
            sum+=va_arg(valist,int);
        }
        va_end(valist);
        return sum/num;
    }
    int main()
    {
        printf("ave : %f\n",ave(2,3,4));
        printf("ave : %f\n",ave(3,3,4,5));
        return 0;
    }
    

    内存管理

    C语言为内存的分配和管理提供了几个函数,定义在stdlib.h

    void calloc(int num,int size);
    //在内存中动态地分配 num 个长度为 size 的连续空间,并将每一个字节都初始化为 0。所以它的结果是分配了 num
    size 个字节长度的内存空间,并且每个字节的值都是0。
    void free(void *address);
    //该函数释放 address 所指向的内存块,释放的是动态分配的内存空间。
    void *malloc(int num);
    //在堆区分配一块指定大小的内存空间,用来存放数据。这块内存空间在函数执行完成后不会被初始化,它们的值是未知的
    void *realloc(void *address, int newsize);
    //该函数重新分配内存,把内存扩展到 newsize。
    注意:void * 类型表示未确定类型的指针. void * 类型可以通过类型转换强制转换为任何其它类型的指针

    命令行参数

    在执行程序的时候,可以从命令行传值给C程序,从main( int argc, char *argv[ ] ),其中argc是传入参数的个数,argv[] 是一个指针数组,指向传递给程序的每个参数,argv[0]是程序的名称,argv[1]是指向第一个参数的指针,argv[n]是最后一个参数

    #include<stdio.h>
    int main(int argc,char *argv[])
    {
        if(argc ==2 )
            printf("get a argument %s\n",argv[1]);
        else if(argc > 2)
            printf("more than 2 argment ");
        else
            printf("exit");
        return 0;
    }
    

    相关文章

      网友评论

          本文标题:C语言复习(二)

          本文链接:https://www.haomeiwen.com/subject/hnzahctx.html