basic

结构体访问成员变量

假设有一个结构体 struct Point 和一个指向 Point 的指针:

struct Point {
    int x;
    int y;
};

struct Point p = {10, 20};
struct Point *p_ptr = &p;
复制代码

可以通过 -> 运算符访问结构体 p 的成员 x 和 y,如下

int x_val = p_ptr->x;  // 等同于 (*p_ptr).x
int y_val = p_ptr->y;
复制代码

为什么使用 ->

简便性:-> 是 (p_ptr).x 的简写,避免了使用 和 () 的繁琐语法。

指针访问:-> 直接表示对结构体指针成员的访问,方便理解。

Typedef:定义新类型

C allows us to define new data type (names) via typedef:

typedef ExistingDataType NewTypeName;

Examples:

typedef float Temperature;
typedef int Matrix[20][20];
复制代码

函数指针

我的理解,就是 typedef 定义一个名字,声明 参数、返回值 是些啥。然后这个名字,当作类型声明,快速复制其他名字的函数。

注意,赋值给其他新函数名字的时候,后面的函数名字加不加&都可以,因为C会实际将其处理为函数地址。

// Define a function pointer type, which points to a function
typedef int (*ComparatorFuncPtr)(int, int);

int IsLarger(int a, int b) {
    return a > b;
}

ComparatorFuncPtr fptr = &IsLarger;  
复制代码

或如:

typedef int (*ComparatorFuncPtr)(int, int);

int IsLarger(int a, int b) {
    return a > b;
}

ComparatorFuncPtr fptr1 = IsLarger;  // Implicit pointer
ComparatorFuncPtr fptr2 = &IsLarger; // Explicit pointer

int result1 = fptr1(5, 3);  // Calls IsLarger(5, 3)
int result2 = fptr2(5, 3);  // Also calls IsLarger(5, 3)
复制代码

使用场景

1.回调函数 (Callback Functions)

函数指针可以作为参数传递给另一个函数,通常用于回调机制。在某些场景下,比如排序、事件驱动程序或者信号处理,你可以将特定的函数通过函数指针传递给库函数,库函数在合适的时机调用你传递的函数。

示例:使用函数指针作为回调函数

#include <stdio.h>

void callback(int result) {
    printf("Callback called with result: %d\n", result);
}

void compute(int a, int b, void (*callbackFunc)(int)) {
    int sum = a + b;
    callbackFunc(sum);  // 调用传入的回调函数
}

int main() {
    compute(3, 4, callback);  // 传入 callback 函数指针
    return 0;
}
复制代码

在这个例子中,compute函数接收一个函数指针参数 callbackFunc,然后在合适的时候调用这个函数。

2.实现策略模式或动态函数调用

函数指针可以让你在程序运行时选择不同的函数来执行相同的任务。这在实现不同的策略或行为时非常有用,比如不同的排序规则、比较函数、或者动态处理不同类型的数据。
示例:不同的比较函数传递给排序算法

#include <stdio.h>

// 比较函数
int ascending(int a, int b) {
    return a - b;
}

int descending(int a, int b) {
    return b - a;
}

// 使用函数指针的通用排序函数
void sort(int* arr, int size, int (*compare)(int, int)) {
    for (int i = 0; i < size - 1; i++) {
        for (int j = i + 1; j < size; j++) {
            if (compare(arr[i], arr[j]) > 0) {
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
    }
}

int main() {
    int arr[] = {5, 2, 9, 1, 5, 6};
    int size = sizeof(arr) / sizeof(arr[0]);

    sort(arr, size, ascending);  // 使用升序比较
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    sort(arr, size, descending);  // 使用降序比较
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    return 0;
}
复制代码

传递命令行参数:参数数量 参数值 环境变量值

首先注意啊,argv 和 env都存储的是字符串,如果你输入参数是数字,需要转换成数字才行

参数数量 参数值

argc (Argument Count)

./my_program arg1 arg2 arg3

argc will be 4:
argv[0] is the name of the program (“./my_program”).

argv[1] is "arg1".
argv[2] is "arg2".
argv[3] is "arg3".
复制代码

argv (Argument Vector)

char argv or char argv[]*

这是个存储 char 的数组,char 是字符指针,指向不同字符串的首地址(第一个字符的地址)

比如我们传参,

./exe aaa bbb
复制代码

程序中,

Char a[]=“aaa”
Char b[]=“bbb”
Char c[]=“ccc”
复制代码

a,b,c名字本身就是char,或者说,*首地址

char a = “hello”; char b = “world”; char *c = “example”;

argv 是一个指针数组,也就是存储多个 char* 的数组。每个元素都是一个字符指针,指向一个字符串。

具体来说,argv 的类型是 char*,表示它是“字符指针的指针”。换句话说,它是一个数组,其中的每个元素都是 char,这些 char* 指向的是具体的字符串(即字符数组)。

argv[0] is the name of the program (or the path used to execute it).
argv[1] to argv[argc-1] are the actual arguments passed to the program.

int main(int argc, char **argv, char **env){
  Print(“argc = %d\n”, argc);
  Print(“argv[0] = %d\n”, argv[0]);
  Print(“argv[1] = %d\n”, argv[1]);
  For (int I=0; i<argc; i++){
    Xxx
  }
}
复制代码

环境变量值

char *env 或 char env[]

形式同char **agv,env是编译器默认定义好的数组

这些字符串是环境变量的名称和值,通常以 “NAME=VALUE”

#include <stdio.h>

int main(int argc, char **argv, char **env) {
    // 遍历并打印所有环境变量
    for (int i = 0; env[i] != NULL; i++) {
        printf("%s\n", env[i]);
    }
    return 0;
}
复制代码

Welcome to point out the mistakes and faults!

Gitalking ...