不,您的示例不安全。
您的 ptr 变量未显式初始化。
如果ptr 是一个局部变量,它将被初始化为一个未定义(即随机)的值。因此,*ptr = 5 会将值 5 写入随机内存位置。这将导致内存损坏或(更有可能)分段错误。请参阅以下示例:
#include <stdio.h>
int main(void)
{
int *ptr; /* Local variables are not intitialized and contain a random value */
printf("ptr contains address %p\n", ptr); /* Prints a random value */
ptr[0] = 123; /* BAD: On macOS causes memory corruption */
return 0;
}
另请参阅下面的注释 [1]。
如果ptr 是一个全局变量,它将被初始化为零。这个*ptr = 5 会将值 5 写入虚拟地址 0,这很可能会导致分段错误。
#include <stdio.h>
int *ptr; /* Global variables are initialized to zero */
int main(void)
{
printf("ptr contains address %p\n", ptr); /* Prints 0x0 */
ptr[0] = 123; /* BAD: On macOS causes "Segmentation fault: 11" */
return 0;
}
静态变量也是如此:
#include <stdio.h>
int main(void)
{
static int *ptr; /* Static variable are initialized to zero */
printf("ptr contains address %p\n", ptr); /* Prints 0x0 */
ptr[0] = 123; /* BAD: On macOS causes "Segmentation fault: 11" */
return 0;
}
如果要使用不指向数组的指针,则应显式分配内存,例如通过调用malloc
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int *ptr; /* Local variables are not intitialized and contain a random value */
/* Explicitly allocate enough memory to store one int value */
ptr = malloc(sizeof(int));
if (!ptr) {
fprintf(stderr, "Out of memory");
exit(1);
}
printf("ptr contains address %p\n", ptr); /* Prints a random value "on the heap" */
*ptr = 111; /* OK */
printf("*ptr contains value %d\n", *ptr); /* OK, 111 */
printf("ptr[0] contains value %d\n", ptr[0]); /* OK, 111 */
ptr[0] = 222; /* OK */
printf("*ptr contains value %d\n", *ptr); /* OK, 222 */
printf("ptr[0] contains value %d\n", ptr[0]); /* OK, 222 */
/* Must explicitly free memory after you are done with it, otherwise you have a memory leak */
free(ptr);
return 0;
}
如果您将指针指向一个 int,则使用 *p 或 p[0](本质上是相同的)读取或写入取消引用的指针是安全的,但 p[1] 是不安全:
#include <stdio.h>
int main(void)
{
int foo = 111;
int bar = 222;
int *ptr = &bar;
printf("Address of ptr %p\n", &ptr); /* An address on the stack */
/* Some random value */
/* Note: this is the address OF the ptr variable, */
/* and not the address stored IN ptr */
printf("Address of bar %p\n", &bar); /* An address on the stack */
/* Exact difference with ptr depends on compiler etc. */
/* On macOS: 12 bytes after address of ptr */
printf("Address of foo %p\n", &foo); /* An address on the stack */
/* Exact difference with bar depends on compiler etc. */
/* On macOS: 4 bytes after address of bar */
printf("foo contains value %d\n", foo); /* 111 */
printf("bar contains value %d\n", bar); /* 222 */
printf("ptr contains address %p\n", ptr); /* The same as address of bar above */
ptr[0] = 333; /* Perfectly safe, changes the value of bar */
printf("bar contains value %d\n", bar); /* 333 */
ptr[1] = 444; /* BAD technically the behavior is undefined */
/* But most likely will change the value of foo */
/* Because most likely foo is stored after bar on the stack */
printf("foo contains value %d\n", foo); /* On macOS: 444 */
return 0;
}
注意 [1]:意外“缓冲区溢出”是 C 程序中非常常见的问题,尤其是在处理字符串时。这是新手 C 程序员最常见的错误之一。请参阅下面的示例。许多病毒利用这些漏洞制作一个特殊的字符串来强制进行非常小心控制的溢出,从而导致函数返回地址(也存储在堆栈中)被覆盖。当函数返回时,它不是返回调用函数,而是返回到攻击者精心选择的某个地址。这允许攻击者执行她选择的一些代码。当我说很大一部分病毒以这种方式工作时,我认为我并没有夸大其词。所以,要小心并密切注意你的内存管理!!!详情请见https://developer.apple.com/library/archive/documentation/Security/Conceptual/SecureCodingGuide/Articles/BufferOverflows.html。
#include <stdio.h>
#include <string.h>
int main(void)
{
int foo = 111;
char str[5];
printf("foo contains value %d\n", foo); /* 111 */
strcpy(str, "12345678"); /* BAD: Overflow! Writing 9 bytes into a 5 byte string */
/* (9 not 8, because of the terminating 0 byte ) */
/* Modern operating systems / compilers / processors catch this */
/* On my macOS, I get "Abort trap 6" */
/* Technically, behavior is undefined */
/* In practice, foo is overwritten */
printf("foo contains value %d\n", foo); /* With older operating systems / compilers / */
/* processors this would show a changed value */
return 0;
}