第一部分:C语言

1.C语言的内存模型:

程序代码区:存放函数体的二进制代码;

静态数据区:也称全局数据区,包含的数据类型比较多,如全局变量、静态变量、一般常量、字符串常量。其中全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。常量数据存放在另一个区域。静态数据区的内存在程序结束后由操作系统释放。

堆区:一般由程序员分配和释放,若程序员不释放,程序运行结束后由操作系统回收。malloc(),calloc()、free()等函数操作的就是这块内存。

栈区:由系统自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。

命令行参数区:存放命令行的参数和环境变量的值,如通过main()函数传递的值。

2 指针与数组区别

数组是相同类型元素的连续集合,数组名代表整个内存块

指针是一个变量,存储内存地址,只存地址,需另分配目标内存

(1)内存分配方式与sizeof运算结果不同

int arr[5];        // 编译器分配20字节连续内存(假设int为4字节)

int *ptr;          // 只分配指针变量本身的内存(通常4或8字节)

ptr = malloc(20);  // 动态分配内存,ptr指向这块内存

sizeof(arr);  // 返回20(整个数组大小)

sizeof(ptr);  // 返回指针大小(4或8字节)

(2)赋值和修改

int arr1[5], arr2[5];

int *p1, *p2;

// 数组不能直接赋值

// arr1 = arr2;  // 错误!数组名是常量指针,不能赋值

// 指针可以赋值

p1 = arr1;      // 正确

p1 = p2;        // 正确

(3)地址运算

int arr[5];
int *p = arr;

p++;           // 正确,p现在指向arr[1]
// arr++;      // 错误!数组名是常量,不能修改

(4)作为函数参数时的退化

当数组作为函数参数传递时,会退化为指针:

void func(int arr[])  {   //  实际上等价于 int *arr
         // sizeof(arr) 返回指针大小,不是数组大小
}

(5)初始化和存储位置

char str1[] = "hello";  // 栈上分配数组,可修改
char *str2 = "world";    // 指针在栈上,指向常量区的字符串

(6)容易混淆的点
数组名在大多数表达式中会退化为指向首元素的指针

arr[i]和*(arr+i)等价

但&arr和&ptr的含义不同:

int arr[5];
int *p = arr;

&arr;  // 类型是 int(*)[5],指向整个数组
&p;    // 类型是 int**,指向指针变量

3.野指针
野指针指向不可用的内存或未初始化的指针,使用野指针会导致未定义行为,通常是程序崩溃。

指针本身即存储地址的变量可以任意赋值,但通过指针访问/修改内存(解引用)时,必须确保指针指向有效的、已分配的内存。未初始化的指针存储的是随机地址,解引用会访问非法内存,导致段错误未定义行为。

(1)未初始化的指针

int *p; //未初始化,随机值

*p = 10;//错误,会访问位置内存

正确示例:

int x =5 ;

int *p = &x;  //指针指向变量x

*p =10; //修改x的值为10

(2)指针被释放后未置空

int *p = (int*)malloc(sizeof(int));

free(p);

*p =20;  //错误,因为已经释放p,无法访问已释放内存

正确示例:

int *p = (int*)malloc(sizeof(int));
*p = 20;      // 正确:修改动态分配的内存
free(p);

(3)超出作用域

int* func(){

      int a = 10;

     return &a; //返回局部变量的地址

}//函数结束,a被销毁,返回的指针变为野指针

4.函数指针

函数指针定义为指向函数的指针变量,可以像调用函数一样通过指针调用。

返回类型 (*指针名)(参数类型列表);

#include <stdio.h>

int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }

int main() {
    // 声明函数指针
    int (*func_ptr)(int, int);
    
    // 指向add函数
    func_ptr = add;  // 或 func_ptr = &add;
    printf("5 + 3 = %d\n", func_ptr(5, 3));
    
    // 指向sub函数
    func_ptr = sub;
    printf("5 - 3 = %d\n", func_ptr(5, 3));
    
    return 0;
}

typedef简化

typedef int (*Operation)(int, int);

Operation op = add;  // 更清晰的声明
printf("%d\n", op(5, 3));

5.指针函数

指针函数定义为返回指针的函数,即函数的返回值是指针

返回类型* 函数名(参数列表)

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

// 返回int指针的函数
int* create_array(int size) {
    int *arr = (int*)malloc(size * sizeof(int));
    for(int i = 0; i < size; i++) {
        arr[i] = i * 2;
    }
    return arr;  // 返回动态分配内存的指针
}

int main() {
    int *ptr = create_array(5);
    
    for(int i = 0; i < 5; i++) {
        printf("%d ", ptr[i]);
    }
    
    free(ptr);  // 记得释放内存
    return 0;
}

注:调用者负责释放返回的动态内存。

6.函数指针数组

函数指针数组定义数组的元素是函数指针,用于实现跳转表或命令表

返回类型 (*数组名[数组大小])(参数类型列表);

示例:计算器

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

double add(double a, double b) { return a + b; }
double sub(double a, double b) { return a - b; }
double mul(double a, double b) { return a * b; }
double div(double a, double b) { return b != 0 ? a / b : 0; }

int main() {
    double (*calc[4])(double, double) = {add, sub, mul, div};
    char operators[] = {'+', '-', '*', '/'};
    
    double x = 10.5, y = 2.5;
    char op = '*';
    
    for(int i = 0; i < 4; i++) {
        if(operators[i] == op) {
            printf("%.2f %c %.2f = %.2f\n", x, op, y, calc[i](x, y));
            break;
        }

       ......
    return 0;
}

7.回调函数机制

#include <stdio.h>

// 回调函数类型定义
typedef void (*Callback)(int);

// 处理函数,接受回调函数作为参数
void process_data(int data[], int size, Callback callback) {
    for(int i = 0; i < size; i++) {
        callback(data[i]);  // 调用回调函数
    }
}

// 各种回调函数
void print_square(int x) {
    printf("%d的平方: %d\n", x, x * x);
}

void print_cube(int x) {
    printf("%d的立方: %d\n", x, x * x * x);
}

int main() {
    int data[] = {1, 2, 3, 4, 5};
    int size = sizeof(data) / sizeof(data[0]);
    
    // 使用不同的回调函数处理数据
    printf("=== 平方计算 ===\n");
    process_data(data, size, print_square);
    
    printf("\n=== 立方计算 ===\n");
    process_data(data, size, print_cube);
    
    return 0;
}

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐