自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(39)
  • 收藏
  • 关注

原创 高级宏定义

同样的道理,第二次先展开 SQUARE(i++),此时 i 的值是 3,完事之后变成 5,所以第二次打印便是:4 的平方是 9。由于 ++ 在后,所以是先使用 i 的值,再自增,上面式子的结果是 1,完事之后 i 的值变成了 3(自增了两次)。printf("%d 的平方是%d\n", i-1, SQUARE(i++));而函数不同,在函数中形参和实参是两个不同的变量,都有自己的内存空间和作用域,调用时是要把实参的值传递给形参。SQUARE(i++) 先展开了,变成 ((i++) * (i++))。

2024-08-03 01:32:13 936

原创 C语言的内存布局

答:因为变量 a 和变量 b 都是局部变量,它们的作用域仅限于所在的函数之中。当函数被调用时,在栈上为它们分配内存空间,当函数结束时,空间自动被回收。分析:根据代码上下文我们可以推断出 array 是一个指针数组,数组中的每个元素是一个函数指针,该函数的参数和返回值都是 void。答:在定义字符变量 a 和 b 的时候,两个局部变量的地址是连续的,各占一个字节,并且 b 在前 a 在后。如果这时候给它赋值,那么将 “污染” a 变量的地址空间,很不幸,我们确实这么做了。

2024-08-03 00:43:22 785

原创 动态内存管理2

但 malloc 函数的调用是在 main 函数之后进行的,所以从概念上来说,static 声明的变量不可能通过调用库函数来进行初始化。答:从形式上看,str 开头的函数使用的是 char 类型的指针(char *)作为参数和返回值;而 mem 开头的函数主要目的是提供一个高效的函数接口来处理内存空间的数据。答:calloc 函数在申请完内存后,自动初始化该内存空间为零,而 malloc 函数不进行初始化操作,所以调用完 malloc 函数之后,需要再调用 memset 函数将内存初始化为零。

2024-08-02 23:14:59 276

原创 动态内存管理

这里务必要注意一点,free() 函数释放的是 ptr 指向的内存空间,但它并不会修改 ptr 指针的值。也就是说,ptr 现在虽然指向 0x8b23008,但该空间已经被 free() 函数释放了,所以对于该空间的引用已经失去了意义(会报错)。因此,为了防止后面再次对 ptr 指向的空间进行访问,建议在调用 free() 函数后随即将 ptr 赋值为 NULL。答:因为将每次申请堆内存空间的粒度调大,malloc 函数会直接返回 NULL 表示失败,这样程序既不会因为内存耗尽而崩溃,也不会退出死循环……

2024-08-02 23:00:28 442

原创 递归C语言

欲修其身者,先正其心;欲诚其意者,先致其知,致知在格物。物格而后知至,知至而后意诚,意诚而后心正,心正而后身修,身修而后家齐,家齐而后国治,国治而后天下平。答:递归的执行效率通常比迭代低很多,所以递归程序要更消耗时间;由于递归函数是不断调用函数本身,在最底层的函数开始返回之前,程序都是一致在消耗栈空间的,所以递归程序要“吃”更多的内存空间;递归的结束条件设置非常重要,因为一旦设置错误,就容易导致程序万劫不复(崩溃)”这个故事之外,你还听过哪些与递归相关的故事?这很重要,否则递归程序会一直走下去,直到崩溃。

2024-08-02 22:29:17 303

原创 生存期和存储类型

答:因为具有文件作用域的变量(比如全局变量)默认具有 External 链接属性,而 External 链接属性“在多个文件中声明的同名标识符表示同一个实体”。具有代码块作用域的变量一般情况下具有自动存储期(比如局部变量和形式参数),具有自动存储期的变量在代码块结束时将自动释放存储空间。答:register,因为寄存器是存在于 CPU 的内部的,CPU 对寄存器的读取和存储可以说是几乎没有任何延迟。答:时间的角度,说白了就是研究这个变量可以“活”多久。答:自动变量拥有代码块作用域,自动存储期和空链接属性。

2024-08-02 22:17:59 214

原创 作用域和链接属性

答:当一个变量被定义的时候,编译器为变量申请内存空间并填充一些值。答:是,因为任何在代码块之外声明的标识符都具有文件作用域(比如全局变量),作用范围是从它们的声明位置开始,到文件的结尾处都是可以访问的。因此,声明的同名标识符被当作独立不同的实体(比如函数的局部变量,因为它们被当作独立不同的实体,所以不同函数间同名的局部变量并不会发生冲突)答:不写 void 也没关系,但写上 void 有一个好处,那就是当你试图对一个参数为 void 的函数传入参数时,编译器会毫不犹豫地给予你错误提示!

2024-08-02 22:05:24 335

原创 全局变量和局部变量

答:虽然程序声明了一个字符指针变量(指望它来存放字符串),但是并没有对其(name)进行初始化,这样也就意味着 name 可能是指向任何地方的,那么它就是一个悬空指针。前面我们强调过,使用悬空指针是极其危险的,上面代码就是一个很好的例子:虽然程序可以运行,但当你输入名字之后,程序立即崩溃(段错误)。答:因为大量使用全局变量会对程序结构产生不良的影响,而且可能导致程序中各个函数之间具有太多的数据联系(在模块化程序设计的指导下,我们应该尽量设计内聚性强,耦合性弱的模块。答:这里列举两点,欢迎大家继续补充!

2024-07-31 00:17:50 613

原创 指针函数和函数指针

答:上面代码试图返回形参的地址,这跟返回局部变量的地址一样是错误的!注:这道题除了考察你对C语言指针的理解程度之外,几乎没有任何作用,在实际开发中,请不要写这样的代码折腾你的同事……答:函数指针是一个指向函数的指针;指针函数是一个返回指针变量的函数。答:解这种题,除非你对指针特别熟练,否则请从最里边的小括号开始分析。答:函数名可以在表达式中被解读成“指向该函数的指针”。答:能,定义一个 void * 类型的指针函数。

2024-07-29 23:08:15 618

原创 参数和指针

dest 参数是 char * 类型,而 src 参数是 const char * 类型,说明dest 所指向的内存空间在函数中是可以改写的,而 src 所指向的内存空间在函数中只能读不能写。答:我们说函数就是一种封装的方法,函数的设计应该遵从“一个函数仅实现一个功能”的原则,这样子我们就可以实现化繁为简的目标,将一个复杂的程序给拆解开来,变成一个个独立的功能,每个功能我们就用一个函数来实现。好吧,打印的值应该是 40 和 4(在小甲鱼的编译环境中,一个整型变量占 4 个字节的内存空间)。

2024-07-28 21:44:29 855

原创 函数初体验

这是因为程序的编译时从上到下执行的,所以从原则上来说,函数必须“先定义,再调用”。答:所谓声明(Declaration),就是告诉编译器我要使用这个函数,你现在没有找到它的定义不要紧,请不要报错,稍后我会把定义补上。有时候,你可能会发现及时不写函数的声明,程序也是可以正常执行的。// D. 返回值是void的函数不需要使用return语句返回。答:重新定义的同名函数会覆盖标准库函数(前提是两者的声明一致,包括返回值和参数类型、个数一致)。答:B -> F -> C -> A -> D -> E。

2024-07-28 19:50:22 493

原创 常量和指针

还是第二题答案的那句话:在赋值、初始化或参数传参的过程中,赋值号左边的类型应该比右边的类型限定更为严格,或至少是同样严格!答:因为 const 修饰的变量具有只读的特性,一旦生成变无法被改变,所以如果没有在定义的时候对它进行初始化,那它就失去了存在的意义。,即第一个 const 限制的是 **q 的指向,第二个 const 限制的是 *q 的指向,唯有一个漏网之鱼 —— q 没有被限制。答:因为没有用 const 修饰 * 这样的解释,所以这两种写法表示的含义其实是一样的,都是表示。

2024-07-27 23:22:21 815

原创 指向指针的指针

如上图所示,*pa 被定义为一个一维数组,其跨度为 2 个字节,所以 *(pa + 8) 指向的是 {'w', 'x'} 这个数组,所以 *(*(pa + 8) + 1) 取出 'x' 元素;*ppa 被定义为一个二维数组,其跨度为 6 个字节,所以 *(ppa + 2) 指向的是 {{'s', 't'}, {'u', 'v'}, {'w', 'x'}} 这个二维数组,所以 *(*(*(ppa + 2) + 2) + 1) 取出 'x' 元素。* 运算符的操作数必须是指针类型(地址),运算结果可以做左值。

2024-07-25 16:54:38 363

原创 void指针和NULL指针

比如目标平台是 32 位的,那么 sizeof(void*) 就是 4,如果是 64 位的,那么 sizeof(void *) 就是 8,如果是 16 位的,那么就是 2 啦。答:当你的指针不知道指向哪儿的时候,那么将它指向 NULL,以后就不会有太多的麻烦。那 void 既然是无类型,我们就不应该用它来定义一个变量,如果你一定要这么做,那么程序就会给你报错(我只是换个提问方式,看看多少童鞋会上当)。注:悬空指针就是指向了不确定的内存区域的指针,通常对这种指针进行操作会使程序发生不可预知的错误。

2024-07-24 23:41:52 827

原创 指针和二维数组

分析:对于初学者来说,这道题的难度级别很高,但当你尝试去理解它其中的原理之后,你会发现对指针的认识又深入了一点儿呢!等号右边强制将 array 这个一位数组重新划分成 3 * 3 的二维数组,然后用数组指针指向它(本章最后说如果要使用指针来指向二维数组,只能使用数组指针,还记得吗?答:*(matrix + 1) + 2 的含义是一个指向字符变量的指针,其值是二维数组 matrix 第二行第三个元素的地址(即 &matrix[1][2])。答:*(*(*(array+i)+j)+k)答:一样啊,怎么不一样?

2024-07-24 20:22:30 305

原创 指针数组和数组指针

array 是整个数组的地址,所以 &array + 1 指向整个数组最后的位置。同样的道理,int (*p)[10] 虽然是定义一个整型指针,但不要忘了它后边还有一个数组,所以它的跨度应该是 sizeof(int) * 10,而 array 作为数组名,它的含义是“指向数组第一个元素的地址”,所以 array 的跨度是 sizeof(array[0]),因此编译系统遇到 int (*p)[10] = array;解析:虽然 array 和 &array 的值相同,但含义是不一样的。

2024-07-24 15:13:58 260

原创 指针和数组

因为这么做会超出要求 1 个字符(比如要求拷贝 5 个字符,实际拷贝了 6 个),因为代码的逻辑是 *target2++ = *target1++ 先赋值,再判断 n--。所以 str[20] == *(str + 20) == *(20 + str) == [20]str。这道题比较考“经验”了,初学者很难想象出来的(So,想不出来不要泄气,以后看到就晓得了~)。答:*(str + 3) 恕我直言:写成 str + 3 或 *str + 3 的童鞋请面壁去……

2024-07-23 14:39:24 321

原创 指针C语言

实际上在内存中,它的存储方式仍然一维数组的线性方式扩展开而已。答:是一个 3 行 4 列的二维数组。由于我们这里只初始化了 10 个元素,并指定了该数组有 4 列,a[2][4] 是不够放了,只能用 a[3][4] 来存放,剩余的空间初始化为 0。如果它被定义为一个 5 行 4 列的二维数组(a[5][4]),那么请问 a[3][3] 的值是多少?So,a[3][3] 的值就是 4 行 4 列的值啦(从 0 开始数,还记得吗?答:五层,每一层一个维数,简单好记。,这是最好的方法,没有之一。

2024-03-30 23:34:08 113

原创 二维数组C

答:是一个 3 行 4 列的二维数组。由于我们这里只初始化了 10 个元素,并指定了该数组有 4 列,a[2][4] 是不够放了,只能用 a[3][4] 来存放,剩余的空间初始化为 0。如果它被定义为一个 5 行 4 列的二维数组(a[5][4]),那么请问 a[3][3] 的值是多少?答:sizeof(a) / sizeof(a[0][0]),这是最好的方法,没有之一。So,a[3][3] 的值就是 4 行 4 列的值啦(从 0 开始数,还记得吗?答:五层,每一层一个维数,简单好记。

2024-03-30 16:34:59 103

原创 编译器更新问题数组

(因为结果必须跟操作数同类型)所以 if (strlen(str1) - strlen(str2) < 0) 应该写成 if (strlen(str1) < strlen(str2))。答:不当使用 C 标准库中的 strncat 函数常常会导致差一错误(差一错误是指在计数时由于边界条件判断失误导致结果多了一或少了一的错误)和安全问题。答:结果应该是只打印 New 这个字符串。答:strncpy 函数并不会自动添加末尾的结束符('\0'),所以你如果拷贝了 n 个字符过去,但不包含结束符,问题就来了。

2024-03-26 20:16:48 96

原创 数组C语言

答:因为 C 语言追求的就是“短小快”,C 语言非常注重程序的速度,而增加边界检查会使速度相对变慢。很多朋友觉得这是 C 语言的缺陷,以后遇到这类问题,你可以傲娇地说“C 语言宁可增加 bug,也不愿意降低速度。因为 '\0' 代表 ASCII 码为 0 的字符,它不是一个可以显示的字符,而是一个“空操作符”,表示什么也不做。当然,C 语言的这种极端追求也是有用的。多数嵌入式芯片烧录的也是 C 的代码;答:至少需要 6 个元素,依次存放 'F', 'i', 's', 'h', 'C' , '\0'。

2024-03-26 00:11:28 131

原创 拾遗C语言

答:a = 14, b = 5, c = 9 解析:解答这道题需要充分消化这一节课我们所学习的内容,首先 b = 3(因为赋值运算符的优先级比逗号运算符高);c = b++ + 5,c = 8(因为 b++ 是先使用变量 b 的值,再将自身加一);a 最后的值是 ++c + ++b,此时 c = 8,b = 4,则 a = 9 + 5,最后 a = 14, b = 5, c = 9。因此第一进入循环判断时,取出的值是0,并不符合循环的条件,因此循环一次都没有被执行。答:a、b、c 都是"l-value"。

2024-03-24 18:24:40 123 1

原创 break语句和continue语句

在 while 语句中,调整部分是循环体的一部分,因此 continue 语句会把它也跳过(没错,小甲鱼觉得你可能又忘了,所以提醒你一下。例如,当偏移量是 3 的时候,所有的字母 A 将被替换成 D,B 变成 E,以此类推。答:很多次(实际上我测试了一下是 1078 次),很多朋友回答 4 次,那是你想当然的把 i 看成整数了,注意这里是浮点数。要求:用户输入一行明文(字符串),针对字母进行加密(偏移量设置为 3),非字母部分保留原型。答:只有当输入为数字时,才会执行语句A。最后的加 0.5 是一个。

2024-03-23 17:08:21 443 1

原创 for语句和嵌套循环

for 语句首先将 count 赋值为 0 后,进行第一次判断(count 是否小于 10),条件成立,执行循环体的内容;最后 count++,判断 count 是否小于 10(这是最后一次判断),结果为假,退出循环。课堂中我们实现的是“左下”三角形的形式打印,现在要求大家分别以“左上”、“右下”和“右上“三角形的形式打印。答:对于没有预先确定执行次数的循环(比如根据用户的输入内容决定是否进入下一轮循环),应该使用 while 语句。写一个程序,对用户输入的整数进行求和。版权属于:​​​​​​​。

2024-03-21 22:49:15 807 1

原创 WHILE语句和DOWHILE语句

先 getchar() 函数获得的值存放到变量 ch 中,再检测 ch 的值是否为空格(' '),如果是,执行循环体的内容,即空语句,然后开始第二轮循环……函数(定义于 <stdlib.h> 头文件中),用于将字符串中的值解析为对应的整型数字。因为决定退出 while 循环的条件表达式的值为 1,即永远为真,所以这是一个永远都不会结束的程序。B. 检测数值是否超出整型变量(int)可存放的范围,如果超出范围,则打印“数值超出范围,结果未定义。printf("请输入待转换的字符串:")

2024-03-19 19:58:16 1053 1

原创 switch语句和分支嵌套

因为字符串 "FishC" 依次对应的是 ch[0], ch[1], ch[2], ch[3], ch[4], ch[5](注:ch[5] 是表示字符串结束的 '\0')。C 语言的 switch 语句没有任何简便的方法指定某个范围的值,除非你将该范围内的每个值都以单独的 case 标签给出。B. 由于减法运算实质上就是特殊的加法运算(第二个操作数符号取反),所以在处理 case '-' 的时候,我们只是将第二个操作数符号取反,然后让程序执行 case '+'。其中 8 和 9 控制左电机的前进和后退。

2024-03-17 20:41:27 1001 1

原创 if语句C

第一次条件判断,如果 a > b,将两变量的值互换,确保 a

2024-03-14 19:22:47 591 1

原创 关系运算符和逻辑运算符

2)) + 3) – 1) – 3 == ((((1) + (0)) + 3) – 1) – 3 == …求值:((97 + 98) <= 99) || ((1 / 2) + (4 % 3)) == (195 <= 99) || (0 + 1) == 1。求值:a = ((b - c) || (1 && 0)) == a = (3 - 4) || 0 == a = (-1 || 0) == a = 1。求值:a = (2 && (3 - 4)) == a = (2 && -1) == a = 1。

2024-03-12 19:58:24 723 1

原创 算术运算符

C. 1.2 + 3 = 4.200000 // 浮点型加整型,编译器会自动将“精度较小”的类型先转换为“精度较大”的类型,再进行运算,所以结果为浮点型。如果不加小括号,那么变量 a 的值最终应该是 14 才对,因为赋值运算符的优先级要低于算术运算符,所以先计算,后赋值。答:虽然公式是正确的,但代码中忽视了 9 / 5 的结果会舍弃小数,等于 1,所以得到的答案偏差比较大。答:0,因为字符 'b' 对应的 ASCII 值为 98,a / 'b' == 2 / 98 == 0。“买房难,难于上青天……

2024-03-12 18:26:13 940 1

原创 字符串和字符

答:通过 变量名[索引号] 的方式可以访问字符数组中的任意一个元素(当然要在范围内),索引号是从 0 开始计算,所以通过 name[4] 可以访问字符 'C'。答:由于 name 变量是声明了 10 个字节的字符串,而 “FishC” 只需 6 个字节的空间来存放,因此多余的空间用 ‘\0’ 进行填充。所以 name 变量在内存中的存储形式应该是:'F','i','s','h','C','\0','\0','\0','\0','\0'。因为字符串最后需要加上一个 '\0' 字符表示结束。

2024-03-11 19:03:59 408

原创 取值范围C

例如 -8 的补码是 1111 1000,如果作为无符号数,其值则是 2^7 + 2^6 + 2^5 + 2^4 + 2^3 == 128 + 64 + 32 + 16 + 8 == 248。答:一个字节约定等于八个比特位(事实上 C 语言没有规定一个字节等于八个比特位,这只是约定俗成),因此一个字节可以表示最大的二进制数是 1111 1111。由于左边第一位是符号位,不能用于表示值的大小,因此一个字节可以表示的最大带符号整数是:0111 1111,转换成十进制数就是 127。

2024-01-25 22:32:21 251

原创 数据类型C

就在棋盘的第 1 格放 1 粒,第 2 格放 2 粒,第三格放 4 粒,以后每一格都比前一格增加一倍,依此放完棋盘 64 格,我就感激不尽了。结果在给达依尔麦子时舍罕惊奇地发现要给的麦子比自己想象的要多得多,于是他进行了计算,结果令他大惊失色。答:由于默认 int 是 signed 的,即带符号位的整数(可以表示负数),需要用一半的存储空间来存放负数;答:不是,虽然它跟 printf() 一样后边有个小括号,并在小括号中填入“参数”,但 sizeof 其实是一个特殊的操作符。答:错误的有 E 和 F。

2024-01-23 11:09:34 383 1

原创 c语言常量和宏定义

你需要为程序中的变量、类型、函数和标签起一个名字,我们把这个名字称之为?main 是一个合法的标识符吗?是,main 是函数的标识符名称。在 C 语言中,只要是数据,那就有类型。还有一个表示结束标志的 '\0'。

2024-01-22 17:32:21 339

原创 C语言变量

ANSI C,C99,C11定义的是 C 语言的标准和规则,简单的说就是定义了 C 语言的语法。变量名用于确定目标,存储单元用于存放变量的值。将变量 b 乘以 2 并赋值给 b(代码这么写:b = b * 2)计算圆的周长(公式:2 * 3.14 * r),并赋值给变量 c。计算圆的面积(公式:3.14 * r * r),并赋值给变量 s。声明一个变量 r,用来存放圆的半径。声明一个变量 c,用来存放圆的周长。声明一个变量 s,用来存放圆的面积。将变量 b 的值赋值给变量 a。将 3 赋值给变量 b。

2024-01-19 19:38:15 324 1

原创 c语言 打印 习题

b就是把下一个要输出的位置往前回退一个,不是删除前一个字符。默认情况下,下一个要输出的位置是当前位置的后一个。能正常输出和正常形式一样。

2024-01-18 23:50:27 377 1

原创 size of 函数输出字符所占字节长度

2024-01-17 13:35:39 339

原创 c语言常量和宏定义

2024-01-17 13:32:13 414

原创 嵌入式软件工程

打印。

2024-01-16 23:07:02 403

原创 嵌入式软件工程

数据类型。

2024-01-16 23:04:38 387

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除