能够找出函数内部 realloc 的问题

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

can figure out the problem with my realloc inside the function

问题

我正在编写一个需要调用一个函数的程序,该函数会一直添加数字,直到输入-1为止,问题是在输入3个数字后程序停止并出现分段错误:

int leNumeros(int **lista, int *nElem, int *tam)
{
    int op, *temp = NULL;
    *lista = (int*) malloc(*tam * sizeof(int));
    
    if(*lista == NULL)
    {
        printf("memory fail\n");
    } else
    {
        do
        {
            printf("number:\n");
            scanf("%d", &op);

            if(op >= 0)
            {
                if(*nElem >= *tam)
                {
                *lista = (int*) realloc( *lista, *nElem * sizeof(int) );
                
                if(*lista == NULL)
                {
                    printf("memory fail");
                }
                else
                {
                    printf("added: %d bytes total: %d bytes\n",
                            *nElem * sizeof(int), *nElem * sizeof(int) + *tam * sizeof(int));
                    //*lista = temp;
                }
                }
                (*lista)[*nElem] = op;
                (*nElem)++;
            }
        } while(op >= 0);
    }    
}


int main(int argc, char** argv) {
    
    int *lista = NULL, nElem = 0, tam = 0;
    
    leNumeros(&lista, &nElem, &tam);
    
    return (EXIT_SUCCESS);
}

我有困难理解发生了什么,请问有人可以帮助我吗?

英文:

I'm writing a program that needs to call a function that adds numbers until -1 is introduced, the problem is that after 3 numbers the program stops and gives segmentation fault:

int leNumeros(int **lista, int *nElem, int *tam)
{
    int op, *temp = NULL;
    *lista = (int*) malloc(*tam * sizeof(int));
    
    if(*lista == NULL)
    {
        printf("memory fail\n");
    } else
    {
        do
        {
            printf("number:\n");
            scanf("%d",&op);

            if(op >= 0)
            {
                if(*nElem >= *tam)
                {
                *lista = (int*) realloc( *lista, *nElem * sizeof(int) );
                
                if(*lista == NULL)
                {
                    printf("memory fail");
                }
                else
                {
                    printf("added: %d bytes total: %d bytes\n",
                            *nElem * sizeof(int), *nElem * sizeof(int) + *tam * sizeof(int));
                    //*lista = temp;
                }
                }
                *lista[*nElem] = op;
                (*nElem)++;
                
                
                
            }
        }while(op >= 0);
    }    
}


int main(int argc, char** argv) {
    
    int *lista = NULL, nElem = 0, tam = 0;
    
    leNumeros(&lista, &nElem, &tam);
    
    return (EXIT_SUCCESS);
}

I'm having trouble understanding what is going on, can anyone help me please?

答案1

得分: 2

当调用leNumeros()时,您尝试分配一个零长度的块 - 这具有_实现定义的行为_。

然后,当您输入一个大于0的数字时,您尝试realloc()一个零长度的块 - 这个行为是_明确定义的_,它会释放原始块然后返回一个空指针,然后在*lista[*nElem] = op;处,您对该空指针进行了解引用,而不是中止循环。

无论如何,*lista[*nElem] = op; 应该是 (*lista)[*nElem] = op;

即使 *nElem 是非零的,以下这行代码也是不良实践,因为如果重新分配失败,原始块将泄漏,因为 *lista 将变为 NULL,而不释放它之前指向的任何内容。相反,您应该(例如):

int* new_block = realloc(*lista, *nElem * sizeof(int));
if (new_block == NULL)
{
    printf("内存失败\n");
    break;
}

*lista = new_block;

要使主函数正常工作,tam 必须大于 0,为了避免由于实现定义的行为而可能的失败,nElem 也应该大于零。

英文:

When leNumeros() is called you attempt to allocate a zero length block - that has implementation defined behaviour.

Then when you enter a number > 0, you attempt to realloc() a zero length block - that behaviour is well defined it frees the original block then returns a null pointer, then at *lista[*nElem] = op; you deference that null pointer rather than aborting the loop.

In any event *lista[*nElem] = op; should be (*lista)[*nElem] = op;

Even if *nElem was non-zero, the line:

*lista = (int*)realloc(*lista, *nElem * sizeof(int));

is bad-practice, because if the reallocation fails the original block will leak because *lista will be come NULL without releasing whatever it previously pointed to. Instead you should (for example):

int* new_block = realloc(*lista, *nElem * sizeof(int));
if( new_block == NULL )
{
    printf( "memory fail\n" ) ;
    break ;
}

*lista = new_block ;

To work at all in main tam must be > 0, and to avoid possible failure due to implementation defined behaviour nElem should also be grater than zero.

答案2

得分: 1

我认为 tam 参数可能是要分配的块大小。例如,如果 tam = 10,那么分配空间给 10 个整数。然后在取 10 个整数后,重新分配 10 个。

此外,请注意,由于运算符优先级,*lista[*nElem] = op;*(lista[*nElem]) = op; 是相同的。您应该先解引用指针,然后使用方括号:(*lista)[*nElem] = op;

void leNumeros(int **lista, int *nElem, int *tam)
{
    if (*tam <= 0) {
        puts("Error: tam must be > 0");
        return;
    }

    int op;

    // 记录数组可以容纳多少个整数
    int items_allocated = *tam;
    *lista = malloc(*tam * sizeof(int));

    if (*lista == NULL)
    {
        printf("memory fail\n");
    }
    else
    {
        do
        {
            printf("number:\n");
            if (1 != scanf("%d", &op)) break;

            if (op >= 0) {
                // 如果空间不足,重新分配 tam 个字节的新块
                if (*nElem >= items_allocated) {
                    items_allocated += *tam;
                    int *temp = realloc(*lista, items_allocated * sizeof(int));

                    if (temp == NULL) {
                        printf("memory fail");
                        break;
                    }
                    else {
                        *lista = temp;
                        printf("added: %zu bytes total: %zu bytes\n", *tam * sizeof(int), items_allocated * sizeof(int));
                    }
                }
                (*lista)[*nElem] = op;
                (*nElem)++;
            }
        } while (op >= 0);
    }
}

int main(int argc, char** argv) {

    int *lista = NULL, nElem = 0, tam = 5;
    leNumeros(&lista, &nElem, &tam);

    for (int i = 0; i < nElem; i++) {
        printf("%d ", lista[i]);
    }

    return (EXIT_SUCCESS);
}
英文:

I think the tam parameter is probably the block size to allocate. So for example, if tam = 10, allocate space for 10 ints. Then after taking 10 ints, realloc for 10 more.

Also, note that because of operator precedence, *lista[*nElem] = op; is the same as *(lista[*nElem]) = op;. You want to deference the pointer first, then use the brackets: (*lista)[*nElem] = op;

void leNumeros(int **lista, int *nElem, int *tam)
{
    if (*tam &lt;= 0) {
        puts(&quot;Error: tam must be &gt; 0&quot;);
        return;
    }

	int op;

    // Keep track of how many ints the array can hold
	int items_allocated = *tam;
	*lista = malloc(*tam * sizeof(int));

	if (*lista == NULL)
	{
		printf(&quot;memory fail\n&quot;);
	}
	else
	{
		do
		{
			printf(&quot;number:\n&quot;);
			if (1 != scanf(&quot;%d&quot;, &amp;op)) break;

			if (op &gt;= 0) {
				// Realloc a new block of tam bytes if out of space
				if (*nElem &gt;= items_allocated) {
					items_allocated += *tam;
					int *temp = realloc(*lista, items_allocated * sizeof(int));

					if (temp == NULL) {
						printf(&quot;memory fail&quot;);
						break;
					}
					else {
                        *lista = temp;
						printf(&quot;added: %zu bytes total: %zu bytes\n&quot;, *tam * sizeof(int), items_allocated * sizeof(int));
					}
				}
				(*lista)[*nElem] = op;
				(*nElem)++;
			}
		} while (op &gt;= 0);
	}
}


int main(int argc, char** argv) {

	int *lista = NULL, nElem = 0, tam = 5;
	leNumeros(&amp;lista, &amp;nElem, &amp;tam);

	for (int i = 0; i &lt; nElem; i++) {
		printf(&quot;%d &quot;, lista[i]);
	}

	return (EXIT_SUCCESS);
}

</details>



huangapple
  • 本文由 发表于 2020年1月4日 01:59:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/59583202.html
匿名

发表评论

匿名网友

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

确定