Learn C the hard way

笨办法学c,ysyx前置课程

参考资料:Learn C the hard way

实验系统:macos

文本编辑器:Sublime


Exercise 1

int main(int argc, char *argv[])
{
    puts("Hello world.");

    return 0;
}

在终端中make

报错,与书中写的似乎不同,无法make

添加编译警告后make

依然如此,问题是缺少头文件,修改代码包含进stdio.h

再次make,成功,生成ex1可执行文件并执行

./ex1

正常输出“Hello world”

附加题

1.删除 return 0 后make,期望得到返回值的warning,结果是没有返回值的warning(即使打开编译器警告),主函数默认返回了0

2.puts函数似乎是自动换行的

3.man 3 puts看一下即可

Exercise 2

主要介绍了Makefile

CFLAGS=-Wall -g

clean:
    rm -f ex1

Makefile的内容,

CFLAGS:打开编译warning

clean:快速清理项目

Makefile可作为一个快捷工具,在终端中执行make clean即可删除ex1可执行文件,并且默认开启了编译时warning

在编写Makefile的时候,注意要打开编辑器设置,取消把tab转换成空格的设定,可以只针对某一类文件勾选(例如Makefile),否则其他文件可能会出问题

附加题

1.只使用make就可以编译,借助于all:ex1

原理是make的时候默认会去找第一条make的目标,自然而然就找到了ex1。使用all还有一个好处,就是可以在后面添加多个程序,这样就可以一次性make整个大项目出来。

make ex1的时候,语法指定如下

cc $(CFLAGS) -o ex1 ex1.c

这里CFLAGS是开头定义的编译规则,也可以替换成 -Wall -g,但是这样写有多个目标需要make的时候就不便于管理,因此需要在开头统一定义

ex1:ex1.c监测ex1是不是最新的ex1 make出来的,如果是就make,不是则提示

make: Nothing to be done for `all'.

 

Makefile如下

CFLAGS=-Wall -g

all:ex1

ex1:ex1.c
	cc $(CFLAGS) -o ex1 ex1.c

clean:
    rm -f ex1

 

2 & 3.

man make和man cc看一下既可

4.可加入自动变量来代替ex1,但个人感觉不太直观

5.还没做

Exercise 3

介绍了格式化输出

格式字符串(%d,%f)等,会将变量替换进输出中

如果后面不带变量,编译器会自己指定成随机的

如果不初始化变量,也会制定成随机的

附加题

1.改变量名、改语法错误等

2.man 3 printf 查看即可

3.编写makefile

  • 收回Exercise 2 里的认识,自动变量很有用

现在需要同时make项目下的所有文件,假设为ex1,ex2,ex3,同时把他们一起clean掉

clean 简单,直接rm ex1 ex2 ex3即可(空格隔开)

make的时候,为了优雅地写,不给每个c文件单独制定make选项,需要使用通配符%

$@ 代表所有构件目标

$< 代表所有源文件

原理是当all发现通配符下的一个需要构建的文件时候,就将目标和源文件替换

Makefile 如下

CFLAGS=-Wall -g

all:ex1 ex2 ex3

%:%.c
	cc $(CFLAGS) -o $@
 
lt; clean: rm -f ex1,ex2,ex3 

Exercise 4

介绍了Valgrind工具,用于检查代码错误并报告

本次更换了实验环境,原因是arm架构的mac本不支持Valgrind工具的安装,开了一个虚拟机,之后和Valgrind有关的都用虚拟机解决

但是,由于内核的版本过高了,源码编译要找到合适的版本比较困难,因此还是apt install了,之后有空再用源码编译一下

附加题

1.把未初始化的变量初始化即可

2.

3.

4.大致是这样:coregrind/目录下存放了二进制插桩(DBI)引擎,将机器码转换为IR表示,在此基础上分析代码。VEX/存放了不同架构下的转换库,include/存放了公共头文件与上述各个模块通信之间的API

Exercise 5

介绍了C程序的基本结构

学习过,没有问题

附加题

Exercise 6

介绍了变量类型

主要是学过的,%d,%f,%c,%s

补充:变量名称搭配错误会引起段错误(Segmentation fault),原因是访问了不该访问的内存,导致错误,在搭配错误时因为不同变量所占内存空间不同会导致这个错误

附加题

4.打印空字符串:使用格式化输出即可,%s," "

Exercise 7

介绍了变量的一些规则

char类型的变量被写入printf表达式时,会自动进行整数提升,转化为ASCII中的int类型

然而%s期望得到一个指向字符串首地址的指针,因此变量类型不匹配,会引发段错误

附加题

1,2.当数字越界时会保存溢出值并打印,依据编译器不同而打印的值不同,不可预知

4.unsigned把有符号数的符号位也用来表示数

5.整数提升,char将字符转化为int,因此可以相乘

Exercise 8

隐晦地介绍了字符串的内容

字符串以\0结尾以让编译器识别字符串的结尾

手动定义字符串时,用这种形式char name[]="Zed"编译器会自动补\0,如果用引号定义一个个字符(例如char name = ["Z","e","d","\0"]),最后要加\0否则会报错,当然在main函数外这么定义可能会成功

附加题

1,2,3.常用的赋值操作,都是合法的,注意字符串的索引,最后一位为空

4.(AI搜集)


  • 8位 CPU (如 Arduino Uno): int 通常是16位 (2字节)。



  • 16位 CPU (如 早期DOS系统): int 通常是16位 (2字节)。



  • 32位 CPU (如 x86): int 通常是32位 (4字节)。long 也通常是32位。


  • 64位 CPU (如 x86-64, ARM64):

    • Linux 和 macOS 上,通常采用 LP64 模型int 是32位 (4字节),long 是64位 (8字节),指针是64位。
    • Windows 上,通常采用 LLP64 模型int 是32位 (4字节),long 也是32位 (4字节),long long 是64位 (8字节),指针是64位。

Exercise 9

还是字符串

附加题

1.会报错,但是编译器进行整数提升,同时会因为编译器的问题,自动寻址到字符的最低位地址对应的字符输出了

2.不报错,打印字符对应的ASCII码

4.可以,使用指针引用首字符的地址即可,打印出的整数是这四个字符拼在一起得到的

我的代码是这样

char* q = name;
int* p = (int*) q;
printf("%d",*p);

 

6.题目的意思似乎是要命名一个指针指向“Zed”

可以写一段测试代码

char* another = name;
another[0]="m";

使用Valgrind检查,报了段错误,根本原因是“Zed”这个字符串被加载到了只读的内存区域

但是使用数组时,可以修改内容,这是因为声明数组的内容是在栈中的,可以修改

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Puff
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇