如何移动指针缩短字符串并正确释放内存?含大数相加场景
C语言字符串末尾填充与内存释放问题解决
为什么会出现free(): invalid pointer错误?
你传给free的指针不是calloc返回的原始内存起始地址。
在你的代码中,res一开始指向calloc分配的10字节内存首地址,但执行res++后,指针被移动到了数组第5个字节的位置。C语言内存管理规则要求:只有malloc/calloc/realloc返回的原始指针才能被free,移动后的指针不属于合法释放对象,因此触发错误。
修复当前代码的两种方法
方法1:保留原始指针,将有效内容移到缓冲区开头
保存calloc返回的原始指针,找到有效字符串的起始位置后,把内容拷贝到缓冲区开头,返回原始指针即可正常释放:
#include <stdlib.h> #include <string.h> #include <stdio.h> char* getGreeting() { // 保存原始分配的指针 char* original_res = (char*) calloc(10, sizeof(char)); char* res = original_res; // 从末尾写入字符 res[4] = 'H'; res[5] = 'e'; res[6] = 'l'; res[7] = 'l'; res[8] = 'o'; res[9] = '\0'; // 找到第一个非空字符的位置 char* start = original_res; while (*start == '\0') { start++; } // 把有效字符串拷贝到缓冲区开头 memmove(original_res, start, strlen(start) + 1); // 返回原始指针,调用者可直接free return original_res; } int main() { char* greeting = getGreeting(); printf("res: %s\n", greeting); free(greeting); // 正常释放 return 0; }
方法2:重新分配内存,拷贝有效内容
找到有效字符串后,用strdup(或malloc+strcpy)创建新内存块,释放原始内存,返回新指针:
#include <stdlib.h> #include <string.h> #include <stdio.h> char* getGreeting() { char* res = (char*) calloc(10, sizeof(char)); res[4] = 'H'; res[5] = 'e'; res[6] = 'l'; res[7] = 'l'; res[8] = 'o'; res[9] = '\0'; char* start = res; while (*start == '\0') { start++; } // 分配新内存拷贝有效字符串 char* result = strdup(start); // 释放原始内存 free(res); return result; } int main() { char* greeting = getGreeting(); printf("res: %s\n", greeting); free(greeting); // 正常释放 return 0; }
针对大数相加场景的解决方案
你的原始需求是实现十进制大数相加,从末尾填充字符串,这里推荐两种适配方案:
方案1:预分配足够内存(推荐)
大数相加的最大长度可预估:两个输入字符串的最大长度 +1(预留进位空间),直接分配足够内存即可:
#include <stdlib.h> #include <string.h> #include <stdio.h> char* addBigNumbers(const char* num1, const char* num2) { int len1 = strlen(num1); int len2 = strlen(num2); int max_len = len1 > len2 ? len1 : len2; // 分配内存:max_len+2(进位+结束符) char* buffer = calloc(max_len + 2, sizeof(char)); if (!buffer) return NULL; // 指针指向缓冲区最后一个可写位置(结束符前) char* ptr = buffer + max_len; int carry = 0; int i = len1 - 1, j = len2 - 1; // 从末尾逐位相加 while (i >= 0 || j >= 0 || carry > 0) { int digit1 = (i >= 0) ? (num1[i] - '0') : 0; int digit2 = (j >= 0) ? (num2[j] - '0') : 0; int sum = digit1 + digit2 + carry; carry = sum / 10; *ptr = (sum % 10) + '0'; ptr--; i--; j--; } // 有效字符串起始位置 char* start = ptr + 1; // 移到缓冲区开头 memmove(buffer, start, strlen(start) + 1); return buffer; } int main() { char* result = addBigNumbers("123456789", "987654321"); printf("Result: %s\n", result); free(result); // 正常释放 return 0; }
方案2:动态扩容(完全未知长度场景)
如果无法预估最大长度,可使用realloc动态扩容缓冲区:
#include <stdlib.h> #include <string.h> #include <stdio.h> char* addBigNumbersDynamic(const char* num1, const char* num2) { int capacity = 32; char* buffer = calloc(capacity, sizeof(char)); if (!buffer) return NULL; char* ptr = buffer + capacity - 1; // 指向最后可写位置 int carry = 0; int i = strlen(num1) - 1, j = strlen(num2) - 1; while (i >= 0 || j >= 0 || carry > 0) { // 检查缓冲区是否已满 if (ptr == buffer) { int new_capacity = capacity * 2; // 计算当前已填充的内容长度 int content_len = (buffer + capacity - 1) - ptr; // 扩容 char* new_buffer = realloc(buffer, new_capacity); if (!new_buffer) { free(buffer); return NULL; } // 调整指针位置 ptr = new_buffer + new_capacity - 1 - content_len; buffer = new_buffer; capacity = new_capacity; } int digit1 = (i >= 0) ? (num1[i] - '0') : 0; int digit2 = (j >= 0) ? (num2[j] - '0') : 0; int sum = digit1 + digit2 + carry; carry = sum / 10; *ptr = (sum % 10) + '0'; ptr--; i--; j--; } // 补结束符,调整有效起始位置 char* start = ptr + 1; memmove(buffer, start, strlen(start) + 1); // 可选:缩容到刚好大小 char* result = realloc(buffer, strlen(buffer) + 1); return result ? result : buffer; } int main() { char* result = addBigNumbersDynamic("9999999999999999", "1"); printf("Result: %s\n", result); free(result); return 0; }
内容的提问来源于stack exchange,提问作者dayuloli
相关产品推荐
相关产品推荐

