核心内容摘要
南北阁Nanbeige 4.1-3B Anaconda科学计算环境配置指南
C语言核心知识
分数组、指针、字符串
数组
1 一维数组// 声明和初始化 int arr[5]; // 声明未初始化 int arr2[5] {1, 2, 3, 4, 5}; // 完全初始化 int arr3[] {1, 2, 3}; // 自动计算大小 int arr4[5] {1, 2}; // 部分初始化其余为0 // 数组大小计算 int size sizeof(arr) / sizeof(arr[0]); // 数组遍历 for(int i 0; i 5; i) { printf(arr[%d] %d\n, i, arr[i]); }
2 二维数组// 声明和初始化 int matrix[3][4]; // 3行4列 int matrix2[2][3] { // 直接初始化 {1, 2, 3}, {4, 5, 6} }; int matrix3[][3] { // 自动计算行数 {1, 2, 3}, {4, 5, 6}, {7, 8, 9} }; // 访问二维数组 for(int i 0; i 2; i) { for(int j 0; j 3; j) { printf(%d , matrix2[i][j]); } printf(\n); }
3 数组的存储特性// 数组在内存中是连续存储的 int arr[3] {1, 2, 3}; // 内存布局 // arr[0] arr[1] arr[2] // 1 2 3 // 地址 arr arr1 arr2 // 数组名是首元素地址 printf(arr %p\n, arr); // 等价于 arr[0] printf(arr[0] %p\n, arr[0]); // 但数组名不是指针常量 // arr some_var; // 错误数组名不能赋值
指针
1 指针基础// 声明指针 int a 10; int *p a; // p指向a的地址 // 使用指针 printf(a的值: %d\n, a); // 直接访问 printf(*p的值: %d\n, *p); // 间接访问 printf(a的地址: %p\n, a); printf(p的值: %p\n, p); // 修改值 *p 20; // 通过指针修改a的值 printf(修改后a: %d\n, a); // 输出
2
2 指针运算int arr[5] {10, 20, 30, 40, 50}; int *ptr arr; // 指向数组首元素 // 指针加减运算 printf(ptr指向: %d\n, *ptr); // 10 ptr; // 指向下一个元素 printf(ptr后: %d\n, *ptr); // 20 ptr 2; // 前进2个元素 printf(ptr2后: %d\n, *ptr); // 40 // 指针比较 int *p1 arr[0]; int *p2 arr[3]; if(p1 p
{ // 比较地址 printf(p1在p2之前\n); } // 指针相减得到元素个数 int diff p2 - p1; // diff 3 printf(p2-p1 %d个元素\n, diff);
3 指针的指针多级指针int a 100; int *p a; // 一级指针 int **pp p; // 二级指针 int ***ppp pp; // 三级指针 // 访问值 printf(a %d\n, a); // 100 printf(*p %d\n, *p); // 100 printf(**pp %d\n, **pp); // 100 printf(***ppp %d\n, ***ppp);//
1
4 指针与数组的关系int arr[3] {1, 2, 3}; // 访问数组的四种方式 arr[0] 10; //
数组下标 *(arr
20; //
指针运算 int *p arr; //
指针变量 p[0] 30; //
指针下标 // 等价性证明 arr[i] ≡ *(arr i) *(arr i) ≡ *(i arr) ≡ i[arr] // 奇怪的写法但正确
5 函数指针// 普通函数 int add(int a, int b) { return a b; } // 声明函数指针 int (*func_ptr)(int, int); // 赋值 func_ptr add; // 函数名就是函数地址 // 或 func_ptr add; // 通过指针调用函数 int result func_ptr(10,
; // 调用add(10,
printf(10 20 %d\n, result); // 输出30 // 函数指针数组 int (*operations[4])(int, int) { add, // 加法 sub, // 减法 mul, // 乘法 div // 除法 }; // 使用函数指针数组 for(int i 0; i 4; i) { printf(结果: %d\n, operations[i](10,
); }
6 void指针// void指针是通用指针 int a 100; float b
14; char c A; void *vp; vp a; // 可以指向任何类型 vp b; vp c; // 使用前需要类型转换 int *int_ptr (int*)vp; printf(值: %d\n, *int_ptr); // 常用于通用函数 void swap(void *a, void *b, size_t size) { char temp; char *pa (char*)a; char *pb (char*)b; for(size_t i 0; i size; i) { temp pa[i]; pa[i] pb[i]; pb[i] temp; } }
字符串
1 字符串基础// 字符串的三种表示方式 char str1[] Hello; // 字符数组 char str2[10] World; // 指定大小 char *str3 String Literal; // 字符串常量 // 字符串以\0结尾 char str[6] {H, e, l, l, o, \0}; // 字符串长度不包括\0 int len strlen(Hello); // len 5 // 字符串输入输出 char name[20]; printf(请输入姓名: ); scanf(%s, name); // 读取一个单词 fgets(name, 20, stdin); // 读取一行安全 printf(姓名: %s\n, name);
2 字符串函数#include string.h char str1[20] Hello; char str2[20] World; // 字符串复制 strcpy(str1, New String); // str1 New String strncpy(str1, Safe Copy,
; // 安全版本 // 字符串连接 strcat(str1, ); // 追加空格 strcat(str1, str
; // str1 Hello World strncat(str1, !,
; // 安全版本 // 字符串比较 if(strcmp(str1, str
2)
{ printf(字符串相等\n); } else if(strcmp(str1, str
2)
{ printf(str1 str2\n); } else { printf(str1 str2\n); } // 字符串查找 char *pos strchr(str1, W); // 查找字符 if(pos) printf(找到W在位置%ld\n, pos - str
; pos strstr(str1, World); // 查找子串 if(pos) printf(找到World\n); // 字符串分割 char text[] apple,banana,orange; char *token strtok(text, ,); while(token) { printf(水果: %s\n, token); token strtok(NULL, ,); }
3 字符串与指针// 字符串常量 char *str Hello; // Hello在只读内存区 // str[0] h; // 错误不能修改字符串常量 // 字符数组 char arr[] Hello; // 在栈上分配内存 arr[0] h; // 正确可以修改 // 动态分配字符串 char *dynamic (char*)malloc(20 * sizeof(char)); strcpy(dynamic, Dynamic String); printf(%s\n, dynamic); free(dynamic);
4 字符处理函数#include ctype.h char c A; // 字符类型判断 if(isalpha(c)) printf(字母\n); // 字母 if(isdigit(c)) printf(数字\n); // 数字 if(isalnum(c)) printf(字母或数字\n); // 字母或数字 if(isspace(c)) printf(空白字符\n); // 空格、制表符等 if(islower(c)) printf(小写字母\n); // 小写 if(isupper(c)) printf(大写字母\n); // 大写 // 字符转换 char lower tolower(A); // a char upper toupper(b); // B // 其他函数 isprint(c); // 可打印字符 ispunct(c); // 标点符号 isxdigit(c); // 十六进制数字 iscntrl(c); // 控制字符
动态内存分配
1 内存管理函数#include stdlib.h // malloc - 分配内存 int *arr (int*)malloc(10 * sizeof(int)); if(arr NULL) { printf(内存分配失败\n); exit(
; } // calloc - 分配并清零 int *zeros (int*)calloc(10, sizeof(int)); // 等价于 malloc memset(
// realloc - 重新分配 arr (int*)realloc(arr, 20 * sizeof(int)); // free - 释放内存 free(arr); free(zeros); // 注意free后指针应设为NULL arr NULL; zeros NULL;
2 常见内存错误//
内存泄漏 void leak() { int *p malloc(
; // 忘记free(p); } //
访问已释放内存 int *p malloc(sizeof(int)); free(p); *p 10; // 错误 //
双重释放 free(p); free(p); // 错误 //
内存越界 int *arr malloc(10 * sizeof(int)); arr[10] 100; // 越界访问 //
使用未初始化指针 int *p; *p 10; // 错误
3 安全的内存使用//
总是检查malloc返回值 int *safe_malloc(size_t size) { void *ptr malloc(size); if(ptr NULL) { fprintf(stderr, 内存分配失败\n); exit(EXIT_FAILURE); } return ptr; } //
使用free后立即设为NULL void safe_free(void **ptr) { if(ptr *ptr) { free(*ptr); *ptr NULL; } } //
使用calloc自动清零 int *arr calloc(10, sizeof(int)); //
使用memset/memcpy int src[5] {1, 2, 3, 4, 5}; int dest[5]; memcpy(dest, src, 5 * sizeof(int)); memset(dest, 0, 5 * sizeof(int));
结构体
1 结构体基础// 定义结构体 struct Student { char name[20]; int age; float score; }; // 声明变量 struct Student stu1; struct Student stu2 {张三, 20,
8
5}; // 访问成员 strcpy(stu
name, 李
; stu
age 21; stu
score
9
0; // 结构体指针 struct Student *pstu stu1; pstu-age 22; // 等价于 (*pstu).age 22;
2 结构体高级特性// 结构体嵌套 struct Date { int year; int month; int day; }; struct Person { char name[20]; struct Date birthday; // 嵌套结构体 }; // 结构体数组 struct Student class[50]; class[0].age 20; class[1].score
9
5; // 结构体大小内存对齐 struct Example { char a; // 1字节 int b; // 4字节 short c; // 2字节 double d; // 8字节 }; // 实际大小可能是24字节包含填充 printf(结构体大小: %lu\n, sizeof(struct Example));
3 联合体共用体union Data { int i; float f; char str[20]; }; union Data data; data.i 10; // 使用int成员 printf(data.i %d\n, data.i); data.f
2
5; // 现在使用float成员 printf(data.f %.1f\n, data.f); // data.i的值被覆盖了 // 联合体大小是最大成员的大小 printf(联合体大小: %lu\n, sizeof(union Data));
指针类型
总结类型声明含义示例整型指针int *p指向int的指针p int_var字符指针char *p指向char的指针p str函数指针int (*p)(int,int)指向函数的指针p add数组指针int (*p)[10]指向数组的指针p arr指针数组int *arr[10]元素是指针的数组arr[0] var二级指针int **p指向指针的指针p ptrvoid指针void *p通用指针p any_var
总结数组是数据的集合指针是内存地址的表示字符串是特殊的字符数组。
掌握这些内容对于理解C语言的内存模型和高效编程至关重要。