Scanf和动态内存分配

huangapple go评论107阅读模式
英文:

Scanf and Dynamic memory allocation

问题

以下是翻译好的代码部分:

int **elem;
elem = (int **)malloc(sizeof(int **) * numCol);

for (i = 0; i < 2; i++)
    for (j = 0; j < numCol; j++)
    {
        scanf("%d", &elem[i][j]); // 这里不应该给指向int的指针赋值吗?
    }
int **elem;
elem = (int **)malloc(sizeof(int **) * numCol);

for (i = 0; i < 2; i++)
{
    elem[i] = (int *)malloc(numCol * sizeof(int));

    // 用值填充它

    for (j = 0; j < numCol; j++)
    {
        scanf("%d", &elem[i][j]);
    }
}

这段代码的问题是与指针的内存分配和访问有关。在第一段代码中,elem 是一个指向指针的指针(int **),但在分配内存后,elem 没有正确分配给二维数组的内存。这导致了段错误。在第二段代码中,elem 的内存分配得更正确,它首先为每一行分配了内存,然后可以安全地访问这些内存。关于为什么要使用 int ** 而不是 int,这取决于你的需求,如果你需要创建一个二维数组,那么使用 int ** 是正确的选择,因为它允许你动态分配不同大小的行。如果你知道数组的大小是固定的,那么使用 int[][] 也是可以的。

英文:
int **elem;
elem = (int **)malloc(sizeof(int**) * numCol);

        for (i = 0; i &lt; 2; i++)
		for (j = 0; j &lt; numCol; j++)
		{
			scanf(&quot;%d&quot;, &amp;elem[i][j]); //Shouldn&#39;t it give a value to the address pointed by 
                                     //a pointer to pointer to int?
			
		}

Why does this code give a segmentation fault error?(Segmentation fault: 11)
And this code works:

int **elem;
elem = (int **)malloc(sizeof(int**) * numCol);

        for (i = 0; i &lt; 2; i++)
	    {
		elem[i] = (int *)malloc(numCol * sizeof(int));

		// Fill it with values

		for (j = 0; j &lt; numCol; j++)
		{
			scanf(&quot;%d&quot;, &amp;elem[i][j]);
		}

I'm confused. Besides that segmentation problem, doesn't int ** give a value of 4 ? Why not just use int.

答案1

得分: 2

第一个代码片段由于您没有为数组"columns"分配任何内存而导致段错误 - 每个elem[i]都没有指向任何有意义的内容。

分配类似这样的“不规则”数组的一般模式如下:

/**
 * 分配N个“行”,实际上是指向T的指针数组
 */
T **arr = malloc(sizeof *arr * numRows); // 适用于任何类型T
if (arr)
{
  /**
   * 对于每个“行”,分配一个T的数组
   */
  for (size_t i = 0; i < numRows; i++)
  {
    arr[i] = malloc(sizeof *arr[i] * numCols);
    if (arr[i])
    {
      for (size_t j = 0; j < numCols; j++)
      {
        // 初始化 arr[i][j]
      }
    }
  }
}

图片可能有助于理解。

首先,您从arr指针开始:

         T **
         +–––+
    arr: |   |
         +–––+

然后,您分配一个指向T的指针数组作为“行”(为了保持图片的合理大小,我们假设有两行两列):

         T **      T *
         +–––+     +–––+
    arr: |   | ––> |   | arr[0]
         +–––+     +–––+
                   |   | arr[1]
                   +–––+

最后,您为每个“行”分配T的数组:

         T **      T *               T
         +–––+     +–––+             +–––+
    arr: |   | ––> |   | arr[0] –––> |   | arr[0][0]
         +–––+     +–––+             +–––+
                   |   | arr[1] –+   |   | arr[0][1]
                   +–––+         |   +–––+
                                 |
                                 |   +–––+
                                 +-> |   | arr[1][0]
                                     +–––+
                                     |   | arr[1][1]
                                     +–––+

请注意,sizeof (int **)不保证与sizeof (int *)sizeof (int)相同(在x86_64上,指针大小通常为8字节)。

需要注意的是,使用这种分段分配方式,行在内存中不会连续 - arr[1][0]不会紧随arr[0][1]

英文:

The first code snippet segfaults because you haven’t allocated any memory for the array columns - each elem[i] doesn’t point to anything meaningful.

The general pattern for allocating "jagged" arrays like this is as follows:

/**
 * Allocate N &quot;rows&quot;, which is actually an array of 
 * pointers to T
 */
T **arr = malloc( sizeof *arr * numRows ); // for any type T
if ( arr )
{
  /**
   * For each &quot;row&quot;, allocate an array of T
   */
  for ( size_t i = 0; i &lt; numRows; i++ )
  {
    arr[i] = malloc( sizeof *arr[i] * numCols );
    if ( arr[i] )
    {
      for ( size_t j = 0; j &lt; numCols; j++ )
      {
        // initialize arr[i][j]
      }
    }
  }
}

Pictures may help.

First you start with the arr pointer:

     T **
     +–––+
arr: |   |
     +–––+

Then you allocate an array of pointer to T as your “rows” (to keep the picture a reasonable size, we’ll assume two rows and two columns):

     T **      T *
     +–––+     +–––+
arr: |   | ––&gt; |   | arr[0]
     +–––+     +–––+
               |   | arr[1]
               +–––+

Finally you allocate arrays of T for each “row”:

     T **      T *               T
     +–––+     +–––+             +–––+
arr: |   | ––&gt; |   | arr[0] –––&gt; |   | arr[0][0]
     +–––+     +–––+             +–––+
               |   | arr[1] –+   |   | arr[0][1]
               +–––+         |   +–––+
                             |
                             |   +–––+
                             +-&gt; |   | arr[1][0]
                                 +–––+
                                 |   | arr[1][1]
                                 +–––+

There’s no guarantee that sizeof (int **) is the same as sizeof (int *) or sizeof (int) (on x86_64, pointer sizes are typically 8 bytes).

Note that with this kind of piecemeal allocation, the rows are not going to be contiguous in memory - arr[1][0] does not immediately follow arr[0][1].

答案2

得分: 1

I'm confused. Besides that segmentation problem, doesn't int ** give a value of 4? Why not just use int.

不是所有的机器都是这样的,因此在sizeof函数中使用正确的类型以避免在程序运行时发现错误会更加正确。

Why does this code give a segmentation error? (Segmentation fault: 11)
And this code works?

第一段代码在动态分配int** elem的内存时有错误,实际上你只分配了矩阵的一行。

在第二段代码中,你对矩阵进行了正确的初始化。请注意,在第二段代码中,你的循环是for i < 2。这种初始化只在numCol等于2时才正确。

一个更好的代码可能是这样的:

int **elem;
elem = (int **)malloc(sizeof(int*) * numCol); //对sizeof进行了修正

for (i = 0; i < numCol; i++) //对numCol而不是2进行循环
{
    elem[i] = (int *)malloc(numCol * sizeof(int));

    // 填充它的值

    for (j = 0; j < numCol; j++)
    {
        scanf("%d", &elem[i][j]);
    }
}
英文:

> I'm confused. Besides that segmentation problem, doesn't int ** give a
> value of 4? Why not just use int.

Not in all machine this is true, so it's correct to use the right type in the sizeof function to avoid error complicated to find out when program is running.

> Why does this code give a segmentation error?(Segmentation fault: 11)
> And this code works?

the first piece of code has an error in dynamic allocation of memory for the int** elem in fact you allocate only a row in the matrix.

In the second code you do the right initialization of the matrix. Pay attention in the second code your cycle is for i<2. This initialization is correct only if numCol is equal to 2.

A better code can be this :

int **elem;
elem = (int **)malloc(sizeof(int*) * numCol); //a correction in sizeof

        for (i = 0; i &lt; numCol; i++) //cycle on numCol and not on 2
        {
            elem[i] = (int *)malloc(numCol * sizeof(int));

            // Fill it with values

            for (j = 0; j &lt; numCol; j++)
            {
                scanf(&quot;%d&quot;, &amp;elem[i][j]);
            }
 }

huangapple
  • 本文由 发表于 2020年1月3日 19:26:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/59577794.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定