指针初始化导致分段错误

17

我编写了一个C程序,内容如下:

情况1

int *a; /* pointer variable declaration */

int b; /* actual variable declaration */

*a=11;

a=&b;/* store address of b in pointer variable*/

运行程序时出现了分段错误。

我按照以下方式更改了代码:

案例2

int *a; /* pointer variable declaration */

int b; /* actual variable declaration */

a=&b;/* store address of b in pointer variable*/

*a=11;

现在它正常工作。

如果有人知道,请解释为什么在CASE 1中会导致分段错误。

5个回答

24
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*/

由于您正在使用的地址不是有效地址,并且您正在存储非法值11,因此会发生分段错误。

                               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;

这将消除许多次令人难以发现的分割错误。


6
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 

5
一行: 在第一段代码中,您正在取消引用未初始化的指针,这会展示未定义的行为。在第二段代码中,您正在取消引用已初始化的指针,这将使您能够访问地址处的值。
有些解释:
首先,您需要意识到指针只是一个整数,而使用*var时,我们告诉编译器,我们将使用变量var(其中的整数)的内容作为地址来获取该地址中的值。如果有**var,同样地,我们告诉编译器,我们将首先使用存储在变量var中的值来获取地址上的值,然后再使用此获取的值作为地址,并获取存储在其中的值。
因此,在您的第一个声明中,它是:
           +----------+        +----------+
           |  garbage |        |  garbage |
           +----------+        +----------+
           |    a     |        |    b     |
           +----------+        +----------+
           |  addr1   |        |  addr2   |
           +----------+        +----------+

然后,您尝试使用存储在a中的值作为地址。 a包含垃圾值,可以是任何值,但您无法访问任何地址位置。因此,当您执行*a时,它将使用a中存储的值作为地址。由于存储的值可以是任何值,因此任何事情都可能发生。
如果您有访问该位置的权限,则代码将继续执行而不会出现分段错误。如果地址恰好是堆结构或其他内存区域的地址,您的代码从堆栈中分配了该地址,则当您执行*a = 10时,它将简单地用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;
}

在访问堆中已释放的内存位置时同样如此。
int main (void)
{
  char *a = malloc (1);
  *a = 'A'; //Works fine, because we have allocated memory
  free (a); //Freeing allocated memory
  *a = 'B'; //Undefined behaviour, we have already freed 
            //memory, it's not for us now.
  return 0;
}

2

int a 存储一个随机整数值。因此,通过 *a 说可能会访问超出边界或无效的内存位置。因此,这是一个段错误。


2
在第一个情况下,您声明了一个指针,但没有分配它指向的地址,因此指针将包含属于系统中另一个进程的地址(或者它将包含一个不是地址的垃圾值,或者它将包含一个无法成为内存地址的空值),因此操作系统会发送一个信号以防止无效的内存操作,从而导致段错误发生。
在第二种情况下,您将要更新的变量的地址分配给指针,并存储该值,这是正确的方法,因此没有出现段错误。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接