15

我写了一个C程序如下:

情况1

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;

现在它工作正常。

如果有人知道,请解释为什么它在案例 1 中出现分段错误。

4

5 回答 5

23
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;

这将多次消除难以发现的分段错误。

于 2013-07-26T05:46:37.837 回答
5
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 
于 2013-07-26T05:39:44.687 回答
4

一行:第一个代码您正在取消引用未初始化的指针,该指针表现出未定义的行为,在第二个代码中,您正在取消引用已初始化的指针,该指针将访问该地址处的值。

一点解释:

首先,您需要意识到指针只不过是一个整数,然后*var我们告诉编译器我们将使用变量的内容var(其中的整数)作为地址来获取该地址中的值。如果有**var类似的情况,我们告诉编译器我们将首先使用变量的存储值var来获取地址处的值,然后再次使用这个获取的值作为地址并获取存储在其中的值。

因此,在您的第一个声明中,它是:

           +----------+        +----------+
           |  garbage |        |  garbage |
           +----------+        +----------+
           |    a     |        |    b     |
           +----------+        +----------+
           |  addr1   |        |  addr2   |
           +----------+        +----------+

然后您尝试将存储的值a用作地址。a包含垃圾,它可以是任何值,但您无权访问任何地址位置。因此,下一刻您*a将使用存储的值a作为地址。因为存储的值可以是任何东西,所以任何事情都可能发生。

如果您有权访问该位置,则代码将继续执行而不会出现分段错误。如果该地址恰好是堆簿记结构中的地址,或者是您的代码从堆或堆栈中分配的其他内存区域,那么当您这样做*a = 10时,它将简单地擦除10该位置中的现有值。这可能会导致未定义的行为,因为现在您在不知道上下文的情况下更改了具有实际内存权限的内容。如果您没有访问内存的权限,您只会遇到分段错误。这称为取消引用未初始化的指针。

您执行的下一条语句a = &b仅分配bin的地址a。这无济于事,因为前一行已取消引用未初始化的指针。

下一个代码在第三条语句之后你有这样的东西:

           +----------+        +----------+
           |  addr2   |---+    |  garbage |
           +----------+   |    +----------+
           |    a     |   +--> |    b     |
           +----------+        +----------+
           |  addr1   |        |  addr2   |
           +----------+        +----------+

第三条语句分配binto的地址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;
}
于 2013-07-26T06:05:32.473 回答
2

在第一种情况下,您已经声明了一个指针,但您没有分配它必须指向的地址,因此该指针将包含一个属于系统中另一个进程的地址(或者它会包含一个垃圾值根本不是地址,否则它会包含一个不能是内存地址的空值)因此操作系统会发送一个信号以防止无效的内存操作,因此会发生分段错误。

在第二种情况下,您将必须更新的变量的地址分配给指针并存储正确的值,因此没有分段错误。

于 2013-07-26T05:42:23.993 回答
1

int a 存储一个随机整数值。所以说 *a,您可能正在访问超出范围或无效的内存位置。所以这是一个段错误。

于 2013-07-26T05:28:10.367 回答