---
title: C Language Fundamentals
description: "## Course Objective ## Why Learn C Language? ### From Reverse Engineering Perspective In Android application security analysis, we encounter different implementation approaches: \"We don't approach this from a development perspective, but rather from a reverse engineering perspective. As long…"
url: "https://www.nullflag.com/support/kb/cpp_c_java_arm64_javascript/c_basic/c-language-fundamentals/"
updated: "2025-11-03"
category: C Lang
---

# C Language Fundamentals

## Course Objective

## Why Learn C Language?

### From Reverse Engineering Perspective

In Android application security analysis, we encounter different implementation approaches:

"We don't approach this from a development perspective, but rather from a reverse engineering perspective. As long as we can understand and analyze, that's sufficient. Different goals lead to different levels of learning difficulty.

Why learn C language for app reverse engineering?

Because most app algorithms are developed at the Java layer, which is relatively easy to implement. To prevent algorithms from being found through Java decompilation and to discover the specific encryption process, developers must increase the difficulty of cracking, so they use C language for development.

When encountering APKs, use JADX for decompilation, When encountering SO dynamic libraries, use IDA for decompilation.

Finally, use hooking methods to pass values and observe the value transmission process.

This is the reverse engineering perspective.

From an Android development perspective: By implementing the developer's process, we know how this encryption was implemented."

![](https://support.nullflag.com/wp-content/uploads/2025/10/image-20251103190027977-1024x716.png)

There is a MainActivity, and when this app first starts, there's an onCreate function that calls a method in some class. If a certain core parameter is obtained, then calling the encryption function at the Java layer can achieve encrypted submission. However, to increase the difficulty of cracking, we need to introduce functions written in C language.

In the next section, we'll cover JNI development, using System.loadLibrary to call a native function that is written in C language. We can see the specific implementation of the encrypt function in the crypt.c file.

### Android Development Context

If you see System.loadLibrary("Crypt"); this code in the JADX decompiled code, it indicates that you need to find the libCrypt.so file in the app's dynamic libraries and drag it into IDA for decompilation. By finding the exported function Java_com_yoloho_libcore_util_Crypt_encrypt_1data() in the SO file, you can roughly understand its meaning from the pseudocode. You need to understand their logic.

![](https://support.nullflag.com/wp-content/uploads/2025/10/image-20251103193408006-1024x730.png)

This course provides an introduction to C language programming concepts, specifically designed for reverse engineering and mobile security analysis. Students will learn essential C programming concepts including data types, pointers, arrays, structures, and linked lists.

## 1. C Language Development Environment Setup

### Three Essential Components:

1. **Language Syntax**: Learn C grammar and write code
2. **Compiler/Interpreter**: Compile and run code
3. **IDE**: Rapid development environment

### 1.1 Compilers

After writing C code following the language syntax, it needs to be compiled by a compiler before execution.

```cpp

                #include <stdio.h>

int main(int argc, char const *argv[]) {
    printf("hello worldn");
    return 0;
}
```

**Compilation in Terminal:**

```
>>> gcc main.c
>>> ./a.out
```

### Common C Compilers:

- **GCC**: GNU Compiler Collection (most widely used)
- **MSVC**: Microsoft Visual C++ Compiler
- **Clang**: LLVM-based compiler

### Platform-Specific Installation:

**macOS:**

- Default: Clang compiler (built-in with Xcode command line tools)
- If not available: Install Xcode from https://developer.apple.com/xcode/

**Windows:**

- Recommended: MinGW (Minimalist GNU for Windows)
- Download: https://osdn.net/projects/mingw/downloads/68260/mingw-get-setup.exe

### 1.2 Integrated Development Environment (IDE)

**CLion by JetBrains:**

- Download: https://www.jetbrains.com/clion/download/other.html
- Recommended versions: 2023.3.1 (easier licensing) or latest 2025.3.1

## 2. C Language Syntax Fundamentals

### 2.1 String Handling

**Important Concept**: C language does not have built-in string data types.

```cpp

#include <stdio.h>

int main() {
    // Single character
    char letter = 'A';   // Only single quotes can be used here, not double quotes. This creates a character. It occupies one byte of storage.

    // Character array
    char word[5] = {'c', 'a', 'l', 'l', ' '};  // "call" — the brackets [5] mean there are 5 elements. ' ' is a null terminator that marks the end of the string "call".

    // Character array = string
    char phrase[] = "clang-basic-lesson"; // {'c','l','a','n','g','-','b','a','s','i','c','-','l','e','s','s','o','n',' '} — although it looks like a string, it is actually a character array at the underlying level. "phrase" represents this string.

    // Print single character
    printf("%cn", letter);  // %c is used for printing characters

    // Print character array "word"
    printf("%sn", word);  // %s is used for printing strings

    // Print character array "phrase"
    printf("%sn", phrase);  // %s is used for printing strings

    // Print Hello, Calleng!
    printf("Hello, Calleng!n");

    return 0;
}
```

```cpp

                #include <stdio.h>
#include <string.h>

int main(int argc, char const *argv[])
{
    // ---------------------------------------------
    // 1. Character type (1 byte storage)
    // ---------------------------------------------
    char v1 = 'w';
    printf("v1 value: %cn", v1);
    // %c is used to print a single character (not a string).

    // ---------------------------------------------
    // 2. Character array -> String
    // ---------------------------------------------
    char v2[10] = {'j', 'o', 'e', 'b', 'i', 'd', 'd', 'e', 'n', ' '};
    printf("v2 value: %sn", v2);
    // %s prints a null-terminated string (ends with ' ').
    // If ' ' is missing, printf() may read beyond memory and cause errors.

    // ---------------------------------------------
    // 3. Character array with sizeof() calculation
    // ---------------------------------------------
    char v3[] = "NullFlag";
    int length = sizeof(v3) / sizeof(char);
    // sizeof(v3) gives the total size in bytes (includes ' ').
    // Dividing by sizeof(char) gives the total number of stored characters, including the null terminator.
    // So the result here is 9 (8 visible chars + 1 ' ').

    printf("v3 value: %s, length: %dn", v3, length);
    // Note: sizeof() measures memory size, not logical string length.
    // For logical string length (excluding ' '), use strlen() instead.

    // ---------------------------------------------
    // 4. Integer array and sizeof()
    // ---------------------------------------------
    int ch_array[3] = {100, 200, 300};
    int ch_array_size = sizeof(ch_array);

    printf("ch_array size is %dn", ch_array_size);
    // Output: 12, because each int occupies 4 bytes, and 3 * 4 = 12.
    // sizeof() returns the total byte size.
    // To get the number of elements: sizeof(ch_array) / sizeof(int) = 3.

    // ---------------------------------------------
    // 5. Character array with Chinese characters (UTF-8)
    // ---------------------------------------------
    char Chinese_characters[] = "中文Bidden";
    // In UTF-8 encoding, each Chinese character (like '中' or '文') typically occupies 3 bytes.
    // "中文" = 6 bytes, "Bidden" = 6 bytes, plus ' ' = 1 byte → total 13 bytes in memory.

    int len = sizeof(Chinese_characters) / sizeof(char);
    printf("Chinese_characters value: %s, total bytes: %dn", Chinese_characters, len);
    // sizeof() counts the total bytes in memory, including ' '.

    // ---------------------------------------------
    // 6. String length calculation with strlen()
    // ---------------------------------------------
    unsigned long dataLen = strlen(Chinese_characters);
    printf("using function strlen() Length: %lun", dataLen);
    // strlen() returns the number of visible characters (not including ' ').
    // sizeof() counts total memory size (including ' ').

    return 0;  // Finally, remember: bytes, characters, character arrays, and how they are represented — these are the core concepts you must understand first when learning strings.
}
```

### 2.2 Arrays

**Key Concept**: Array elements are stored contiguously in memory with adjacent addresses.

```
char v2[3] = {'w','u','p'};
int v3[3] = {11,22,33};
```

**Array Characteristics:**

- Fixed number of elements
- Fixed data types (each element occupies same memory size)

```cpp

                #include <stdio.h>

int main() {
    char v3[] = "calleng";

    printf("Position 0 value: %c, memory address: %p n", v3[0], &v3[0]);
    printf("Position 1 value: %c, memory address: %p n", v3[1], &v3[1]);
    printf("Position 2 value: %c, memory address: %p n", v3[2], &v3[2]);

    return 0;
}
```

```cpp

                #include <stdio.h>

int main(int argc, char const *argv[]) {
    int v3[] = {11, 22, 33, 44, 55, 66};  // Each integer occupies 4 bytes
    printf("Position 0 value: %d, memory address: %p n", v3[0], &v3[0]); // 0x00000
    printf("Position 1 value: %d, memory address: %p n", v3[1], &v3[1]); // 0x00004
    printf("Position 2 value: %d, memory address: %p n", v3[2], &v3[2]); // 0x00008
    return 0;
}
```

**Array Variable as Pointer**

```cpp

                #include <stdio.h>

int main(int argc, char const *argv[]) {
    // Character array
    char v3[] = {'c', 'a', 'l', 'l', 'e', 'n', 'g'};
    printf("v3 value: %p n", v3);      // Array name = first element address
    printf("v3 address: %p n", &v3);    // Array address
    printf("v3[0] address: %p n", &v3[0]); // First element address
    printf("v3[1] address: %p n", &v3[1]); // Second element address

    return 0;
}
```

### 2.3 Integer Data Types

**Memory Allocation:**

- `short`: 2 bytes
- `int`: 4 bytes
- `long`: 8 bytes

```cpp

                #include <stdio.h>

int main(int argc, char const *argv[]) {
    // Signed vs Unsigned
    // signed short v4[] = {11, 22, 33};    // Default: signed
    // unsigned short v4[] = {11, 22, 33};   // Unsigned

    short v4[] = {-11, 22, 33};
    printf("Value: %d, memory address: %pn", v4[0], &v4[0]);
    printf("Value: %d, memory address: %pn", v4[1], &v4[1]);

    return 0;
}
```

### 2.4 Pointers

#### Pointer Concept Visualization

```
Memory Layout:

      Memory Location
$
 0x7ffd257fceac    666        v1 points here
 0x7ffd257fcea0  0x7ffd...    v2 points here (stores v1's address)
```

#### Basic Pointer Syntax

```
int v1 = 666;
int* v2 = &v1;   // & operator: Get memory address (8 bytes on 64-bit systems)
```

```cpp

                #include <stdio.h>

int main() {
    int v1 = 666;
    int* v2 = &v1;

    printf("v1 value: %d, memory address: %p n", v1, &v1);
    printf("v2 value: %p, memory address: %p n", v2, &v2);

    return 0;
}
```

**Output:**

```
v1 value: 666, memory address: 0x7ffd257fceac
v2 value: 0x7ffd257fceac, memory address: 0x7ffd257fcea0
```

```cpp

                int v1 = 666;
int* v2 = &v1;

// If you have a pointer variable v2 storing a memory address,
// how do you get the value at that address?
int v3 = *v2; // 666 (dereference operator)
```

**Key Pointer Operators:**

- `&variable`: Get memory address of variable
- `*pointer`: Get value stored at memory address pointed to by pointer

```cpp

                #include <stdio.h>

int main() {
    int v1 = 666;
    int* v2 = &v1;
    int* v3 = &v1;

    v1 = 999;

    printf("v2 pointer value: %d n", *v2); // 999
    printf("v3 pointer value: %d n", *v3); // 999

    return 0;
}
```

```cpp

                #include <stdio.h>

int main() {
    int v1 = 666;
    int* v2 = &v1;
    int* v3 = &v1;

    printf("v2 pointer value: %d n", *v2); // 666
    printf("v3 pointer value: %d n", *v3); // 666

    *v2 = 888; // Modify value through pointer

    printf("v2 pointer value: %d n", *v2); // 888
    printf("v3 pointer value: %d n", *v3); // 888
    printf("v1 value: %d n", v1);           // 888

    return 0;
}
```

```cpp

                #include <stdio.h>

void modifyValue(int *arg) {
    *arg = 555;
}

int main() {
    int v1 = 666;
    modifyValue(&v1);  // Pass address
    printf("v1 value after modification: %d n", v1); // 555

    return 0;
}
```

#### Critical Warning for Reverse Engineers

When analyzing C code, be cautious about function calls:

```
v1 = 123;
doEncrypt(&v1);  // DANGEROUS: v1's value may change after this call

// Later in code, v1 might not be 123 anymore!
```

vs.

```
v1 = 123;
doEncrypt(v1);   // SAFE: v1 will remain 123

// v1 is guaranteed to still be 123
```

#### Pointer Summary

- **Essence**: Pointers are data types representing memory addresses, enabling multiple variables to reference the same value
- **Pointer Types**: `int*`, `char*`, `short*`, etc.
- **Key Operators**: `&` (address of) and `*` (dereference)
- **Memory Usage**: One pointer occupies 8 bytes on 64-bit systems
- **Purpose**: Memory efficiency and shared data access

### 2.5 Advanced Pointer Concepts

### Pointer Arithmetic Examples

```cpp

                #include <stdio.h>

int main() {
    char v34[] = {'a', 'e', 'x'};
    char *v28 = v34;  // Points to first element

    printf("v34[0]: %c, address: %p n", v34[0], &v34[0]);
    printf("v34[1]: %c, address: %p n", v34[1], &v34[1]);
    printf("v34[2]: %c, address: %p n", v34[2], &v34[2]);

    printf("v28 initial value: %p n", v28);
    v28 += 1;
    printf("v28 after +1: %p n", v28);
    v28 += 1;
    printf("v28 after +2: %p n", v28);

    return 0;
}
```

```cpp

                #include <stdio.h>

int main() {
    char v34[] = {'a', 'e', 'x'};
    char *v28 = v34;

    printf("v28: %p, value: %c n", v28, *v28);
    v28 += 1;
    printf("v28: %p, value: %c n", v28, *v28);
    v28 += 1;
    printf("v28: %p, value: %c n", v28, *v28);

    return 0;
}
```

```cpp

                #include <stdio.h>

int main() {
    char v34[] = {'a', 'e', 'x'};
    char *v28 = v34;

    v28 += 1;        // Point to second element
    *v28 = 'b';      // Modify it

    printf("v34[0]: %c n", v34[0]); // 'a'
    printf("v34[1]: %c n", v34[1]); // 'b' (modified)
    printf("v34[2]: %c n", v34[2]); // 'x'

    return 0;
}
```

### String Manipulation Examples

```cpp

                #include <stdio.h>
#include <string.h>

int main() {
    char name[] = "calleng";

    // Check if substring "pe" exists in name
    char *res = strstr(name, "pe");
    if (res == NULL) {
        printf("Not foundn");
    } else {
        printf("Found at position: %pn", res);
    }

    return 0;
}
// Application: Anti-debugging techniques (checking for "frida/tmp" strings)
```

```cpp

                #include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main() {
    char name[] = "wupeiqi";
    printf("Original: %s, address: %pn", name, name);

    // Allocate memory for copy (+1 for null terminator)
    char *newName = malloc(strlen(name) + 1);

    // Copy content
    strcpy(newName, name);

    printf("Copy: %s, address: %pn", newName, newName);

    // Free allocated memory
    free(newName);

    return 0;
}
```

```cpp

                #include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main() {
    char name[] = "Joe";
    char role[] = "Bidden";

    // Allocate sufficient memory
    char *result = malloc(strlen(name) + strlen(role) + 1);

    // Concatenate strings
    strcpy(result, name);
    strcat(result, role);

    printf("Result: %sn", result); // "JoeBidden"

    free(result);
    return 0;
}
```

### 2.6 Pointer to Pointer

**Concept**: Pointers can point to other pointers, creating multiple levels of indirection.

```
Memory Layout:

     Level 1 (Data)
$
 0x1000  666                   v1 points here
 0x2000  0x1000                v2 points here (stores v1's address)
 0x3000  0x2000                v3 points here (stores v2's address)
```

```
int v1 = 666;
int* v2 = &v1;     // Single pointer
int* v3 = &v1;     // Single pointer
int** v4 = &v2;    // Pointer to pointer
int*** v5 = &v4;   // Pointer to pointer to pointer
```

**Essence**: Pointers enable data manipulation based on memory addresses, providing powerful control over program memory.

### 2.7 Structures

Structures allow grouping of related data under a single name.

```cpp

                #include <stdio.h>

struct Person {
    char name[30];
    int age;
};

int main() {
    struct Person v1 = {"Obama", 18};
    struct Person v2 = {"Trump", 3};
    struct Person v3 = {"Kelinton", 31};

    printf("Name: %sn", v1.name);
    return 0;
}
```

```cpp

                #include <stdio.h>

struct Person {
    char name[30];
    int age;
};

int main() {
    struct Person v1 = {"elop of Nokia CEO", 18};

    // Direct member access
    printf("Name: %s n", v1.name);

    // Pointer to structure
    struct Person *pp = &v1;

    // Access through pointer with dereference
    printf("Name: %s n", (*pp).name);

    // Access through pointer with arrow operator
    printf("Name: %s n", pp->name);

    return 0;
}
```

**Linked Lists Implementation**

```
Visualization:

 11   22   33  NULL
```

```cpp

                struct Node {
    int data;
    struct Node *next; // Pointer to next node
};

// Node creation
struct Node v3 = {33, NULL};
struct Node v2 = {22, &v3};
struct Node v1 = {11, &v2};

// Access patterns
v1.data;                   // 11
(*v1.next).data;          // 22
v1.next->data;            // 22
v1.next->next->data;      // 33
```

```cpp

                #include <stdio.h>

struct Person {
    int data;
    struct Person *next;
};

int main(int argc, char const *argv[]) {
    struct Person p3 = {33};
    struct Person p2 = {22, &p3};
    struct Person p1 = {11, &p2};

    printf("p1 data: %dn", p1.data);
    printf("p2 data: %dn", p1.next->data);
    printf("p3 data: %dn", p1.next->next->data);

    return 0;
}
```

```
Visualization:
NULLNULL
       11      22      33
```

```cpp

                #include <stdio.h>

struct Person {
    int data;
    struct Person *next;    // Next node pointer
    struct Person *prev;    // Previous node pointer
};

int main() {
    struct Person p3 = {33};
    struct Person p2 = {22};
    struct Person p1 = {11};

    // Set forward links
    p1.next = &p2;
    p2.next = &p3;

    // Set backward links
    p2.prev = &p1;
    p3.prev = &p2;

    // Forward traversal
    printf("Forward: %d -> %d -> %dn",
           p1.data, p1.next->data, p1.next->next->data);

    // Backward traversal
    printf("Backward: %d -> %d -> %dn",
           p3.data, p3.prev->data, p3.prev->prev->data);

    return 0;
}
```

```
Visualization:

           

 11      22      33
```

```cpp

                #include <stdio.h>

struct Person {
    int data;
    struct Person *next;
    struct Person *prev;
};

int main() {
    struct Person p3 = {33};
    struct Person p2 = {22};
    struct Person p1 = {11};

    // Create circular links
    p1.next = &p2;    p1.prev = &p3;
    p2.next = &p3;    p2.prev = &p1;
    p3.next = &p1;    p3.prev = &p2;

    // Circular traversal
    printf("Circular traversal:n");
    printf("Position 1: %dn", p1.data);
    printf("Position 2: %dn", p1.next->data);
    printf("Position 3: %dn", p1.next->next->data);
    printf("Back to 1: %dn", p1.next->next->next->data);

    return 0;
}
```

### 2.8 Preprocessor and Header Files

**Preprocessor**: Runs before program compilation.

```cpp

                #include <stdio.h>

#define ME    2024
#define SIZE  07

int main() {
    int data = 19;
    printf("%d-%d-%d n", ME, SIZE, data);
    return 0;
}
```

```cpp

                #include <stdio.h>

#define ADD(x1, x2) (x1 + x2 + 100)

int main() {
    int data = ADD(11, 22); // 11 + 22 + 100
    printf("Result: %d n", data);
    return 0;
}
```

```cpp

                #include <stdio.h>

#define DB(x1, x2) (x1 * x2)

int main() {
    int data = DB(2 + 1, 4);  // Becomes: (2 + 1 * 4) = 6, not 12
    printf("Result: %d n", data);
    return 0;
}
```

**Multi-file Projects**

**Project Structure:**

```
project/
 main.c
 utils.c
 utils.h
```

```cpp

                // Function declaration
int plus(int v1);
```

```cpp

                int plus(int v1) {
    return v1 + 100;
}
```

**Main File (main.c):**

```cpp

                #include <stdio.h>
#include "utils.h"  // Include custom header

int main() {
    int data = plus(100);
    printf("Result: %d n", data);
    return 0;
}
```

**Application Note**: For JNI development, we include C standard library headers and JNI-specific headers to access native functionality.

## 3. Summary and Key Concepts

### Core Takeaways

1. **Memory Management**: Understanding pointers is crucial for reverse engineering
2. **Data Structures**: Arrays, structures, and linked lists form the foundation
3. **Type System**: Strong typing with explicit memory allocation
4. **Preprocessor**: Macro substitution before compilation
5. **Multi-file Projects**: Header files enable modular development

### For Reverse Engineers

- **Pointer Analysis**: Essential for understanding data flow
- **Memory Layout**: Critical for buffer overflow and memory corruption analysis
- **Structure Definitions**: Key to reverse engineering complex data formats
- **JNI Integration**: Important for Android native code analysis

### Next Steps

This foundation enables:

- Advanced reverse engineering techniques
- Binary exploitation analysis
- Mobile security assessment
- Custom tool development for security research

---
