我正在学习C编程,因为我是一名python程序员,我不完全确定C的内部工作原理。我只是偶然发现了一件非常奇怪的事情。
void test_realloc(){
// So this is the original place allocated for my string
char * curr_token = malloc(2*sizeof(char));
// This is really weird because I only allocated 2x char size in bytes
strcpy(curr_token, "Davi");
curr_token[4] = 'd';
// I guess is somehow overwrote data outside the allocated memory?
// I was hoping this would result in an exception ( I guess not? )
printf("Current token > %s\n", curr_token);
// Looks like it's still printable, wtf???
char *new_token = realloc(curr_token, 6);
curr_token = new_token;
printf("Current token > %s\n", curr_token);
}
int main(){
test_realloc();
return 0;
}
所以问题是:为什么我能够将更多的字符写入字符串而不是分配的大小?我知道我应该自己处理mallocated内存,但这是否意味着当我在指定内存外写字时没有迹象表明出现了问题?
我想要完成的事情
答案 0 :(得分:7)
知道我应该自己处理mallocated内存,但这是否意味着当我在指定的内存外写字时没有迹象表明出现了问题?
欢迎使用C编程:)。一般来说,这是正确的:你可以做错事,并且不会立即收到反馈。实际上,在某些情况下,您可以做错事,从不在运行时看到问题。但是,在其他情况下,您会看到崩溃或其他对您没有意义的行为。
关键术语是未定义的行为。这是一个你应该熟悉的概念,如果你继续用C语言编程。它就像听起来一样:如果你的程序违反了某些规则,行为是 undefined - 它可能会做你想要的,它可能会崩溃,它可能会做一些不同的事情。更糟糕的是,它可能会做你想要的大多数,但偶尔会做一些与众不同的事情。
正是这种机制允许C程序快速运行 - 因为它们不会在运行时执行很多可能用于Python的检查 - 但它也会使C变得危险。编写错误的代码并且不知道它很容易;然后在其他地方进行微妙的更改,或使用不同的编译器或操作系统,代码将不再按您的意愿运行。在某些情况下,这可能会导致安全漏洞,因为不受欢迎的行为可能会被利用。
答案 1 :(得分:2)
假设您有一个如下所示的数组。
int arr[5] = {6,7,8,9,10};
从数组的基础知识中,数组的名称是指向数组基本元素的指针。这里,arr是数组的名称,它是一个指向基本元素的指针,它是6.因此,*arr
,字面上,*(arr+0)
给出6作为输出和*(arr +1)给你7等等。
这里,数组的大小是5个整数元素。现在,尝试访问第10个元素,尽管数组的大小是5个整数。 arr[10]
。这不会给你一个错误,而是给你一些垃圾价值。由于arr只是一个指针,因此取消引用将以arr+0
,arr+1
,arr+2
等方式完成。以同样的方式,您也可以使用基本数组指针访问arr+10
。
现在,尝试使用此示例了解您的上下文。虽然您只为字符分配了2个字节的内存,但您可以访问超出使用指针分配的两个字节的内存。因此,它不会给你一个错误。另一方面,您可以预测机器的输出。但是不能保证您可以预测另一台机器上的输出(可能是您在机器上分配的内存中填充了零,并且可能是第一次使用那些特定的内存位置!)。在声明中,
char *new_token = realloc(curr_token, 6);
请注意,您正在为curr_token
指向new_token
指针所指向的6个字节的数据重新分配内存。现在,new_token
的初始大小将为6个字节。
答案 2 :(得分:1)
通常malloc
的实现方式是它分配与段落(基本对齐)对齐的内存块,等于16个字节。
因此,当您请求分配例如2个字节时,malloc实际上分配了16个字节。这允许在调用realloc
时使用相同的内存块。
根据C标准(7.22.3内存管理功能)
- ...如果分配成功,则返回指针 它可以被分配给指向任何类型对象的指针 具有基本对齐要求,然后用于访问此类 对象或分配的空间中的此类对象的数组 (直到空间被明确解除分配)。
醇>
尽管如此,你不应该依赖这种行为,因为它不是规范性的,因此被视为未定义的行为。
答案 3 :(得分:0)
在C中不执行自动边界检查。 程序行为是不可预测的。 如果你在为另一个进程保留的内存中写入,你将以分段错误结束,否则你只会损坏数据,ecc ......