Lab1 C(完全完成)

Exercise 1: Hello!

首先我们对lab01里面的ex1_hello.c文件执行gcc ex1_hello.c得到
Pasted image 20240918170004.png

这里我们把ex1_hello.c文件compile成了可执行文件a.out

接下来我们在文件里面执行```

./a.out

得到
Pasted image 20240918170152.png

在图中,我们看到执行./a.out之前我们执行了一个啊a.out但是报错了。为什么呢?

The executable file is a.out, so what is the ./ for?

Answer

Answer: when you want to execute an executable, you need to prepend the path to the name of the executable. The dot refers to the "current directory." Double dots (..) would refer to the directory one level up.

还有一点就是,直接输入刚才那串,系统可能会在环境变量中寻找此命令。

gcc编译命令

gcc -o ex1_hello ex1_hello.c

解释

Review: Pointers

一段代码

int main() {
    int my_var = 20;
    int* my_var_p;
    my_var_p = &my_var;
}

一句话

Note

In a nutshell, &x gets the address of x, while *x gets the contents at address x.

Exercise 2: Pointers and Functions

第二个小练习很简单。

Pasted image 20240918180945.png
第一个是传入了一个int变量,但是子函数有自己的stack frame,第二个直接传入地址,修改的就是地址对应的内容。

Review: Arrays

An array is a fixed length data structure that can hold one or more elements of the same type.

In C, arrays are represented as a pointer to the first element.

Exercise 3: Arrays

非常简单,不再介绍

Review: Pointer Arithmetic

When performing pointer arithmetic, C automatically accounts for the type of the pointer and adds the correct number of bytes.

For example, if you write ptr + 5, C will not always add 5 to ptr. Instead, C will add 5 times the size of the datatype that ptr points to.

If ptr was an int* and ints take up 4 bytes in memory, ptr + 5 adds 20 to the address held in ptr.

Exercise 4: Pointer Arithmetic

这个也简单,主要看review就可以

Review: Strings

In C, strings are represented as an array of chars. Strings are a special type of char arrays because they always end in a null terminator (\0). Recall that arrays in C do not contain any information about their length, so the null terminator allows us to determine when the string ends.

When allocating memory for a string, there must be enough memory to store the characters within the string and the null terminator. Otherwise, you might run into undefined behavior. However, the array could be larger than the string it stores.

C has a library of functions for manipulating strings, such as:

Exercise 5: Strings

很简单

Exercise 6: Copying Strings

Pasted image 20240918191354.png
运行后我们发现
Pasted image 20240918191439.png
这是故意的
Pasted image 20240918191403.png

我们改成strncpy之后

Fix the program in ex6_strcpy_fixed.c using strncpy (documentation) so that it stores as many characters of longer_message as you can in message without changing the size of message.

Pasted image 20240918192104.png

Exercise 7: Structs

依旧非常简单

注意下

Pasted image 20240918192516.png

In these cases, you may use Student as the type instead of struct Student. We won't go into detail here, but feel free to check out this link if you're interested.

FAQ

What is a header file?

Header files allow you to share functions and macros across different source files. For more info, see the GCC header docs.

What is a null terminator?

A null terminator is a character used to denote the end of a string in C. The null terminator is written as '\0'. The ASCII value of the null terminator is 0. When you make a character array, you should terminate the array with a null terminator like this

char my_str[] = {'e', 'x', 'a', 'm', 'p', 'l', 'e', '\0'};

If you are using double quotes to create a string, the null terminator is implicitly added, so you should not add it yourself. For example:

char *my_str = "example";

What is an executable?

An executable is a file composed of binary that can be executed on your computer. Executables are created by compiling source code.

What is strlen?

See the man pages for a full description. Type the following into your terminal

man strlen

To exit the man pages, press q.

What is a macro?

Chapter 1 Getting Started#Preprocessor and macros于老师的课程介绍

A macro is a chunk of text that has a name. Whenever this name appears in code, the preprocessor replaces the name with the text. Macros are indicated with #define For example:

#define ARR_SIZE 1024
#define min(X, Y)  ((X) < (Y) ? (X) : (Y))

int main() {
    int arr1[ARR_SIZE];
    int arr2[ARR_SIZE];
    int arr3[ARR_SIZE];

    for (int i = 0; i < ARR_SIZE; ++i) {
        arr3[i] = min(arr1[i], arr2[i]);
    }
}

In this code, the preprocessor will replace ARR_SIZE with 1024, and it will replace

arr3[i] = min(arr1[i], arr2[i]);

with

arr3[i] = ((arr1[i]) < (arr2[i]) ? (arr1[i]) : (arr2[i]));

Macros can be much more complex than the example above. You can find more information in the GCC docs

What is a segfault?

A segfault occurs when you try to access a piece of memory that "does not belong to you." There are several things that can cause a segfault including

  1. Accessing an array out of bounds. Note that accessing an array out of bounds will not always lead to a segfault. The index at which a segfault will occur is somewhat unpredictable.
  2. Derefrencing a null pointer.
  3. Accessing a pointer that has been free'd (free is not in the scope of this lab).
  4. Attempting to write to read-only memory. For example, strings created with the following syntax are read only. This means that you cannot alter the value of the string after you have created it. In other words, it is immutable.
char *my_str = "Hello";

However, a string created using the following syntax is mutable.

char my_str[] = "hello";

Why is the first string immutable while the second string is mutable? The first string is stored in the data portion of memory which is read-only while the second string is stored on the stack.