我写了一个C程序如下:
int *a; /* pointer variable declaration */
int b; /* actual variable declaration */
*a=11;
a=&b;/* store address of b in pointer variable*/
运行程序时出现分段错误。
我更改了代码如下:
int *a; /* pointer variable declaration */
int b; /* actual variable declaration */
a=&b;/* store address of b in pointer variable*/
*a=11;
现在它工作正常。
如果有人知道请解释为什么它在CASE 1中给出了分段错误。
答案 0 :(得分:16)
CASE .1
int *a; /* pointer variable declaration */
int b; /* actual variable declaration */
*a=11;//Not valid means you are not owner of the address where a now pointing it is unknown and accessing this will segfault/
a=&b;/* store address of b in pointer variable*/
这将是分段错误,因为您使用的地址不是有效地址,而您存储的是非法的地址。
b
+-------+ +--------+
| + | 11 |
|Unknown| | |
+---+---+ +---+----+
| |
| |
+ +
a a
CASE .2
int *a; /* pointer variable declaration */
int b; /* actual variable declaration */
a=&b;/* store address of b in pointer variable*/
*a=11;
现在它的工作正常,因为b的地址是有效的,你存储11是合法的。
以上情况也是指针声明的正确方法
int *a = NUll;
a = malloc(sizeof(int));
*a=5;
free(a);//must
或
int *a = NUll;
int b;
a = &b;
*a=5;
这将很多次删除分段错误,很难找到。
答案 1 :(得分:4)
int *a; // a pointer variable that can hold a memory address of a integer value.
案例1,
*a = 10; // here you have asigned 10 to unknown memory address;
它显示了分段错误,因为将值分配给未定义的内存地址。 未定义的行为。
案例2,
a=&b; // assigning a proper memory address to a.
*a=11;// assigning value to that address
考虑这个例子:
#include<stdio.h>
int main()
{
int *a,b=10;
printf("\n%d",b);
a=&b;
*a=100;
printf("-->%d",b);
}
Output: 10-->100
这就是它的工作原理。
b // name
----------
+ 10 + // value
----------
4000 // address
假设b的内存位置是4000。
a=&b => a=4000;
*a=100 => *(4000)=100 => valueat(4000) => 100
操纵后看起来像这样。
b // name
----------
+ 100 + // value
----------
4000 // address
答案 2 :(得分:4)
一行:您正在取消引用未初始化指针的第一个代码,它显示未定义的行为,在第二个代码中,您将解除引用初始化指针,该指针将允许访问该地址的值。
一点解释:
首先你需要意识到一个指针只是一个整数,一个*var
我们告诉编译器我们将使用变量var
的内容(其中的整数)作为获取该地址中的值的地址。如果有**var
,我们告诉编译器我们将首先使用变量var
的存储值来获取地址处的值,并再次使用此获取的值作为地址并获取存储的值在它。
因此,在您的第一份声明中,它是:
+----------+ +----------+
| garbage | | garbage |
+----------+ +----------+
| a | | b |
+----------+ +----------+
| addr1 | | addr2 |
+----------+ +----------+
然后尝试使用a
中存储的值作为地址。 a
包含垃圾,它可以是任何值,但您无权访问任何地址位置。因此,当您执行*a
时,它将使用a
中的存储值作为地址。因为存储的值可以是任何东西,所以任何事情都可能发生。
如果您有权访问该位置,则代码将继续执行而不会出现分段错误。如果地址碰巧是堆簿保留结构中的地址,或者代码从堆栈或堆栈分配的其他内存区域,那么当您执行*a = 10
时,它只会用{{1}擦除现有值在那个位置。这可能会导致未定义的行为,因为现在您已经更改了某些内容而不了解具有内存实际权限的上下文。如果您没有内存权限,则只会出现分段错误。这称为取消引用未初始化的指针。
您只需在10
中指定a = &b
地址b
的下一个语句。这没有用,因为前一行已取消引用未初始化的指针。
下一个代码在第三个语句后你有这样的东西:
a
第三个声明将 +----------+ +----------+
| addr2 |---+ | garbage |
+----------+ | +----------+
| a | +--> | b |
+----------+ +----------+
| addr1 | | addr2 |
+----------+ +----------+
的地址分配到b
。在此之前a
未被解除引用,因此在初始化之前存储在a
中的垃圾值永远不会用作地址。现在,当您将知识的有效地址分配到a
时,解除引用a
现在可以访问a
指向的值。
扩展答案,你需要注意,即使你已经为指针分配了一个有效的地址,你必须确保在取消引用指针时指针指向的地址的生命周期没过期。例如,返回局部变量。
a
从堆中访问释放的内存位置时也是如此。
int foo (void)
{
int a = 50;
return &a; //Address is valid
}//After this `a' is destroyed (lifetime finishes), accessing this address
//results in undefined behaviour
int main (void)
{
int *v = foo ();
*v = 50; //Incorrect, contents of `v' has expired lifetime.
return 0;
}
答案 3 :(得分:2)
在第一种情况下,您已经声明了一个指针,但是您没有指定它必须指向的地址,因此指针将包含一个属于系统中另一个进程的地址(或者它将包含一个垃圾值根本不是地址,或者它包含一个不能作为内存地址的空值,因此操作系统发送信号以防止无效的内存操作,从而发生分段错误。
在第二种情况下,您要将必须更新的变量的地址分配给指针并存储正确执行的值,因此没有分段错误。
答案 4 :(得分:1)
int a存储随机整数值。所以说* a,你可能正在访问一个超出范围或无效的内存位置。所以这是一个段错误。