如何用void函数实现字符串动态分配及相关DMA问题
C语言动态内存分配问题解答
1. 改写为void版的动态字符串创建函数
要实现create_string(&str)的调用方式,需要传递指针的指针作为参数——因为我们要修改外部指针变量str的指向,而非指针指向的内容。具体代码如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> void create_string(char **dest) { // 初始化动态内存,初始大小为0 *dest = malloc(0 * sizeof(char)); if (*dest == NULL) { // 内存分配失败直接返回 return; } unsigned int size = 0; char c; while (1) { scanf("%c", &c); // 遇到空格或换行停止读取 if (c == ' ' || c == '\n') { break; } size++; // 用临时变量接收realloc返回值,避免分配失败丢失原内存地址 char *temp = realloc(*dest, size * sizeof(char)); if (temp == NULL) { free(*dest); *dest = NULL; return; } *dest = temp; (*dest)[size - 1] = c; } // 分配额外空间存储字符串结束符'\0' char *temp = realloc(*dest, (size + 1) * sizeof(char)); if (temp == NULL) { free(*dest); *dest = NULL; return; } *dest = temp; (*dest)[size] = '\0'; } int main() { char *str = NULL; create_string(&str); if (str != NULL) { printf("读取的字符串:%s\n", str); printf("字符串长度:%lu\n", strlen(str)); free(str); // 记得释放内存 } return 0; }
关键说明:
char **dest接收外部指针的地址,通过*dest直接修改外部指针的指向- 新增内存分配失败的错误处理,避免内存泄漏或程序崩溃
- 每次
realloc用临时变量过渡,防止分配失败时丢失原内存地址
2. 二维数组的动态内存分配实现
C语言中二维数组的动态分配主要有两种常用方式:
方式1:行指针数组(每行可不等长)
先分配存储指针的数组,再为每个指针单独分配行内存,适合每行长度不同的场景:
#include <stdio.h> #include <stdlib.h> int main() { int rows = 3; int cols[] = {2, 4, 3}; // 每行列数可自定义 // 步骤1:分配行指针数组 int **arr = malloc(rows * sizeof(int*)); if (arr == NULL) { return 1; } // 步骤2:为每行分配内存并初始化 for (int i = 0; i < rows; i++) { arr[i] = malloc(cols[i] * sizeof(int)); if (arr[i] == NULL) { // 分配失败时回滚已分配的内存 for (int j = 0; j < i; j++) { free(arr[j]); } free(arr); return 1; } for (int j = 0; j < cols[i]; j++) { arr[i][j] = i * 10 + j; } } // 打印数组 for (int i = 0; i < rows; i++) { for (int j = 0; j < cols[i]; j++) { printf("%d ", arr[i][j]); } printf("\n"); } // 释放内存:先释放每行,再释放指针数组 for (int i = 0; i < rows; i++) { free(arr[i]); } free(arr); return 0; }
方式2:连续内存的二维数组(模拟静态数组)
一次性分配连续内存块,通过偏移量访问元素,内存更紧凑,适合行列固定的场景:
#include <stdio.h> #include <stdlib.h> int main() { int rows = 3; int cols = 4; // 步骤1:分配连续内存块,总大小为rows*cols个int int *arr = malloc(rows * cols * sizeof(int)); if (arr == NULL) { return 1; } // 步骤2:通过偏移量访问元素,等价于静态数组的arr[i][j] for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { arr[i * cols + j] = i * 10 + j; } } // 打印数组 for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { printf("%d ", arr[i * cols + j]); } printf("\n"); } // 释放内存:只需一次free free(arr); return 0; }
如果想用arr[i][j]的语法访问连续内存,可以额外分配指针数组映射行地址:
int **arr_ptr = malloc(rows * sizeof(int*)); for (int i = 0; i < rows; i++) { arr_ptr[i] = arr + i * cols; } // 此时可用arr_ptr[i][j]访问元素 // 释放时先释放arr_ptr,再释放arr
3. 输入特定字符串停止扫描(支持多类型)
核心思路:先读取整行输入,判断是否为停止标记(如"STOP"),若是则终止;否则将输入转换为对应数据类型。对于结构体等复杂类型,可先解析各字段再判断停止条件。
示例1:读取int直到输入"STOP"
#include <stdio.h> #include <stdlib.h> #include <string.h> int main() { char buffer[100]; int num; while (1) { printf("输入整数或STOP停止:"); fgets(buffer, sizeof(buffer), stdin); // 去掉fgets读取的换行符 buffer[strcspn(buffer, "\n")] = '\0'; if (strcmp(buffer, "STOP") == 0) { break; } // 转换为int并验证格式 if (sscanf(buffer, "%d", &num) == 1) { printf("读取到整数:%d\n", num); } else { printf("输入格式错误,请重新输入\n"); } } printf("已停止输入\n"); return 0; }
示例2:读取自定义结构体直到输入"STOP"
假设结构体包含姓名和年龄:
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { char name[50]; int age; } Person; int main() { char buffer[100]; Person p; while (1) { printf("输入姓名+年龄(空格分隔),或输入STOP停止:"); fgets(buffer, sizeof(buffer), stdin); buffer[strcspn(buffer, "\n")] = '\0'; if (strcmp(buffer, "STOP") == 0) { break; } // 解析结构体字段并验证格式 if (sscanf(buffer, "%s %d", p.name, &p.age) == 2) { printf("读取到人员信息:姓名=%s,年龄=%d\n", p.name, p.age); } else { printf("输入格式错误,请重新输入\n"); } } printf("已停止输入\n"); return 0; }
注意事项
- 用
fgets读取整行输入,避免scanf残留的换行符干扰后续读取 strcspn用于去除换行符,确保字符串比较准确- 对于bool类型,可将输入转换为0/1或"true"/"false"后再判断停止条件
内容的提问来源于stack exchange,提问作者Soham Jobanputra
相关产品推荐
相关产品推荐

