指针函数和函数指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>

// 什么是函数指针,什么是指针函数
// 函数指针:指向一个函数的指针
// 指针函数:一个函数的返回值是一个指针的函数

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

int* abc(void) // 指针函数
{

}

int main(void)
{
int (*ptr)(int, int) = &add; // 函数指针
}

指针的大小

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>

// 指针的大小
// char* int* float*
// 指针的大小和编译器的位数有关
// 在 32bit 的系统霞指针的大小是4个字节
// 在 64bit 的系统下指针的大小是8个字节
// 指针的大小和指针的类型无关

int main(void)
{
    // 将三个类型的指针的大小打印出来
    printf("char* size = %d\n", sizeof(char*));
    printf("int* size = %d\n", sizeof(int*));
    printf("float* size = %d\n", sizeof(float*));
}

64bit 的系统下输出

1
2
3
char* size = 8
int* size = 8
float* size = 8

32bit 的系统下输出

1
2
3
char* size = 4
int* size = 4
float* size = 4

strlen 和 sizeof 的区别

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
#include <string.h>

// strlen 和 sizeof 的区别
// 1. sizeof 是一个运算符,strlen 是一个函数,包含 string.h 头文件
// 2. sizeof 计算的是所占内存的大小,strlen 计算的是字符串的长度
// 字符串以'\0'结尾,strlen 不计算'\0'的长度
// 3. strlen 一般用于字符串的长度,sizeof 可以计算int char float double 等类型的大小

int main(void)
{
    printf("%d %d\n", sizeof("\0"), strlen("\0"));  // 2 0
}

C 语言内存分配方式有几种

  • C 语言内存分配方式有几种
  1. 静态存储器分配,例如全局变量,静态变量
  2. 栈上分配,例如局部变量,函数参数
  3. 分配,例如 malloc,calloc,realloc,free

数组指针和指针数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>

// 数组指针和指针数组
// 1. 数组指针是指向数组的指针,本质上是一个指针变量,指向数组的首地址
// 2. 指针数组是一个数组,数组的每个元素都是指针变量,指向不同的地址

int main(void)

{
// 数组指针
    int (*p)[5]; // p 是一个指向包含 5 个整数的数组的指针

    // 指针数组
    int *p1[5]; // p1 是一个包含 5 个整数指针的数组
    int* a, a1, a2;
    int *p1[5] = {a, a1, a2};
}

struct 结构体和 union 联合体的区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>

// struct 结构体和 union 联合体的区别
// 1. union 联合体:成员共享一块地址。
// 共同体的大小 = 最大成员的大小

// 2. struct 结构体:成员各自占用不同的地址。
// 结构体的大小 = 所有成员的大小之和 + 补齐字节

typedef union

{
    char c;
    int i;
    float f;
} DataType1; // 联合体

typedef struct
{
    char c;
    int i;
    float f;
} DataType2; // 结构体

int main(void)
{
    printf("sizeof(DataType1) = %d\n", sizeof(DataType1)); // 4
    printf("sizeof(DataType2) = %d\n", sizeof(DataType2)); // 12
    printf("sizeof(DataType1+DataType2) = %d\n", sizeof(DataType1) + sizeof(DataType2)); // 16
    return 0;
}

野指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
#include <malloc.h>

// 野指针是什么,为什么会导致有野指针
// 野指针是指向一个不合法的内存地址的指针,使用野指针会导致程序崩溃或数据错误

//1. 当指针被创建的时候,没有赋值,这个时候指针就成为了野指针
//2. 当指针被free或delete后,如果没有把指针置为NULL,这个时候指针也成为了野指针
//3. 当指针越界的时候也是野指针

int main(void)
{
    int *p = NULL; // 定义一个指针变量 p,并初始化为 NULL
    int *p1 = (int *)malloc(sizeof(int)); // 动态分配内存,p1 指向分配的内存
    *p1 = 10; // 给 p1 指向的内存赋值
    printf("p1 = %d\n", *p1); // 打印 p1 指向的值
    free(p1); // 释放 p1 指向的内存
    p1 = NULL; // 将 p1 置为 NULL,避免野指针
    return 0;
}

数组和链表的区别

    1. 数组的地址空间是连续的,链表的地址空间是不连续的
    1. 数组访问速度较快,数组直接通过下标访问,链表需要遍历
    1. 链表增删查改比数组快,链表可以在 O(1) 的时间内插入和删除元素,而数组需要移动元素

宏函数注意点

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>

// 写一个宏,这个宏返回输入参数比较小的一个
#define MIN(a, b) ((a) <= (b) ? (a) : (b))

int main(void)
{
    int a = 10, b = 20;
    printf("min = %d\n", MIN(a, b)); // 打印最小值
    return 0;
}

# include<> 和 # include “”的区别

  • 使用 # include<> 和 # include “” 的区别
  1. 编译器会从标准库的路径里面去搜索,对于搜索标准库的文件速度会比较快
  2. 编译器会从用户的工作路径里面去搜素,对于自己定义的文件使用 “” 的速度会比较快

全局变量和局部变量的区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>

// 全局变量和局部变量的区别
// 1. 作用域不同:全局变量在整个程序中都可以访问,局部变量只能在当前函数内部访问
// 2. 生命周期不同:全局变量在程序运行期间一直存在,局部变量在函数调用时创建,函数结束时销毁
// 3. 存储位置不同:全局变量存储在数据段,局部变量存储在栈区
// 4. 使用方式不同:全局变量可以在多个函数中使用,局部变量只能在当前函数中使用

int a = 20; // 全局变量

void test()
{
    int a = 10; // 局部变量
    printf("局部变量 a = %d\n", a); // 打印局部变量
}

int main(void)
{
    test(); // 调用 test 函数
    printf("全局变量 a = %d\n", a); // 打印全局变量
    return 0;
}