我是C的新手,我有这个问题。为什么以下代码崩溃:
int *a = 10;
*a = 100;
答案 0 :(得分:20)
因为你试图将100写入内存位置0x0000000A,这可能没有分配给你的程序。也就是说,
int *a = 10;
并不意味着指针'a'将指向内存中具有值10的位置。这意味着它指向内存中的地址10(0x0000000A)。然后,你想在这个地址写一些东西,但你没有这样做的“权利”,因为它没有被分配
您可以尝试以下操作:
int *a = malloc(sizeof(int));
*a = 100;
这会起作用,虽然非常低效。如果您只需要一个int,那么您应该将其放入stack, not the heap。在32位架构上,指针长度为32位,int也是32位长,因此指向int的指针结构以这种方式占用(at least)8字节的内存空间4.我们甚至没有提到过缓存问题。
答案 1 :(得分:12)
您需要将指针指定给内存位置,而不是任意值(10)。
int cell = 10;
int *a = &cell; // a points to address of cell
*a = 100; // content of cell changed
请参阅my answer另一个问题,关注 C 。
答案 2 :(得分:7)
我想建议稍微改变malloc()的使用,以便建议使用它来为int分配内存。而不是:
a = malloc(sizeof(int));
我建议不要重复变量的类型,因为编译器已知并且手动重复它会使代码更加密集,并且会带来错误风险。如果您稍后将声明更改为例如
long *a;
在不更改分配的情况下,最终会分配错误的内存量(在一般情况下,在32位计算机上int
和long
通常大小相同)。这是IMO,更好用:
a = malloc(sizeof *a);
这仅仅意味着“a指向的类型的大小”,在本例中为int
,这当然是完全正确的。如果您如上所述更改声明中的类型,则此行仍然正确。如果您更改作业左侧变量的名称仍然存在风险,但至少您不再需要不必重复信息。
另请注意,sizeof
在实际对象(即变量)上使用时不需要括号,只能使用类型名称,类似于强制转换表达式。 sizeof
不是函数,而是运算符。
答案 3 :(得分:2)
因为你从来没有为a分配任何内存。您刚刚为指向。
的指针分配了一些堆栈空间int *a = NULL; a = malloc (sizeof (int)); if (a != NULL) { *a =10; }
会工作。
或者你可以给出一些现有变量的地址,这也可以。
即
int a* = NULL; int b = 10; a = &b;
现在这意味着做类似
的事情*a = 100;
还将b设置为== 100
答案 4 :(得分:2)
以下一行,
int *a = 10;
定义指向整数 a 的指针。然后,指向指针a到内存位置10。
下一行,
*a = 100;
将值100放在a指向的内存位置。
问题是:
答案 5 :(得分:1)
因为您声明了一个指向int的指针,将指针初始化为10(一个地址),然后尝试为此地址的int赋值。由于地址10处的内存不属于您的进程,因此会崩溃。这应该有效:
int *a;
a = malloc(sizeof(int));
*a = 10;
printf("a=%i\n", *a);
free(a);
答案 6 :(得分:1)
这段代码甚至可以编译吗? 10不能转换为int *
,除非你像这样投射:
int *a = (int *) 10;
*a = 100;
在这种情况下,您尝试将100写入10的内存地址。这通常不是有效的内存地址,因此程序崩溃。
答案 7 :(得分:0)
它可能会崩溃,因为您将指针分配给您无权访问的内存的某些部分,然后您将一些值分配给该内存位置(您不允许这样做!)。< / p>
答案 8 :(得分:0)
好的,今天尝试给出最简单的解释,同时试图给你更详细的图片。让我们添加一些括号吗?
(int*) a = 10;
(*a) = 100;
您尝试将四个字节写入地址范围[10-13]。程序的内存布局通常更高,因此您的应用程序不会意外地覆盖任何可能的地方并且仍然起作用(例如来自.data,.bss和stack)。所以它最终会崩溃,因为地址范围尚未分配。
指针指向内存位置,C静态类型定义指针的类型。虽然你可以轻松覆盖指针。简单地:
(void*) v = NULL;
我们在这里进一步研究。什么是空指针?它只是指向地址0的指针。
您还可以为指针指定结构类型:
struct Hello {
int id;
char* name;
};
...
struct Hello* hello_ptr = malloc(sizeof Hello);
hello_ptr->id = 5;
hello_ptr->name = "Cheery";
好的,什么是malloc? Malloc分配内存并返回指向已分配内存的指针。它具有以下类型签名:
void* malloc(size_t size);
如果您没有保守的垃圾收集器,很可能您的内存不会自动释放。因此,如果您希望从刚刚分配的内容中恢复使用内存,则必须执行以下操作:
free(hello_ptr);
你所做的每个malloc都有一个size-tag,所以你不需要说明你指向free -routine的块的大小。
好的,还有一件事,字符串在内存中的样子是什么?例如,类似于“Cheery”的那个。简单回答。它是一个以零结尾的字节数组。
0.1.2.3.4.5. 6
C h e e r y \0
答案 9 :(得分:0)
你也可以把它写成:
int* a = 10;
*a = 100;
注意第一行的不同间距。这不是一种流行的风格,但我个人认为它更清晰。它与编译器具有完全相同的含义。
然后,大声朗读:
"Pointer-to-int 'a' becomes 10"
"Value-pointed-to-by 'a' becomes 100"
代替实际值:
"Value-pointed-to-by 10 becomes 100"
...您意识到10不太可能指向您可以使用的内存。
你几乎不会分配一个带有文字的指针:
int* ptr = (int*)10; // You've guessed at a memory address, and probably got it wrong
int* ptr = malloc(sizeof(int)); // OS gives you a memory address at runtime
我猜可能会有一些非常低级别的作业,您可以直接指定绝对内存地址。例如内核实现?