跳转至

Lab 1: C

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. Dereferencing 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 (不可移动的).

C
1
char *my_str = "Hello";

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

C
1
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.

Warning
C
1
2
char* a = "hi";  // read-only memory, can't be moved
char b[] = "hi"; // stack, can be moved

What is a macro?

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:

C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#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:

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

with

C
1
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

Pointers

Pointers Details

Tips

This pointer_tutorial is the best one I have ever seen:) Thanks to UCB!

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 (bytes) to the address held in ptr.

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:

  • strlen: computes the length of a string by counting the number of characters before a null terminator
  • strcpy: copies a string from one memory location to another, one character at a time until it reaches a null terminator (the null terminator is copied as well)
Warning

strcpy is an unsafe function. We only allocate enough space in message to store the message hello, but then we try to store a longer message. When this happens, we overflow the space we allocated for message, and crash the program!

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.

For example, if longer_message has space for 10 characters, and message has space for 2 characters, fix the program in ex6_strcpy_fixed.c so that message stores 2 characters from longer_message.

Struct

I think there are 3 ways to present Structure:

1) Class + object simultaneously

C
1
2
3
4
struct Class{
    int a;
    int b;
 }object;

You can use object now.

2) Class then object (directly)

C
1
2
3
4
5
6
7
8
struct Class{
   int a;
   int b;
}

...

struct Class object;

3) Class then object (alias)

C
1
2
3
4
5
6
7
8
typedef struct{
   int a;
   int b;
}Class;

...

Class object;

In this way, 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.