C语言 入坑总结
什么是内存泄漏?
内存泄漏是指计算机程序在使用内存时,没有正确释放不再需要的内存,导致系统中的可用内存逐渐减少,最终可能导致程序性能下降或崩溃。
数组指针和指针数组区别
数组指针
- 数组指针是指一个指针,它指向一个数组的首元素。
- 它是一个单一的指针变量,用于存储数组的地址。
- 数组指针的类型是指向数组的指针,它指定了数组元素的数据类型和维度。
- 通过数组指针,可以遍历整个数组,访问数组中的元素。
int arr[5] = {1, 2, 3, 4, 5};
int (*ptr)[5]; // 声明一个指向包含5个int元素的数组的指针
ptr = &arr; // 将ptr指向arr数组的首地址
指针数组
- 指针数组是一个数组,它的元素都是指针。
- 它包含多个指针变量,每个指针可以指向不同的数据或对象。
- 指针数组的元素可以是不同类型的指针,指向不同类型的数据。
- 常用于创建数组的数组,每个元素指向不同的字符串或对象。
int x = 1, y = 2, z = 3;
int *ptrArr[3]; // 声明一个包含3个int指针的数组
ptrArr[0] = &x; // 第一个元素指向x
ptrArr[1] = &y; // 第二个元素指向y
ptrArr[2] = &z; // 第三个元素指向z
小结:
数组指针是一个指针,它指向整个数组,用于处理多维数组或将数组传递给函数。
指针数组是一个数组,它的元素是指针,用于存储不同的指针对象,通常用于管理多个同类型的指针。
指针常量和常量指针区别
指针常量是指指针所指向的位置不能改变,即指针本身是一个常量,但是指针所指向的内容可以改变。
int * const p=&a;
常量指针具有只能够读取内存中数据,却不能够修改内存中数据的属性的指针,称为指向常量的指针,简称常量指针。
const int * p; int const * p;
#include<>和#include""区别
#include<>会先到系统指定目录寻找头文件
#include""先到项目所在目录寻找头文件,如果没有找到再到系统指定目录寻找头文件
#运算符和##作用
# 运算符用于将宏参数转换为字符串常量。它可以将宏参数的值包装在双引号中,将其转换为字符串。
#define STRINGIFY(x) #x
printf("%s\n", STRINGIFY(Hello)); // 输出 "Hello"
## 将连个符号连接成一个新的符号
#define CONCAT(x, y) x##y
int xy = CONCAT(10, 20); // 这将展开为 int xy = 1020;
什么是泛型指针
泛型指针是指void类型指针,它可以指向任何类型的数据。
0长度数组
0长度数组是一种特殊的数组类型,它的大小为0。0长度数组通常用于柔性数组(Flexible Array)的实现。这些数组在编译时不占用任何内存空间,但可以用于计算偏移量,以便在结构体中创建可变长度的数据结构。
struct MyStruct {
int someData;
double moreData;
char flexArray[0]; // 0长度数组
};
typedef和#define区别
typedef 用于创建类型别名,而 #define 用于创建宏。
typedef 创建一个新的类型名称,提高代码的可读性。#define 只进行文本替换。
使用 typedef 时,编译器会进行类型检查,而宏则只进行简单的文本替换。
typedef 只能用于创建类型别名,而宏可以用于各种目的,包括创建常量、函数、表达式等。
typedef 只在编译器的作用域内有效,而宏在整个文件中有效。
typedef int MyInt;
MyInt x = 42; // 现在 MyInt 可以用来声明变量
#define MAX_VALUE 100
int num = MAX_VALUE; // 编译时会替换为 int num = 100;
const和#define区别
#define 是用于预处理器文本替换的,而 const 是用于声明常量变量的。
#define 不分配内存,而 const 分配内存以存储常量值。
#define 不进行类型检查,而 const 提供类型安全。
const 具有作用域,而宏在整个文件中有效。
#define MAX_VALUE 100
const int MAX_VALUE = 100;
什么是悬挂指针和野指针
悬挂指针是指已经指向了一个对象或变量,但该对象或变量已经被释放或销毁,使得指针指向的内存区域不再有效。
int* ptr = (int*)malloc(sizeof(int));
free(ptr); // 现在 ptr 是一个悬挂指针
*ptr = 42; // 访问悬挂指针的值,可能导致未定义的行为
野指针是指一个未被初始化的指针,它包含一个随机或无效的内存地址,没有明确指向任何有效的对象或变量。
int* ptr; // 未初始化的野指针
*ptr = 42; // 访问野指针的值,可能导致未定义的行为
浅拷贝和深拷贝
浅拷贝
- 浅拷贝是一种简单的拷贝操作,它仅复制数据结构中的成员的值或引用。
- 对于指向动态分配内存的指针成员,浅拷贝只会复制指针的值,而不会复制指针指向的实际数据。这意味着原始对象和副本将共享相同的动态分配内存块。
- 当一个对象发生改变时,另一个对象也会受到影响,因为它们引用相同的数据。
struct MyStruct {
int* data;
};
struct MyStruct obj1, obj2;
obj1.data = (int*)malloc(sizeof(int));
*obj1.data = 42;
// 浅拷贝
obj2 = obj1;
*obj2.data = 100; // 修改 obj2 也会影响 obj1
深拷贝
深拷贝是一种复制操作,它不仅复制数据结构的成员的值,还复制指针成员指向的数据。这意味着原始对象和副本拥有各自独立的内存副本。
对于包含动态分配内存的成员,深拷贝将为每个成员分配新的内存,并将数据复制到新内存中。
当一个对象发生改变时,另一个对象不会受到影响,因为它们引用不同的数据。
struct MyStruct {
int* data;
};
struct MyStruct obj1, obj2;
obj1.data = (int*)malloc(sizeof(int));
*obj1.data = 42;
// 深拷贝
obj2.data = (int*)malloc(sizeof(int));
*obj2.data = *obj1.data; // 复制数据,而不是指针
*obj2.data = 100; // 修改 obj2 不会影响 obj1
联合体和共用体区别
- 联合体允许不同的成员共享相同的内存位置,而共用体的成员不共享内存。
- 联合体的大小等于最大成员的大小,而共用体的大小等于所有成员的大小之和。
- 在联合体中,只能同时访问一个成员,而在共用体中,可以同时访问多个成员。
- 在联合体中,只能同时访问一个成员,而在共用体中,可以同时访问多个成员。
extern关键字
注意函数内部定义变量int g_x, g_y; 和 extern g_x, g_y是完全不一样的,前面是定义局部变量,后面是已经定义好的外部全局变量,这里是声明外部全局变量,后面才可以使用该全局变量。
#include "stdio.h"
#include "stdlib.h"
#include "utils.h"
#include "gnu/libc-version.h"
int g_m, g_n; // 表示定义该文件全局变量
extern int g_a, g_b; // 表示外部已经定义好的全局变量,这里是该文件对其声明,不是定义。
void main_test(void)
{
printf("TEST ENTRY\n");
printf("GNU libc version: %s\n", gnu_get_libc_version());
/* int g_x, g_y; 定义局部变量*/
extern int g_x, g_y; // 声明外部全局变量,下面才可以使用
printf("g_x=%d, g_y=%d\n", g_x, g_y);
}
// 定义全局变量g_x, g_y,但是上面main_test函数想使用全局变量必须使用extern进行声明才能引用
int g_x = 0;
int g_y = 1;
void test(void)
{
printf("test, g_x=%d, g_y=%d\n", g_x, g_y);
}
热门相关:神秘总裁小小妻 楚氏赘婿 隐婚试爱:娇妻,好甜! 嫡嫁千金 精灵掌门人