![](https://img-blog.csdnimg.cn/41b691fe739e4ce498595abcb6f939f2.png?x-oss-process=image/resize,m_fixed,h_224,w_224)
C“关于”系列——迷雾击破整理
文章平均质量分 76
《C Primer Plus(6th)》中所见的常见问题,解析之~
itzyjr
Stay hungry,Stay foolish!
展开
-
关于C之格式化输出——参数传递机制
#include <stdio.h> int main(void) { float n1 = 3.0; double n2 = 3.0; long n3 = 2000000000; long n4 = 1234567890; printf("int(%zd) long(%zd) float(%zd) double(%zd)\n", sizeof(int), sizeof(long), sizeof(float), sizeof(double));.原创 2021-03-25 16:44:50 · 280 阅读 · 0 评论 -
关于C之运算符优先级
C语言优先级 优先级 运算符 名称或含义 使用形式 结合方向 说明 1 [] 数组下标 数组名[整型表达式] 左到右 () ...原创 2020-04-30 14:21:00 · 190 阅读 · 0 评论 -
关于C之ADT二叉查找树
对于一个排序的列表,用二分查找,比顺序查找好得多。一般而言,n次比较能处理个元素的数组,所以项数越多,越能体现二分查找的优势。下图直观表示了用二分法查找Susan:选择何种数据类型取决于具体的问题。如果因频繁地插入和删除项导致经常调整大小,而且不需要经常查找,选择链表会更好。如果只是偶尔插入或删除项,但是经常进行查找,使用数组会更好。如果需要一种既支持频繁插入和删除项又支持频繁查找的数...原创 2019-11-12 00:37:16 · 379 阅读 · 0 评论 -
关于C之ADT队列
队列是一种“先进先出”(first in,first out,缩写为FIFO)的数据形式,就像排队买票的队伍一样(前提是没有人插队)。接下来,我们建立一个非正式的抽象定义:类型名: 队列类型属性: 可以储存一系列项类型操作: 初始化队列为空确定队列为空确定队列已满确定队列中的项数在队列末尾添加项在队列开头删除或恢复项清空队列有了的关于ADT之链表基础,...原创 2019-11-11 03:45:43 · 379 阅读 · 0 评论 -
关于C之按值传递与指针误区解读
我们看下面代码:#include <stdio.h>typedef struct node { int r;} Node, * List;void AddItemX(int R, List plist);void AddItemY(int R, List* plist);int main(void) { List movies = NULL; AddItemX(...原创 2019-11-11 02:32:15 · 193 阅读 · 0 评论 -
关于C之ADT链表
有时用链表代替数组,那么先看一个数组的例子:使用一个结构储存每部电影,一个数组储存一年内看过的电影。为简单起见,我们规定结构中只有两个成员:片名和评级(0~10)。#include<stdio.h>#include<string.h>#define TSIZE 45 /* 储存片名的数组大小 */#define FMAX 5 /* 影片的最大数量 */st...原创 2019-11-10 21:23:27 · 258 阅读 · 0 评论 -
关于C之抽象数据类型(ADT)理论
什么是类型?类型特指两类信息:属性和操作。例如,int 类型的属性是它代表一个整数值,因此它共享整数的属性。允许对int类型进行算术操作是:改变int类型值的符号、两个int类型值相加、相减、相乘、相除、求模。当声明一个int类型的变量时,就表明了只能对该变量进行这些操作。C的int类型背后是一个更抽象的整数概念。数学家已经用正式的抽象方式定义了整数的属性。例如,假设N和M是整数,那么N+M=...原创 2019-11-10 19:58:48 · 365 阅读 · 0 评论 -
关于C之可变参数
之前的文章有提到过变参宏,即该宏可以接受可变数量的参数。stdarg.h 头文件为函数提供了一个类似的功能,但是用法比较复杂。必须按如下步骤进行:1.提供一个使用省略号(一定是最后的参数)的函数原型;2.在函数定义中创建一个va_list类型的变量;3.用宏把该变量初始化为一个参数列表;4.用宏访问参数列表;5.用宏完成清理工作。void f1(int n, ...); ...原创 2019-11-09 05:29:42 · 242 阅读 · 0 评论 -
关于C之断言assert
assert.h 头文件支持的断言库是一个用于辅助调试程序的小型库。它由assert()宏组成,接受一个整型表达式作为参数。如果表达式求值为假(非零),assert()宏就在标准错误流(stderr)中写入一条错误信息,并调用abort()函数终止程序(abort()函数的原型在stdlib.h头文件中)。assert()宏是为了标识出程序中某些条件为真的关键位置,如果其中的一个具体条件为假,就用...原创 2019-11-09 05:14:09 · 405 阅读 · 0 评论 -
关于C之内联函数
通常,函数调用都有一定的开销,因为函数的调用过程包括建立调用、传递参数、跳转到函数代码并返回。使用宏使代码内联,可以避免这样的开销。C99还提供另一种方法:内联函数(inline function)。读者可能顾名思义地认为内联函数会用内联代码替换函数调用。其实C99和C11标准中叙述的是:“把函数变成内联函数建议尽可能快地调用该函数,其具体效果由实现定义”。因此,把函数变成内联函数,编译器可能会用...原创 2019-11-09 05:06:25 · 782 阅读 · 0 评论 -
关于C之泛型
C11新增了一种表达式,叫作泛型选择表达式。在程序设计中,泛型编程(generic programming)指那些没有特定类型,但是一旦指定一种类型,就可以转换成指定类型的代码。例如,C++在模板中可以创建泛型算法,然后编译器根据指定的类型自动使用实例化代码。在C中这个功能是C11版本才具有的,可根据表达式的类型(即表达式的类型是int、double 还是其他类型)选择一个值。泛型选择表达式不...原创 2019-11-09 04:54:04 · 1344 阅读 · 0 评论 -
关于C之条件编译指令#undef、#ifdef、#else、#endif、#ifndef、#if、#elif、#line、#error、#pragma
条件编译:可以使用其他指令创建条件编译(conditinal compilation)。也就是说,可以使用这些指令告诉编译器根据编译时的条件执行或忽略信息(或代码)块。1.#ifdef、#else和#endif指令:#ifdef MAVIS#include "horse.h" // 如果已经用#define定义了 MAVIS,则执行下面的指令#define STABLES 5#el...原创 2019-11-09 04:34:49 · 727 阅读 · 0 评论 -
关于C之预处理指令#define宏及#include
#define:对于预处理指令#define,是程序已经准备好进入预处理阶段,预处理器查找一行中以#号开始的预处理指令。预处理器不做计算,不对表达式求值,它只进行替换。一般而言,预处理器发现程序中的宏后,会用宏等价的替换文本进行替换。如果替换的字符串中还包含宏,则继续替换这些宏。如果这样定义一条预处理指令:#define FOUR 2+2然后这样调用:int hex...原创 2019-11-09 02:50:51 · 961 阅读 · 0 评论 -
关于C之函数指针及typedef简介
先看一个C标准库<stdio.h>中的一个函数qsort(),它的功能是对任何类型的数组进行排序。void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*))参数:base-- 指向要排序的数组的第一个元素的指针。 nitems-- 由 bas...原创 2019-11-08 23:11:16 · 352 阅读 · 0 评论 -
关于C之结构、联合与指针
结构:建立一个结构声明:struct book { char title[MAXTITL]; char author[MAXAUTL]; float value;};声明一个结构变量:struct book library;编译器执行这行代码便创建了一个结构变量library。编译器使用book模板为该变量分配空间:一个内含MAXTITL个元素的c...原创 2019-11-08 21:53:30 · 337 阅读 · 0 评论 -
关于C之递归
C允许函数调用它自己,这种调用过程称为递归(recursion)。递归有 时难以捉摸,有时却很方便实用。结束递归是使用递归的难点,因为如果递 归代码中没有终止递归的条件测试部分,一个调用自己的函数会无限递归。递归的原理:其实就是一个栈(stack),比如求5的阶乘,要知道5的阶乘,就要知道4的阶乘,4又要是到3的,以此类推,所以递归式就先把5的阶乘表示入栈,在把4的入栈,直到最后一个,之后...原创 2019-11-08 05:31:55 · 244 阅读 · 0 评论 -
关于C之动态内存分配完成一/二维变长数组
变长数组(VLA)和调用 malloc()在功能上有些重合。例如,两者都可用于创建在运行时确定大小的数组:int vlamal() { int n; int * pi; scanf("%d", &n); pi = (int *) malloc (n * sizeof(int)); int ar[n];// 变长数组 pi[2] = ar...原创 2019-11-08 01:30:37 · 614 阅读 · 0 评论 -
关于C之二维数组与指针(首地址&步长)
先看一个二维数组的直观示意图:float rain[5][12]:5行12列。二维数组可以看作是把一维数组当作元素的一维数组。rain[5][12]就可看作是由5个元素的组成的一维数组(每个元素都是一个一维数组,其size为12)。可以这样初始化:const float rain[5][12] = { {4.3, 4.3, 4.3, 3.0, 2.0, 1.2, 0....原创 2019-11-08 01:17:45 · 1519 阅读 · 0 评论 -
关于C之auto、register、static、extern、const、volatile、restrict、_Atomic关键字详解
1.自动变量auto:为了更清楚地表达你的意图,例如为了表明有意覆盖一个外部变量定义,或者强调不要把该变量改为其他存储类别,可以显示使用关键字auto,如下所示:int plox;int main(void) { ...}void go(){ auto int plox;由于局部变量plox与外部全局变量名称相同,这里显示表明意图,易于理解。其实在go()函数中不...原创 2019-11-07 22:13:40 · 489 阅读 · 0 评论 -
关于C之字符串两种声明方式的核心区别及内存分配方式的静态/堆/栈
比如有如下声明和初始化:const char pets[12] = "nice cat.";由于字符串本质上是一个字符数组,以上声明是下面的简版:const char pets[12] = {'n','i','c','e',' ','c','a','t','.','\0','\0','\0'};对于没初始化的元素会自动初始化为0(null字符not字符0)。以上声明在内存中的表...原创 2019-11-07 06:57:34 · 328 阅读 · 0 评论 -
关于C之getchar()/setbuf缓冲机制解析
看一个例子,就可以知道这个潜在的问题:/* 猜数字 */#include <stdio.h>int main(void) { int guess = 1; printf("Pick an integer from 1 to 100. I will try to guess "); printf("it.\nRespond with a y if guess right ...原创 2019-11-07 01:28:45 · 870 阅读 · 0 评论 -
关于C之二进制模式与文本模式
用二进制模式打开一个文件的时候,文件本身的内容和你编写程序时用函数读到的内容完全相同(或者说和磁盘上的内容完全相同)。实际上, 所有的数据都是以二进制形式储存的, 甚至连字符都以字符码的二进制表示来储存。 如果文件中的所有数据都被解释成字符码, 则称该文件包含文本数据。 如果部分或所有的数据都被解释成二进制形式的数值数据, 则称该文件包含二进制数据( 另外, 用数据表示机器语言指令的文件都是二...原创 2019-11-04 06:44:21 · 2187 阅读 · 0 评论 -
关于C之文件结尾EOF与二进制文件换行符
文件结尾:计算机操作系统要以某种方式判断文件的开始和结束。 检测文件结尾的一种方法是, 在文件末尾放一个特殊的字符标记文件尾。CP/M、 IBMDOS和MS-DOS的文本文件曾经用过这种方法。 如今, 这些操作系统可以使用内嵌的Ctrl+Z字符来标记文件结尾。 这曾经是操作系统使用的唯一标记,不过现在有一些其他的选择, 例如记录文件的大小。 所以现代的文本文件不一定有嵌入的Ctrl+Z, ...原创 2019-11-04 00:36:43 · 3428 阅读 · 0 评论 -
关于C之缓冲输入
先看一个看似很简单的例子:#include <stdio.h>int main(void) { char ch; while ((ch = getchar()) != '#') putchar(ch); return 0;}|Hello, there. I would[enter]Hello, there. I would...原创 2019-11-03 21:10:38 · 282 阅读 · 0 评论 -
关于C之空字符与空指针
先看一个例子:#include <stdio.h>#define STLEN 10int main(void) { char words[STLEN]; int i; puts("Enter strings (empty line to quit):"); while (fgets(words, STLEN, stdin) != NULL &&...原创 2019-11-03 19:55:36 · 735 阅读 · 0 评论 -
关于C之字符串与从键盘输入
C字符串:在C中,没有直接的字符串,完全替代之的是字符数组。字符数组中每一个字符占一个字节。当初始化列表中的值少于数组元素个数时,编译器会把剩余的元素都初始化为0。也就是说,如果不初始化数组,数组元素和未初始化的普通变量一样,其中储存的都是垃圾值;但是,如果部分初始化数组,剩余的元素就会被初始化为0。可以这样申明一个字符串:char arr[50] = "Zing went th...原创 2019-11-02 13:30:04 · 1561 阅读 · 0 评论 -
关于C之ASCII码与转义字符
ASCII码:ASCII是基于拉丁字母的一套电脑编码系统。它是现今最通用的单字节编码系统,并等同于国际标准ISO/IEC 646。共定义了128个字符,其中33个字符无法显示(这是以现今操作系统为依归,但在DOS模式下可显示出一些诸如笑脸、扑克牌花式等8-bit符号),且这33个字符多数都已是陈废的控制字符。控制字符的用途主要是用来操控已经处理过的文字,在33个字符之外的是95个可显示的字符。...原创 2019-11-02 07:27:39 · 6659 阅读 · 3 评论 -
关于C之整型溢出后的值
#include <stdio.h> int main(void) { int i = 2147483647; // maximum value of int unsigned int j = 4294967295; // maximum value of unsigned int printf("%d %d %d\n", i, i+1, i+2); ...原创 2019-11-02 04:56:42 · 1459 阅读 · 0 评论 -
关于C之整数与浮点数二进制表示
关于字节与位:一个int占4个字节(byte),一个字节占8位(bit),所以一个int占用4x8=32位。char类型的范围为什么是-128~127?有一个整型范围的公式:-2^(n-1)~2^(n-1)-1 (n为整型的内存占用位数)。对于char类型,占一个字节,n=8,代入得:-128~127。char占8位,用二进制表示为 0000 0000 ~ 1111 111...原创 2019-11-02 03:48:04 · 2108 阅读 · 1 评论