Don*_*ore 2 c malloc memory-management allocation
这是一个基本的例子:
#include <all the basic stuff>
int main(void) {
char *name = (char *) malloc(2 * sizeof(char));
if(name == NULL) {
fprintf(stderr, "Error: Unable to allocate enough memory!\n");
return EXIT_FAILURE;
}
strcpy(name, "Bob Smith");
printf("Name: %s\n", name);
free(name);
return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)
因为我只分配2个字节的信息(2个字符),所以当我执行strcpy时应该会出现某种错误,对吧?这不会发生,而只是将字符串复制,打印出来,释放内存并成功退出.为什么会发生这种情况,如何正确使用malloc?
您的程序调用未定义的行为.
未定义的行为是超出语言规范的行为.根据定义,这意味着您无法保证获得任何明确定义的行为(例如错误).该程序明确无效.
使用时strcpy
,该函数只是假定传递给它的缓冲区足够大以容纳要复制的字符串.如果假设是错误的,它会尝试写入缓冲区之外的区域.如果发生这种情况,程序将属于C规范的这种情况,在J.2未定义的行为中:
在以下情况下,行为未定义:
- 将指针加到或减去数组对象和整数类型会产生一个不指向或超出同一数组对象的结果
因此,要strcpy
正确使用,您必须手动确保有关字符串长度和缓冲区长度的上述假设成立.要做到这一点,一个简单的方法是保持缓冲区的长度保存在某处,计算要复制的字符串的长度,并进行比较.
例如:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
size_t bufferSize = 2 * sizeof(char);
char *name = malloc(bufferSize);
if(name == NULL) {
fprintf(stderr, "Error: Unable to allocate enough memory!\n");
return EXIT_FAILURE;
}
size_t length = strlen("Bob Smith");
if(length + 1 > bufferSize) {
fprintf(stderr, "Error: The target buffer is too small!\n");
return EXIT_FAILURE;
}
strcpy(name, "Bob Smith");
printf("Name: %s\n", name);
free(name);
return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)
作为一个不相关的旁注,你会注意到我没有投出结果malloc
,因为a void*
是可以隐式转换为char*
.
最后说明:
当您尝试确保代码的正确性时(或者因为您正在学习该语言或因为您打算发布该软件),C的这一方面听起来可能不切实际.
这就是为什么有些工具可以在程序执行无效操作时提供错误.Valgrind就是这样一个工具(Jonathan Leffler在评论中提到过).