1. Exercise 1 :See what you can C
# 用gcc 来编译可执行文件如program.c
gcc program.c
# 就可以得到一个executable file named a.out.
./a.out
# 如果想给这个可执行文件命名,则使用 -o
gcc -o program program.c
./program
# 使用-g 能得到一个 可执行程序的debugger程序
gcc -g -o hello hello.c
# 开始dubug,运行,在mac上用lldb
lldb hello
2. Exercise 2:Catch those bugs!
Answer the questions:
- While you’re in a gdb session, how do you set the arguments that will be passed to the program when it’s run?
chenhuiyi@bogon lab01 % lldb hello
(lldb) settings set target.run-args 1 2 3
(lldb) run
- How do you create a breakpoint?
(lldb) breakpoint set --name main
(lldb) breakpoint set --file test.c --line 12
此时,设置了断点但还没有执行程序,按以下步骤来执行程序并在断点处停止:
(lldb) target create my_program
启动你的程序,可以使用 run
命令:
(lldb) run
当程序执行到你之前设置的断点位置时,LLDB会自动将程序暂停,并在 (lldb) 提示符下等待你的命令,如图所示:
- How do you execute the next line of C code in the program after stopping at a breakpoint?
(lldb) step
- if the next line of code is a function call, you’ll execute the whole function call at once if you use your answer to #3. (If not, consider a different command for #3!) How do you tell GDB that you want to debug the code inside the function (i.e. step into the function) instead? (If you changed your answer to #3, then that answer is most likely now applicable here.)
使用 step
命令,但带上 -i
(或 --into
)选项,它告诉LLDB进入函数内部进行调试。
(lldb) step -i
当你完成函数内部的调试后,你可以使用 step
命令继续执行函数之后的代码,或者使用 finish
命令退出函数调用并返回到调用函数的上下文
5.How do you continue the program after stopping at a breakpoint?
(lldb) continue
- How can you print the value of a variable (or even an expression like 1+2) in gdb?
(lldb) print my_variable
(lldb) print 1 + 2
7.How do you configure gdb so it displays the value of a variable after every step?
可以通过设置检查点:
(lldb) watchpoint set variable my_variable
或者使用 display(我用display才能在打印台上看到)
(lldb) display count
- How do you show a list of all variables and their values in the current function?
(lldb) frame variable
argc=1表示只有一个变量,这个变量就是这个程序名称本身
- How do you quit out of lldb?
(lldb) quit
(lldb) q
Exercise 3:Debugging w/ YOU(ser input)
The purpose of this exercise is to make you unafraid of running the debugger even when your program needs user input. It turns out that you can send text to stdin
, the file stream read by the function fgets in this silly program, with some special characters right from the command line.
Hint 1: If you’re creating a text file containing your input, you’re on the right track!
(lldb)settings set target.input-path xxx.txt
(lldb)run
或者直接使用process launch 则不需要再加上run
(lldb) process launch --stdin input.txt
如果不进入lldb这个调试器的话,可以直接在terminal向可执行程序输入:
./a.out < fileName.txt
Exercise 4: Valgrind’ing away
lab推荐的是 Valgrind这个工具,是一个模拟你的GPU并且跟踪内存访问的程序。但是,在macos上没有可用的版本,通过这个命令可以看出:
brew info valgrind
从 segfault_ex
开始。你应该观察到了一个段错误(segfault),当程序试图访问它无权访问的内存时就会发生崩溃。
在macos上,可以使用Instruments 来检测内存访问问题:
(未解决)
nts 来检测内存访问问题:
(未解决)
Exercise 5:Pointers and Structures in C
Here’s one to help you in your interviews. In ll_cycle.c
, complete the function ll_has_cycle()
to implement the following algorithm for checking if a singly- linked list has a cycle.
- Start with two pointers at the head of the list. We’ll call the first one tortoise and the second one hare.
- Advance hare by two nodes. If this is not possible because of a null pointer, we have found the end of the list, and therefore the list is acyclic.
- Advance tortoise by one node. (A null pointer check is unnecessary. Why?)
- If tortoise and hare point to the same node, the list is cyclic. Otherwise, go back to step 2.
If you want to see the definition of the node
struct, open the ll_cycle.h
header file.
ll_cycle.h
:
#ifndef LL_CYCLE_H
#define LL_CYCLE_H
typedef struct node {
int value;
struct node *next;
} node;
int ll_has_cycle(node *);
#endif
在ll_cycle.c
补充代码:
#include <stddef.h>
#include "ll_cycle.h"
int ll_has_cycle(node *head) {
/* your code here */
// 判断一个链表是否有环,通常称为“乌龟和兔子”算法(也被称为Floyd的循环检测算法)。
//这个算法的核心思想是使用两个指针(乌龟和兔子)以不同的速度遍历链表。如果链表中存在环,这两个指针最终会在环内相遇。
node *tortoise = head,*hare = head;
while(hare!=NULL && hare->next!=NULL){ // 确保hare可以移动两步
hare = hare->next->next;
tortoise = tortoise->next;
if(tortoise == hare){
return 1;
}
}
return 0;
}
#选项 -c 表示只编译和汇编,但不链接。它会生成一个名为 ll_cycle.o 的目标文件(object file)
$ gcc -c ll_cycle.c
$ gcc -c test_ll_cycle.c
# 此命令将之前生成的两个目标文件(test_ll_cycle.o 和 ll_cycle.o)链接在一起,
# 创建一个可执行文件。-o test_ll_cycle 指定了输出的可执行文件名为 test_ll_cycle。
$ gcc -o test_ll_cycle test_ll_cycle.o ll_cycle.o
$ ./test_ll_cycle