C

作者: 放肆滴微笑 | 来源:发表于2019-12-15 22:26 被阅读0次

    C 99 据说是1999年所定义的

    引入头文件

    里面只有函数的声明,没有实现,编译的时候,会去对应的so文件找到函数的实现

    #include <stdio.h>
    

    基本数据类型

    有符号(默认定义变量就是有符号)和无符号
    signed 有符号 unsigned无符号

    • int %d
    • short
    • long
    • float
    • double
    • char
    • bool 非0 就是true 0是flase 非Null就是true 等于null就是false
    类型 占位 字节
    short %d 2
    int %d 4
    long %ld 4
    float %f 4
    double %lf 8
    char %c 1
    字符串 %s
    十六进制 %x
    八进制 %o

    为什么 int 和 long 一模一样长,还有这两者的出现呢?
    答:long类型 和 int类型,在早期16为电脑的时候 int是2字节,long是4字节,而计算机经过多年的发展,一般是32位,64位,就造成了int 和 long一样长了,如果想使用8位 则可以long long xxx 这样声明

    使用sizeof来运算获得类型在不同平台准确字节

    double d = 1.12342;
    printf("double 字节%d\n", sizeof(d));
    

    如果只取小数点后2位,只需要在%f前面加上.2

    long double ld01 = 16.123456;
    printf("ld01=%.2f,字节:%d\n", ld01, sizeof(ld01));
    

    vim xxx.c 创建一个文件

    编译c文件

    gcc xxx.c -o xxx
    

    字符串

    字符串的拼接,需要定义一个数组

        char strChar[200];
        sprintf(strChar,"今天是%d号\n",11); // 拼接到char 数组
        printf("%s\n",strChar);
    

    数组

    1、格式是这样的(array[] = {},array[6] = ),不能这样([] array)
    2、必须给定 数组的大小,或者直接初始化

    • 数组是一块连续的内存空间
    • 数组内存地址和数组首位内存地址一样
    int test[8];
    int test[]={1,2,3,4,5};
    

    for循环数组

        int test[] = {1,3,4,2,4};
    
        printf("数组首位地址:%#x\n",test);
        for (int i=0;i< sizeof(test)/ sizeof(int);i++) {
            printf("内存地址:%#x\n", (test + i));
            printf("内存地址对应的值:%x\n", * (test + i));
        }
    
    
    数组首位地址:0x5f19f5f0
    内存地址:0x5f19f5f0
    内存地址:0x5f19f5f4
    内存地址:0x5f19f5f8
    内存地址:0x5f19f5fc
    内存地址:0x5f19f600
    

    动态内存申请 只要是动态内存申请,则在堆取,剩下的都在栈区

        calloc 
        需要头文件
        #include <stdbool.h>
    
         //在堆中申请 10个int类型的内存空间,也就是10*4 = 40字节
        int *p = calloc(10, sizeof(int));
        // 清空内存,因为内存可能是别人剩下的,里面还会有原来的值
        memset(p, NULL, 10 * sizeof(int));
        
        //释放堆内存,申请了,用完要释放
        free(p); 
        // 这个时候p 属于野指针,可以让p = 0 或者 null
        p = NULL;
    

    C 和 C++ ?

    C面向过程,一个一个的函数,没有类,没有面向对象
    C++面向对象 思想和 Java的一模一样,开始有类

    字符串

    使用字符数组存储字符串

    //字符数组    
    char str[] = {'c', 'h', 'i', 'n', 'a', '\0'};   // 后面写0,就能结束
    char str1[6] = {'c', 'h', 'i', 'n', 'a'};   // 直接写6个大小,字符5位,第6位就是0
    char str2[10]="china";  // 直接双引号就是字符串
    str[0]='w';
    str1[0]='w';
    str2[0]='w';
    printf("str %s\n", str);
    printf("str1 %s\n", str1);
    printf("str2 %s\n", str2);
    -------------------------------------
    str whina
    str1 whina
    str2 whina
    

    使用字符指针

    char *str = "i XXX";
    printf("*str %s\n",str);
    
    *str i XXX
    

    字符串指针和数组字符串 区别,字符串指针不能修改内存,数组可以

    内存分配

    C里面内存分配分为静态内存和动态内存
    静态内存放在栈中,一般比较小,比如几M(存放确定的常数)自动释放,超过会有stack overflow错误,如

    int a[1024 * 1024 * 10];
    

    动态内存放在堆中,大小为内存的80%,程序员手动释放
    创建一个数组,动态指定数组的大小,相当于java的集合

    • 静态内存分配,分配内存大小是固定的。
      问题:1、容易超出栈内存的最大值,从而stack overflow错误
      2、为了防止内存不够用,会开辟更多的内存,容易浪费内存
    • 动态内存分配,在程序运行过程中,动态内存需要指定内存大小,手动释放,释放后还可以继续使用

    动态创建一个数组

        int len;
        printf("输入一个长度");
        scanf("%d", &len);
        int *p = malloc(len * sizeof(int));
    
        int i = 0;
        for (; i < len; i++) {
            *(p + i) = rand() % 100;
            printf("p==%d---%#x\n", p[i], &p[i]);
        }
    
    
    输入一个长度5
    p==7---0x38500000
    p==49---0x38500004
    p==73---0x38500008
    p==58---0x3850000c
    p==30---0x38500010
    

    动态创建数组,并改变数组的大小,
    存在问题,
    1、缩小数组大小(内存),缩小的数据会丢失
    2、扩大,内存会是连续的
    3、扩大,1.如果当前内存段后面有需要扩大的空间,直接扩展这段内存空间,realloc返回的指针,地址也是原指针的地址
    2.如果当前内存段后面空间不够需要扩大的空间,那么就使用堆后面第一个能够满足这一要求的内存块,将目前的数据复制到新的位置,并将原来的数据释放掉,返回新的内存地址
    3.如果申请失败,返回NULL,原来的指针仍然有效

    int len;
        printf("输入一个长度");
        scanf("%d", &len);
        int *p = malloc(len * sizeof(int));
    
        int i = 0;
        for (; i < len; i++) {
            *(p + i) = rand() % 100;
            printf("p==%d---%#x\n", p[i], &p[i]);
        }
    
        int len2;
        printf("输入一个长度");
        scanf("%d", &len2);
        int *p2 = realloc(p, (len + len2) * sizeof(int));
        i = 0;
        for (; i < len + len2; i++) {
            *(p2 + i) = rand() % 100;
            printf("p==%d---%#x\n", p2[i], &p2[i]);
        }
    
    //p 不用再释放了,因为p2释放了,p也就释放了,p2本来就是对p的重新增长
        //if (p != NULL) {
          //  free(p);
            //p = NULL;
        //}
        if (p2 != NULL) {
            free(p2);
            p2 = NULL;
        }
    
    输入一个长度5
    p==7---0x38500000
    p==49---0x38500004
    p==73---0x38500008
    p==58---0x3850000c
    p==30---0x38500010
    输入一个长度3
    p==72---0x38500000
    p==44---0x38500004
    p==78---0x38500008
    p==23---0x3850000c
    p==9---0x38500010
    p==40---0x38500014
    p==65---0x38500018
    p==92---0x3850001c
    

    内存分配细节

    • 不能多次释放同一个指针,
    • 释放完后,指针仍然有值,需要给指针=NULL
    • 内存泄露,获取到的内存,如果需要再赋值,需要再赋值前进行free,要不相当于内存没有释放,系统认为还在使用
        int *p1 = malloc(1024 * 1024 * sizeof(int));
        free(p1); // 需要释放
        p1 = NULL;
        printf("p1 = %#x\n",p1);
        p1 = malloc(1024 * 1024 * sizeof(int) * 2); // 重新赋值
        printf("p1 = %#x\n",p1);
        free(p1);
        p1 = NULL;
    

    头文件 .h文件,对外暴露 #include ""引入的是目录下可以看到的自己写的<>引入系统C配置的环境

    引入头文件后,在.c文件中写头文件的函数,会有左右切换的符号,可以和头文件和当前写的文件进行交换。


    image.png

    之后再使用这个头文件,就直接在使用地方引入头文件,调用会调用实现头文件的.c文件
    include 并不等于卷的import java.lang.String。
    而是将include <xxx.h> 里的所有代码都复制一遍,放到include的地方。
    所以如果不用就不要调用不用的h文件,要不会造成体积增大,在预处理器阶段就完成了,还不到编译器就结束了

    宏 可以理解为java中的常量

    宏不需要分号结尾

    #define NAME "wx"
    

    预处理器,代码的指向流程,可以作为代码块选择 或者 注释使用

    if 和 #endif配套

    void main() {
    #define NAME "wx"
    
    #if 0   // 非0 是true  0就是false  所以打印else if 但是预编译就直接有颜色显示
        printf("打印 if \n");
    #else if
        printf("打印 else if \n");
    #endif   // 一定会执行
        printf("打印 endif \n");
    }
    
    
    打印 else if 
    打印 endif 
    
    image.png

    配合宏

    #define DEBUG
    
        //ifdef 表示有定义   ifndef 表示没有定义 n == not
    #ifdef DEBUG
        printf("配合宏,有定义DEBUG");
    #else
        printf("配合宏");
    #endif
        printf("必须执行");
    
    
    #ifndef DEBUG
        printf("配合宏,有定义DEBUG");
    #else
        printf("配合宏");
    #endif
        printf("必须执行");
    
    image.png

    相关文章

      网友评论

          本文标题:C

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