![](https://img-blog.csdnimg.cn/20201014180756916.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
C和指针
马•晓
职位:机器视觉工程师 CV Engineer
主要研究方向:机器视觉 工业数据分析
主要编程语言:C++ Python Matlab
主要技能:机器视觉 机器学习 统计分析 OpenCV Halcon PaddlePaddle OpenVINO Scikit-learn
展开
-
第18章 运行时环境
判断运行时环境一个函数分成3个部分:函数序(prologue)、函数体(body)和函数跋(epilogue)。函数序用于执行函数启动需要的一些工作,如为局部变量保留堆栈中的内存。函数体是用于执行有用工作的地方。函数跋用于在函数即将返回之前清理堆栈。运行时效率当程序增长后的容量超过了内存的数量时,它就无法运行,因此它就属于“太大”。即使在一些现代的机器上,一个必须存储于ROM(通常用于存储那些在计算机上控制一些设备的程序)的程序必须相当小才有可能装入到有限的内存空间中。但许多现代的计算机系统在这方面原创 2020-08-21 22:13:38 · 220 阅读 · 0 评论 -
第17章 经典抽象数据类型
有些抽象数据类型(ADT)是C程序员不可或缺的工具,这是由于它们的属性决定的。这类ADT有链表、堆栈、队列和树等。内存分配所有的ADT都必须确定一件事情——如何获取内存来存储值。有3种可选的方案:静态数组、动态分配数组和动态分配的链式结构。静态数组要求结构的长度固定,而且这个长度必须在编译时确定。但这个方案最为简单,而且最不容易出错。如果使用动态数组,可以在运行时才决定数组的长度。而且如果需要的话,可以通过分配一个新的、更大的数组,把原来数组的元素复制到新数组中,然后删除原先的数组,从而达到动态改变原创 2020-08-21 18:16:44 · 154 阅读 · 1 评论 -
第16章 标准库函数
整型函数这组函数返回整型值,其分为3类:算术、随机数和字符串转换。算术<stdlib.h>,包含4个函数int abs(int value); // 返回参数的绝对值 // 如果其结果不能用整数表示 则行为未定义long int labs(long int value); // 也是返回绝对值 但作用对象是长整数div_t div(int numerator, int denominator); // 分子除以分母 得到商和余数 // 结果用一个div_t结构返回 // 其包含2原创 2020-08-21 17:02:17 · 246 阅读 · 0 评论 -
第15章 输入/输出函数
perror函数以一种简单、统一的方式报告错误。其简化向用户报告这些特定错误的过程,其原型为:void perror(char const *message);如果message不是NULL并且指向一个非空的字符串,perror函数就打印出这个字符串,后面跟一个分号和一个空格,然后打印出一条用于解释errno当前错误代码的信息。只有当一个库函数失败时,errno才会被设置。当函数成功运行时,errno的值不会被修改。这意味着我们不能通过测试errno的值来判断是否有错误发生。反之,只有当被调用的函数原创 2020-08-16 13:52:38 · 121 阅读 · 0 评论 -
第14章 预处理器
C预处理器在源代码编译之前对其进行一些文本性质的操作。它的主要任务包括删除注释、插入被#include指令包含的文件的内容、定义和替换由#define指令定义的符号以及确定代码的部分内容是否应该根据一些条件编译指令进行编译。在#define中,如果定义的内容很长,可以分成几行,除了最后一行之外,每行的末尾都要加一个反斜杠\,例如:#define DEBUG_PRINT printf("File %s line %d:" \ " x=%d, y=%d, z=%d", \ __FILE__, __LIN原创 2020-08-15 22:37:48 · 158 阅读 · 0 评论 -
第13章 高级指针话题
只有当确实需要时,你才应该使用多层间接访问。不然的话,你的程序将会变得更庞大、更缓慢并且更难于维护。高级指针声明,例如int *f(); // 其是返回值类型为整型指针的函数int (*f)(); // 其是返回值为整型的函数指针int *f[]; // 其是元素为整型指针的数组int (*f[])(); // 其是一个数组 数组元素是返回值为整型的函数指针int *(*f[])(); // 其是一个数组 // 数组元素是返回值为整型指针的函数指针int (*f)(int, float);原创 2020-08-15 21:30:31 · 123 阅读 · 0 评论 -
第12章 使用结构和指针
可以通过组合使用结构和指针创建强大的数据结构。链表(linked list)是一些包含数据的独立数据结构(通常称为节点)的集合。链表中的每个节点通过链或指针连接在一起。程序通过指针访问链表中的节点。通常节点是动态分配的,但有时你也能看到由节点数组构建的链表。书中给出的单链表的优秀实现为:#include <stdlib.h>#include <stdio.h># define FALSE 0# define TRUE 1typedef struct NODE{ s原创 2020-08-15 18:29:12 · 138 阅读 · 0 评论 -
第11章 动态内存分配
当声明数组时,你必须用一个编译时常量指定数组的长度。但是,数组的长度常常在运行时才知道,这是由于它所需要的内存空间取决于输入数据。这时应该使用动态内存分配。C函数库提供了两个函数,malloc和free,分别用于执行动态内存分配和释放,这些函数维护一个可用的内存池。**动态分配的内存没有以任何方式进行初始化。如果对这块内存进行初始化非常重要,要么手动对它进行初始化,要么使用calloc函数进行初始化。**两个函数的原型为:void *malloc(size_t size);void free(void原创 2020-08-15 17:43:24 · 429 阅读 · 0 评论 -
第10章 结构和联合
聚合数据类型(aggregate data type)能够同时存储超过一个的单独数据。C提供了两种类型的聚合数据类型:数组和结构。和数组名不同,当一个结构变量在表达式中使用时,它并不被替换成一个指针。结构变量也无法使用下标来选择特定的成员。结构变量属于标量类型,所以你可以像对待其他标量类型那样执行相同类型的操作。结构也可以作为传递给函数的参数,它们也可以作为返回值从函数返回,相同类型的结构变量相互之间可以赋值。你可以声明指向结构的指针,取一个结构变量的地址,也可以声明结构数组。有两种定义和声明结构的方原创 2020-08-14 23:15:15 · 143 阅读 · 0 评论 -
第9章 字符串、字符和字节
C语言并没有显式的字符串数据类型,因为字符串以字符串常量的形式出现或者存储于字符数组中。NUL字节是字符串的终止符,但它本身并不是字符串的一部分,所以字符串的长度并不包括NUL字节。(1)求字符串长度:strlen(2)复制字符串:strcpy程序员必须保证目标字符数组的空间足以容纳需要复制的字符串。如果字符串比数组长,多余的字符仍被复制,它们将覆盖原先存储于数组后面的内存空间的值。strcpy无法解决这个问题,因为它无法判断目标字符串数组的长度。(3)连接字符串:strcat(4)字符串比较:原创 2020-08-12 23:25:06 · 182 阅读 · 0 评论 -
第8章 数组
数组名的值是一个指针常量。只有在两种场合下,数组名并不用指针常量来表示,就是当数组名作为sizeof操作符或单目操作符&的操作数时。sizeof返回整个数组的长度,而不是指向数组的指针的长度。取一个数组名的地址所产生的是一个指向数组的指针,而不是一个指向某个指针常量的值的指针。你不能使用赋值符把一个数组的所有元素复制到另一个数组。你必须使用一个循环,每次复制一个元素。一个神奇而不使用的例子:2[array] // 其等价于 *(array+2)**如果可以互换使用指针表达式和下标表达式,原创 2020-08-12 22:54:07 · 152 阅读 · 0 评论 -
第7章 函数
一个没有参数的函数原型应该写成如下:int *func(void);关键字void提示没有任何参数,而不是表示它有一个类型为void的参数。当程序调用一个无法见到原型的函数时,编译器便认为该函数返回一个整型值。对于那些并不返回整型值的函数,这种认定可能会引起错误。C函数的所有参数均以“传值调用”方式进行传递,这意味着函数将获得参数值的一份拷贝。但是如果被传递的参数是一个数组名,并且在函数中使用下标引用该数组的参数,那么在函数中对数组元素进行修改实际上修改的是调用程序中的数组元素。函数将访问调用程序原创 2020-08-10 22:55:06 · 101 阅读 · 0 评论 -
第6章 指针
尽管一个字包含了4个字节,它仍然只有一个地址。至于它的地址是它最左边那个字节的位置还是最右边那个字节的位置,不同的机器有不同的规定。通过一个指针访问它所指向的地址的过程称为间接访问或解引用指针,这个用于执行间接访问的操作符是单目操作符*。在你对指针进行间接访问之前,必须非常小心,确保它们已被初始化。C标准定义了NULL指针,它作为一个特殊的指针变量,表示不指向任何东西。要使一个指针变量为NULL,你可以给它赋一个零值。为了测试一个指针变量是否为NULL,你可以将它与零值进行比较。NULL指针的概念非常原创 2020-08-10 21:52:38 · 146 阅读 · 0 评论 -
第5章 操作符和表达式
一、操作符移位操作只是简单地把一个值的位向左或向右移动。在左移位中,值最左边的几位被丢弃,右边多出来的几个空位则由0补齐。右移位操作存在一个左移位操作不曾面临的问题:从左边移入新位时,可以选择两种方案。一种是逻辑移位,左边移入的位用0填充;另一种是算术移位,左边移入的位由原先该值的符号位决定,符号位为1则移入的位均为1,符号位为0则移入的位均为0,这样能够保持原数的正负形式不变。标准说明无符号值执行的所有移位操作都是逻辑移位,但对于有符号值,到底是采用逻辑移位还是算术移位取决于编译器。你可以编写一个简单原创 2020-08-09 21:54:30 · 103 阅读 · 0 评论 -
第4章 语句
一、表达式语句所谓语句“没有效果”只是表示表达式的值被忽略。二、代码块代码块就是位于一对花括号之内的可选的声明和语句列表。三、if语句在C的if语句和其他语言的if语句中,只存在一个差别。C并不具备布尔类型,而是用整型来代替。零值表示假,非零值表示真。C拥有所有你期望的关系操作符,但它们的结果是整型值0或1,而不是布尔值“真”或“假”。四、for语句for循环有一个风格上的优势,它把所有用于操纵循环的表达式收集在一起,放在同一个地点,便于寻找。当循环体比较庞大时,这个优点更为突出。五、swi原创 2020-08-09 20:44:11 · 102 阅读 · 0 评论 -
第3章 数据
一、基本数据类型在C语言中,**仅有4种基本数据类型——整型、浮点型、指针和聚合类型(如数组和结构等)。**所有其他的类型都是从这4种基本类型的某种组合派生而来。整型分为signed和unsigned,包括char,int,short int,long int。(当可移植问题比较重要时,字符是否为有符号数就会带来两难的境地。最佳妥协方案就是把存储于char型变量的值限制在signed char和unsigned char的交集内,这可以获得最大程度的可移植性,同时不牺牲效率。并且只有当char型变量显原创 2020-08-09 11:47:49 · 104 阅读 · 0 评论 -
第2章 基本概念
一个C程序的源代码保存在一个或多个源文件中,但一个函数只能完整地出现在同一个源文件中。把相关的函数放在同一个文件内是一种好策略。每个源文件都分别编译,产生对应的目标文件。然后,目标文件被链接在一起,形成可执行程序。编译和最终运行程序的机器有可能相同,也可能不同。在用gcc编译c代码时,当使用<math.h>库函数时,需增加编译选项-lm,如:gcc punched_card_machine.c -lm -o punched_card_machine.out...原创 2020-08-09 10:26:34 · 133 阅读 · 0 评论 -
第1章 快速上手
1.要从逻辑上删除一段C代码,更好的办法是使用#if指令,如:#if 0 statements;#endif在#if和#endif之间的程序段就可以有效地从程序中移除,即使这段代码之间原先存在注释也无妨,所以是一种更安全的方法。2.在C语言中,数组参数是以引用形式进行传递的,也就是传址调用,而标量和常量则是按值传递的。例如:int readColumnNumbers(int columns[], int max){}在函数声明的数组参数中,并未指定数组的长度。这种格式是正确的,因原创 2020-08-08 22:18:54 · 76 阅读 · 0 评论