
C语言
C语言学习笔记
Baymaxly
一名大二的在校生呀,加油!!!
展开
-
【C/CPP】assert断言与static_assert静态断言
一、断言assert是一个宏函数,其原型定义在assert.h中:#ifdef NDEBUG#define assert(condition) ((void)0)#else#define assert(condition)#endif一般在调试版本中使用,作用是在程序运行的时候将条件condition的表达式的逻辑值与0进行比较,若相等,则在标准错误输出上输出实现指定的诊断信息,...原创 2020-02-18 22:53:10 · 1799 阅读 · 1 评论 -
【Cpp】NULL与nullptr(C++11起)
一、先来谈谈NULLNULL是一个宏,其定义如下#ifndef __cplusplus#define NULL (void *)0#else#define NULL 0#endif在C语言中,NULL就是(void *)0,通常用于指示指针没有有效操作对象,以避免野指针的出现int *p = NULL;/*业务代码*/if(NULL != p){ /*解引用p*/...原创 2020-02-18 21:19:24 · 1317 阅读 · 0 评论 -
【Cpp】C和C++混合编程
一、混合编程杂绪1.1 为什么需要混合编程Cpp是从C演变过来的,C有很多优秀成熟项目和库,没必要在C++中重写,C++程序可以直接调用调用庞大项目划分后一部分适合用C(底层),一部分适合用C++(中间层、上层)1.2 混合编程的支撑编译型程序的编译过程:源文件->目标(库)文件->可执行程序->镜像文件任何编程语言执行时都必须是可执行程序,所以都必须先被编译成...原创 2020-02-15 21:49:52 · 6713 阅读 · 1 评论 -
【C语言】main函数的argc、argv传参
一、main函数返回值1.1 函数为什么需要返回值一般而言,参数是函数的输入,返回值是函数的输出(在高级应用中,使用参数放回,放回值说明状态)函数需要对外输出数据(函数运行的一些结果值)因此需要返回值形式上来说,函数被另一个函数所调用,返回值作为函数式的值返回给调用这个函数的地方1.2 main函数的正确书写以下三种方式是正确规范的int main(void){}int ...原创 2020-02-15 00:46:00 · 14633 阅读 · 1 评论 -
【C语言】常用DEBUG宏汇总
一、printf函数与fprintf函数1.1 printfprintf的函数原型为: int printf(const char *format, ...);用于将格式化后的字符串输出到标准输出。标准输出,即标准输出文件,对应终端的屏幕。printf称为可变参数函数,其定义声明和普通函数相同。在其参数列表中,format称为固定参数部分,...称为参数占位符,二者共同构成可变参数...原创 2020-02-14 23:04:49 · 2105 阅读 · 2 评论 -
【C语言】存储类与作用域、生命周期与链接属性
一、概念解析与内存映像1.1 概念解析存储类:内存有多种管理方法:stack、heap、.data、bss段、.text等,一个变量的存储类属性就是描述这个变量存储在何种内存段中。作用域:用来描述一个符号(变量、函数等)起作用的范围。生命周期:用来描述变量的诞生(给变量分配内存)与消亡(回收分配的内存空间,此时变量无权访问此内存空间)链接属性:一个程序从源代码到最终的可执行程序需要经过...原创 2020-02-14 01:24:52 · 403 阅读 · 0 评论 -
【C语言】静态链接库与动态链接库的制作与使用
一、函数库简述简单来说,函数库就是一些事先写好的模块化的函数的集合,可以供给其他程序员使用。最开始没有函数库,每个程序员写程序都要从零开始写,时间长了慢慢地就积累下来了一些优质的函数库。后来有组织把各种函数库收拢在一起,经过校准和整理,形成一份标准化的函数库,就是现在的标准的函数库,如glibc1.1 函数库的提供形式:动态链接库与静态链接库早期的函数共享都是以源代码的形式进行的,慢慢地,源...原创 2020-02-12 15:55:13 · 1003 阅读 · 0 评论 -
【C语言】预处理、宏定义、内联函数
一、由源码到可执行程序的过程1. 预处理: 源码经过预处理器的预处理变成预处理过的.i中间文件gcc -E test.c -o test.i2. 编译: 中间文件经过编译器编译形成.s的汇编文件gcc -S test.i -o test.s3. 汇编: 汇编文件经过汇编器生成目标文件.o(机器语言)gcc -c test.s -o test.o4. 链接: 链接器将目标文件链接...原创 2020-02-10 21:54:15 · 530 阅读 · 0 评论 -
【C语言】宏定义实现位运算
一、常用位操作符1.1 位与&真值表&10110000特点有0为0,全1为11.2 位或|真值表|10111010特点有1为1,全0为01.3 位异或^真值表^10101010特点相同为0,相异为11.4 位取反~位取反是将操作数...原创 2020-02-09 15:14:04 · 4442 阅读 · 1 评论 -
【C语言】共用体union与大小端模式
一、共用体union1.1 共用体的定义、变量定义和使用共用体union和结构体struct在类型定义、变量定义和使用方法上很相似,如下代码段#include <stdio.h>typedef union myunion1{ int a; char b;}MU1;int main(void){ MU1 test1; test1.a =...原创 2020-02-08 01:44:33 · 2093 阅读 · 0 评论 -
内核第一宏:offsetof宏和container_of宏
绪论通过结构体的整体变量来访问其中的各个元素,形式上是通过./->来访问,实质上是通过指针方式来访问的(编译器会自动计算偏移量)。在C/C++中,其实可以用一些宏来计算结构体中成员变量与结构体的地址关系,那就是offsetof宏和container_of宏一、offsetof宏offsetof宏:通过虚拟一个type类型的结构体变量,然后用type.member的方式来访问member...原创 2020-02-05 17:56:47 · 366 阅读 · 0 评论 -
__attribute__((aligned(n)))和__attribute__((packed))
绪__attribute__是GUN C中极具特设的一大机制,可以用来设置函数属性(Function Attribute)变量属性(Variable Attribute)类型属性(Type Attribute)这里我们主要阐述用__attribute__((aligned(n)))和__attribute__((packed))两个指令对结构体进行属性设置一、作用简述__at...原创 2020-02-04 23:56:42 · 2375 阅读 · 1 评论 -
#pragma pack的使用
绪论在没有外部干预的情况下,编译器会根据操作系统及编译环境来自动设定结构体的内存对齐的默认字节,但是在实际开发中,有时候考虑到实际内存,会有将结构体设置为1字节对齐(不对齐)的需求,这个时候就要借助C/C++编译指令#pragma pack(),这个指令也是非常复杂的,这里只总结两种常用的一、#pragma pack(n)与 #pragma pack()1.1 作用简述#pragma pa...原创 2020-02-04 21:10:26 · 796 阅读 · 0 评论 -
结构体及其内存对齐
一、结构体的类型与变量定义使用UDT时都是先定义类型再使用,使用结构体也一样:先定义结构体类型再用类型定义变量,有以下两种使用方式:1.1 方式一:类型和变量独立定义struct student{ char name[20]; int age;};struct student s1;注意:类型一般定义在主函数外面,变量根据实际需求来决定定义在哪里。1.2 方式二:...原创 2020-02-04 19:27:54 · 823 阅读 · 0 评论 -
字符串与字符数组、sizeof与strlen
一、C语言的字符串类型C语言没有原生的字符串类型,不像C#等高级语言中具有string类型来表示字符串,C语言中的字符串是通过字符指针来间接实现的,如:char *p = "WHUT2018";此时p就叫做字符串,但是实际上p只是一个字符指针(本质上就是一个指针变量,只是p指向了一个字符串的起始地址而已)1.1 C语言中字符串的本质字符串就是指针指向的一段连续的内存空间,在内存中就...原创 2020-02-03 20:23:58 · 1058 阅读 · 1 评论 -
代码段(.text)、数据区(.data)和bss段
一、三个常用段编译器在编译程序的时候,将程序中的所有元素分成一些部分,各部分构成一个段,段是可执行程序的组成部分。代码段:程序中的可执行部分,是由函数堆叠而成的数据段(数据区、静态数据区、静态区):程序中的数据,C语言中的全局变量(全局变量才算程序的数据,局部变量是函数的数据)bss段(ZI段(zero initial)):被初始化为0,bss段本质上也是属于数据段。也就是说bss段就...原创 2020-02-01 21:06:33 · 4043 阅读 · 0 评论 -
堆(heap)及内存泄露
一、堆内存特点操作系统堆管理器管理:堆管理器是操作系统的一个模块,堆管理内存分配灵活,按需分配大块内存:堆内存管理着总量很大的操作系统内存块,各进程可以按需申请使用,使用完释放手动申请、释放:需要写代码去malloc及free脏内存:堆内存也是反复使用的,而且使用者用完释放前不会清除,因此也是脏的临时性:堆内存只在malloc和free之间属于某个进程,可以访问。在malloc之间个...原创 2020-02-01 17:31:55 · 907 阅读 · 0 评论 -
栈(Stack)
一、内存杂谈1.1 程序执行需要内存支持对程序来说,内存就是程序的立足之地(程序是被放在内存中运行的);程序运行时需要内存来存储一些临时变脸1.2 内存管理内存管理最终是由操作系统来完成的:内存本身在物理上是一个硬件器件,由硬件系统提供内存是由操作系统统一管理。为了内存管理既方便又合理,操作系统提供了多种机制让程序使用内存。这些机制彼此不同,各自有各自特点,程序根据实际情况选择某种方...原创 2020-01-31 22:11:10 · 339 阅读 · 0 评论 -
二维数组及其动态内存分配
一、二维数组的基本概念1.1 二维数组的内存映像从内存角度看,二维数组和一维数组一样,在内存中都是连续分布的多个内存单元,并没有本质差别,只是内存的管理方式不一样,如下图所示一维数组int a[10]与二维数组int b[2][5]的对应关系一维数组a[0]a[1]a[4]a[5]a[9]二维数组b[0][0]b[0][1]b[0][4]b[1...原创 2020-01-31 18:42:15 · 11054 阅读 · 2 评论 -
二重指针
一、二重指针的本质二重指针与一重指针本质上都是指针变量,指针变量的本质也就是变量,都是用来指向别的东西的,在32位机上都是占4字节内存空间二重指针指向的变量类型是一个一重指针1.1 测试代码段 int a = 1; int *p1 = NULL; //一重指针 int **p2 = NULL; //二重指针 printf("sizeof(p1) = %...原创 2020-01-28 13:22:08 · 1324 阅读 · 0 评论 -
typedef的应用
一、与typedef相关的预备知识1.1 C语言的两种类型内建类型ADT(也叫原生类型、基础数据类型):编译器自带的类型,如int/double等自定义类型UDT:不是编译器自带的类型,是程序员自己定义的,如结构体类型、数组类型、函数指针类型等1.2 typedef加工的是类型而不是变量类型就是一个数据模板,变量是一个实在的数据类型是不占内存的,变量是占内存的在面向对象的语言中...原创 2020-01-27 22:20:07 · 445 阅读 · 0 评论 -
函数指针的应用
一、函数指针实现多态多态就是同一个执行但是实际结果不一样C语言虽然没有多态,但是可以用函数指针指向不同的函数来实现同一个调用执行不同的结果1.1 测试代码#include <stdio.h>//定义一个pFunc类型,这个函数指针类型指向一种特定参数列表和返回值得函数typedef int (*pFunc)(int, int);int add(int a, i...原创 2020-01-27 18:10:31 · 4342 阅读 · 0 评论 -
指针数组与数组指针、函数指针
一、指针数组与数组指针1.1 概念与区别指针数组的实质是一个数组,这个数组中存储的内容全部是指针变量。数组指针的实质是一个指针,这个指针指向的是一个数组。1.2 一般规律找核心: 在定义一个符号的时候,关键在于搞清楚定义的符号是什么找结合: 其次看谁和核心最近、谁和核心结合(结合的实质是运算)如果核心和*结合,表示核心是指针如果核心和[]结合,表示核心是数组如果核...原创 2020-01-22 20:34:55 · 410 阅读 · 0 评论