我是 C 新手,我有这个问题。为什么以下代码会崩溃:
int *a = 10;
*a = 100;
因为您正在尝试将 100 写入内存位置 0x0000000A,这可能未分配给您的程序。那是,
int *a = 10;
并不意味着指针'a'将指向内存中值为10的位置。这意味着它指向内存中的地址10(0x0000000A)。然后,您想在该地址中写入一些内容,但您没有这样做的“权利”,因为它没有被分配
您可以尝试以下方法:
int *a = malloc(sizeof(int));
*a = 100;
这会奏效,尽管效率极低。如果您只需要一个 int,则应该将其放入堆栈,而不是堆。在 32 位架构上,指针的长度为 32 位,而 int 的长度也为 32 位,因此指向 int 的指针结构占用(至少)8 个字节的内存空间,而不是 4 个。我们甚至还没有提到缓存问题。
您需要将指针分配给内存位置,而不是任意值 (10)。
int cell = 10;
int *a = &cell; // a points to address of cell
*a = 100; // content of cell changed
请参阅我对另一个问题的回答,关于小心C。
对于建议使用它为 int 分配内存的所有答案,我想建议对 malloc() 的使用稍作改变。代替:
a = malloc(sizeof(int));
我建议不要重复变量的类型,因为编译器知道这一点并手动重复它会使代码更加密集,并引入错误风险。如果您稍后将声明更改为例如
long *a;
如果不更改分配,您最终会分配错误的内存量(在一般情况下,在 32 位机器上int
并且long
通常大小相同)。国际海事组织,最好使用:
a = malloc(sizeof *a);
这只是表示“a 指向的类型的大小”,在这种情况下int
,这当然是完全正确的。如果像上面那样改变声明中的类型,这一行仍然是正确的。如果您更改赋值左侧的变量名称,仍然存在风险,但至少您不再不必要地重复信息。
另请注意,sizeof
在实际对象(即变量)上使用它时不需要括号,只需要类型名称,它看起来像强制转换表达式。sizeof
不是函数,而是运算符。
因为你从来没有为 a 分配任何内存。您刚刚为指向 a 的指针分配了一些堆栈空间。
int *a = NULL; a = malloc (sizeof (int)); 如果(一个!= NULL) { *a =10; }
将工作。
或者,您可以提供一些现有变量的地址,这也可以。
IE
int a* = NULL; 诠释 b = 10; a = &b;
这现在意味着做类似的事情
*a = 100;
还将 b 设置为 == 100
下一行,
int *a = 10;
定义一个指向整数a的指针。然后将指针 a指向内存位置 10。
下一行,
*a = 100;
将值 100 放入 a 指向的内存位置。
问题是:
因为您声明了一个指向 int 的指针,所以将指针初始化为 10(一个地址),然后尝试为该地址处的一个 int 赋值。由于地址 10 的内存不属于您的进程,因此您会崩溃。这应该有效:
int *a;
a = malloc(sizeof(int));
*a = 10;
printf("a=%i\n", *a);
free(a);
这段代码甚至可以编译吗?10 不能转换为int *
,除非你像这样转换它:
int *a = (int *) 10;
*a = 100;
在这种情况下,您尝试将 100 写入 10 处的内存地址。这通常不是有效的内存地址,因此您的程序会崩溃。
它可能会崩溃,因为您将指针分配给您无权访问的内存部分,然后您为该内存位置分配了一些值(不允许这样做!)。
好的,今天试图给出最简单的解释,同时试图给你更详细的图片。让我们添加一些括号好吗?
(int*) a = 10;
(*a) = 100;
您尝试将四个字节写入地址范围 [10-13]。您的程序的内存布局通常开始较高,因此您的应用程序不会意外覆盖它可以并且仍然起作用的任何内容(例如,来自 .data、.bss 和堆栈)。所以它最终会崩溃,因为地址范围尚未分配。
指针指向内存位置,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 中都有一个大小标签,因此您无需说明您为 free 例程指向的块的大小。
好的,还有一件事,字符串在内存中是什么样子的?例如,类似于“Cheery”的那个。简单的回答。它是一个以零结尾的字节数组。
0.1.2.3.4.5. 6
C h e e r y \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
我想可能有一些非常低级的工作,您可以直接指定绝对内存地址。例如内核实现?