1. Intermediate C Code Analysis Examples
1.1. Pointer Size and String Length
- Understand how a character pointer that points to a string literal behaves.
- Confirm that
sizeof and strlen calculate values using different criteria.
#include <stdio.h>
#include <string.h>
int main(void) {
char* text = "0123456789";
size_t result = sizeof(text) + strlen(text);
printf("%zu\n", result);
return 0;
}
char *text is not an array that stores the string contents; it is a pointer that stores the starting address of a string literal.
sizeof(text) is the size of the pointer variable itself, which is different from the length of the string it points to.
strlen(text) counts the number of characters from the location the pointer references until it reaches '\0'.
- The size of a pointer can vary depending on the execution environment, and this explanation uses a 64-bit environment as its basis.
1.2. Pointer Arithmetic
- An array name behaves like a value that represents the address of the first element, so it can be used like a pointer.
- Adding +1 to a pointer does not simply move it by 1 byte; it moves by the size of the data type and points to the next array element.
- In other words, the array name acts as the starting address, and pointer arithmetic has the same meaning as moving to the next slot in the array.
#include <stdio.h>
int main(void) {
int nums[] = {4, 8, 15, 16, 23, 42};
int *p = nums + 1;
int result = *(p + 2) + p[-1];
printf("%d\n", result);
return 0;
}
nums + 1 means the address of the second element in the array.
*(p + n) and p[n] are interpreted in the same way.
- Negative indexes such as
p[-1] are also calculated relative to the current pointer position.
1.3. Pointers as Function Arguments
- Understand that function arguments in C are passed by value.
- Understand why passing a pointer as an argument can allow the caller's variable to be modified.
- Compare how a variable passed by value and a variable passed by address differ after a function call.
#include <stdio.h>
static void update(int *left, int right) {
right += *left;
*left = right - (*left / 2);
}
int main(void) {
int x = 8;
int y = 3;
update(&x, y);
printf("%d\n", x + y);
return 0;
}
&x is the address of the variable x, and the original x can be accessed inside the function through *left.
- A value received as an ordinary integer argument does not affect the caller's variable even if it changes inside the function.
1.4. Double-Pointer Allocation
- Understand how to pass the address of dynamically allocated memory back to the caller from inside a function.
- Understand the flow of using
char ** to modify the caller's char * variable.
- Trace the process of copying a string into the allocated buffer and freeing it after use.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int make_copy(char **out, const char *src) {
size_t len = strlen(src);
*out = malloc(len + 1);
if (*out == NULL) {
return -1;
}
memcpy(*out, src, len + 1);
(*out)[0] = 'A';
return (int)len;
}
int main(void) {
char *buff = NULL;
int result = make_copy(&buff, "abcde");
if (result < 0) {
return 1;
}
printf("%s,%d\n", buff, result);
free(buff);
return 0;
}
&buff is the address of the pointer variable buff itself, and it can be received by a char ** parameter.
*out = malloc(...) makes the caller's buff point to the newly allocated memory.
- You must allocate
strlen(src) + 1 bytes so the null character can also be copied.
memcpy(..., len + 1) copies both the string body and the final '\0'.
(*out)[0] accesses the first character of the allocated string.
1.5. Buffer Size and String Accumulation
- Understand how to calculate the remaining buffer space when appending a new string after an existing string.
- Understand how the append function copies data only within the remaining available space.
- Trace how multiple function calls accumulate changes in the same buffer state.
#include <stdio.h>
#include <string.h>
static int append_limited(char *dst, size_t dst_size, const char *src) {
size_t dst_len = strlen(dst);
size_t src_len = strlen(src);
if (dst_len + src_len >= dst_size) {
size_t room = dst_size - dst_len - 1;
memcpy(dst + dst_len, src, room);
dst[dst_size - 1] = '\0';
return -1;
}
memcpy(dst + dst_len, src, src_len + 1);
return 0;
}
int main(void) {
char buffer[10] = "abcd";
append_limited(buffer, sizeof(buffer), "efgh");
append_limited(buffer, sizeof(buffer), "ijkl");
printf("%s\n", buffer);
return 0;
}
- When appending to the end of a string, you must calculate the current string length and the total buffer size so the buffer is not exceeded.
- You must also leave space for the null character ('\0') that marks the end of the string.
- When strings are appended multiple times, each new result continues accumulating from the previous result.
- The actual append position points to the end of the current string, expressed as
dst + dst_len.