• C语言学习笔记


    指针与数组

    数组的大小需要在编译时确定,声明一个数组时,编译器根据声明时指定的元素数量分配一片连续的内存空间。
    一维数组的数组名是一个指针常量,也就是数组首个元素的地址,当数组名当做sizeof操作符的操作数时返回的是整个数组的长度,数组名当做&操作符的操作数时返回的是一个指向数组的指针。
    多维数组在声明时同样分配一片连续的内存空间,它是按照行优先的顺序存储的。二维数组的数组名是一个指向数组的指针。

    int matrix[3][10];
    int (*p1)[10] = matrix;
    int *p2 = matrix[0];
    int v = matrix[0][0];
    
    • 1
    • 2
    • 3
    • 4

    指针在进行加减运算时,地址移动的大小是该指针所指向类型大小的整数倍。指向数组的指针在进行加减运算时,地址移动的大小是该指针所指向数组大小的整数倍,指向数组的指针在第一次解引用时返回的是其所指向的数组的首地址,第二次解引用返回的是数组中元素的值,所以matrix[i][j]等价于*(*(p1 + i) + j)
    指针数组中,每个元素是一个指针变量,其声明方式为

    int *p[10];
    
    • 1

    优先级

    优先级从高到低分别是:

    • 操作符:() [] -> .
    • 单目运算符:! ~ ++ – - (type) * & sizeof

    获取字符串的长度

    size_t strlen(char const *string)
    
    • 1

    注意size_t是一个无符号的整形,C语言中有符号数和无符号数的运算结果是无符号数,无符号数永远大于零。

    复制字符串至指定内存地址

    char* strcpy(char* dst, char const* src)
    
    • 1

    如果复制后dst和src存在内存重叠,则结果是未定义的,dst必须是一个字符数组或一个指向动态内存的指针, 不能使用字符串常量,如果复制后的dst比之前的字符串长度短,则\0之后不会被当做字符串读取,如果复制后的dst比之前的长,则之后的内存空间会被覆盖。

    链接字符串

    char* strcat(chat* dst, char cosnt* src)
    
    • 1

    dst必须为一个字符串,该函数会找到dst字符串的末尾,并将src的字符串复制到该位置,注意src和dst不能发生内存重叠,否则结果是未定义的。

    比较字符串长度

    int strcmp(char const *s1, char const* s2)
    
    • 1

    如果s1小于s2,返回小于零的值,如果s1等于s2,返回零,如果s1大于s2,返回大于零的值

    内存操作
    复制指定字节数

    void* memcpy(void* dst, void const* src, size_t length);
    
    • 1

    同样dst和src不能重叠,如果可能存在重叠,应该使用memmove

    void* memmove(void* dst, void const *src, size_t length)
    
    • 1

    sizeof数组,返回数组所占的字节数,即每个元素所占字节数乘以元素的个数。
    sizeof指针,32位主机返回4,64为主机返回8
    sizeof结构体,返回内存对齐后的大小。
    注意字符串要包含最后一个\0
    数组作为函数参数进行传递时,该数组会自动退化为同类型的指针。

    函数的形参是一个指针,不要用该指针去申请动态内存

    void getMemory(char* p, int num){
    	p = (char*)malloc(sizeof(char) * num);
    }
    void Test(void) 
    { 
     char *str = NULL; 
     GetMemory(str, 100); // str 仍然为 NULL 
     strcpy(str, "hello"); // 运行错误 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    getMemory函数中,形参p一开始指向实参str保存的地址,在指向malloc语句后,p指向malloc返回的动态内存地址,getMemory运行结束后,形参p销毁,导致内存泄漏,而实参依然指向原先的地址。

    如果非得要用指针参数去申请内存,那么应该改用“指向指针的指针”

    void GetMemory2(char **p, int num) { 
     *p = (char *)malloc(sizeof(char) * num); 
    }
    char *GetMemory3(int num) 
    { 
     char *p = (char *)malloc(sizeof(char) * num); 
     return p; 
    }
    void Test2(void) { 
     char *str = NULL; 
     GetMemory2(&str, 100); // 注意参数是 &str,而不是 str 
     strcpy(str, "hello"); 
     cout<< str << endl; 
     free(str); 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    GetMemory2实参为指针变量,形参是指向指针的指针,指向实参指针变量的地址,malloc返回申请的动态内存地址,形参通过解引用符得到实参的指针变量,使得实参指向动态内存地址,函数调用结束后,销毁指向指针的指针形参。
    同样也可以用return语句返回动态内存的地址,但是return语句不要返回指向栈内存的指针,例如

    char *GetString(void) 
    { 
     char p[] = "hello world"; 
     return p; // 编译器将提出警告 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    free会释放指针指向的动态内存,但是该指针所指向的地址依然不变,这样的指针被称为野指针,应该将该指针的值设置为NULL,避免访问该地址,
    指针变量在创建时应该被初始化,让其指向合法的内存,否则会成为野指针。

  • 相关阅读:
    快手二面:你有没有调用过第三方接口?碰到过哪些坑?
    【NodeJs-5天学习】第四天存储篇⑤ ——PM2,node.js应用进程管理器
    经典快速制作套打证书模板(doc)大全
    java-php-python-ssm医患辅助系统计算机毕业设计
    Xshell+Xftp通过代理的方式访问局域网内网服务器
    才毕业1年,面试测试岗开口就是17k,还以为是来了什么技术高手,一问三不知...
    迪拜推出国家元宇宙战略
    计算机三级 - 数据库技术 - 第十四章 数据仓库与数据挖掘 笔记
    初识Java语言中的lambda表达式和函数式接口
    C语言学习:3、数据输入
  • 原文地址:https://blog.csdn.net/weixin_49024732/article/details/132762571