c - 函数接收指向双精度的指针,分配内存并填充结果的双精度数组
问题描述
我的目标是将指向 double 的指针传递给函数,在函数内部动态分配内存,用 double 值填充结果数组并返回填充数组。在 StackOverflow 中到处潜伏之后,我发现了两个相关的主题,分别是 Initializing a pointer in a separate function in C和C 动态增长数组。因此,我尝试编写自己的代码。但是,结果与上述主题中描述的不同。该程序使用 gcc 和 Visual Studio 运行。
一审。
int main()
{
double *p;
int count = getArray(&p);
<...print content of p...>
return 0;
}
int getArray(double *p)
{
int count = 1;
while(1)
{
if(count == 1)
p = (double*)malloc(sizeof(double));
else
p = (double*)realloc(p, count*sizeof(double));
scanf("%lf", &p[count-1]);
<...some condition to break...>
count++;
{
<... print the content of p ...>
return count;
}
(这是来自编译器的关于不兼容参数类型的警告。忽略它)。
输入:
1.11
2.22
3.33
输出:
1.11
2.22
3.33
0.00
0.00
0.00
二审。
int main()
{
double *p;
int count = getArray(&p);
<...print content of p...>
return 0;
}
int getArray(double **p)
{
int count = 1;
while(1)
{
if(count == 1)
*p = (double*)malloc(sizeof(double));
else
{
double ** temp = (double*)realloc(*p, count*sizeof(double));
p = temp;
}
scanf("%lf", &(*p)[count-1]);
<...some condition to break...>
count++;
{
<... print the content of p ...>
return count;
}
输入:
1.11
2.22
Segmentation error.
我在几个不同的 *nix 机器上尝试了这种方法,当循环使用 realloc 时它失败了。令人惊讶的是,这段代码使用 Visual Studio 可以完美运行。
我的问题是:第一个代码允许分配和重新分配内存,甚至将所有分配的内存传递给 main(),但是,所有值都归零。问题是什么?至于第二个程序,分段错误的原因是什么?
解决方案
正确的做法是这样的:
int getArray(double **p)
{
int count = 0;
while(1)
{
if(count == 0)
*p = malloc(sizeof(**p));
else
*p = realloc(*p, (count+1)*sizeof(**p));
scanf("%lf", &((*p)[count]));
<...some condition to break...>
count++;
{
<...print content of p...>
return count;
}
如果你将一个指针传递给一个函数,并且你不仅想改变它指向的值,而且改变它指向的地址,你必须使用双指针。否则根本不可能。
并且通过使用 sizeof(var) 而不是 sizeof(type) 来省去一些麻烦。如果你写int *p; p = malloc(sizeof(int));
,那么你在写同样的东西 (int) 两次,这意味着如果它们不匹配,你可能会把事情搞砸,这正是发生在你身上的事情。这也使得之后更改代码变得更加困难,因为您需要在多个地方进行更改。如果你改为写int *p; p = malloc(sizeof(*p));
,风险就消失了。
另外,不要投射 malloc。这是完全没有必要的。
分配(和重新分配)时您应该做的另一件事是检查分配是否成功。像这样:
if(count == 0)
*p = malloc(sizeof(**p));
else
*p = realloc(*p, (count+1)*sizeof(**p));
if(!p) { /* Handle error */ }
另请注意,可以重新分配 NULL 指针,因此在这种情况下malloc
不需要。只使用realloc
没有 if 语句的调用。值得一提的是,如果您希望在 realloc 失败时能够继续执行,则不应将 p 分配给返回值。如果 realloc 失败,您将失去以前拥有的一切。改为这样做:
int getArray(double **p)
{
int count = 0;
// If *p is not pointing to allocated memory or NULL, the behavior
// of realloc will be undefined.
*p = NULL;
while(1)
{
void *tmp = realloc(*p, (count+1)*sizeof(**p));
if(!tmp) {
fprintf(stderr, "Fail allocating");
exit(EXIT_FAILURE);
}
*p = tmp;
// I prefer fgets and sscanf. Makes it easier to avoid problems
// with remaining characters in stdin and it makes debugging easier
const size_t str_size = 100;
char str[str_size];
if(! fgets(str, str_size, stdin)) {
fprintf(stderr, "Fail reading");
exit(EXIT_FAILURE);
}
if(sscanf(str, "%lf", &((*p)[count])) != 1) {
fprintf(stderr, "Fail converting");
exit(EXIT_FAILURE);
}
count++;
// Just an arbitrary exit condition
if ((*p)[count-1] < 1) {
printf("%lf\n", (*p)[count]);
break;
}
}
return count;
}
您在下面的评论中提到您通常在使用指针时遇到问题。这并不罕见。这可能有点棘手,需要一些练习才能习惯。我最好的建议是了解什么*
和&
真正意味着什么,并真正考虑清楚。*
是取消引用运算符,因此*p
存在于 address 的值p
。**p
是存在于 address 的值*p
。地址操作符&
是 的一种逆运算符,*
因此*&x
与 x
还要记住,[]
用于索引的运算符只是语法糖。它的工作原理是这样的:p[5]
转换为*(p+5)
,它具有与p[5]
相同的有趣效果5[p]
。
在我上面代码的第一个版本中,我使用p = tmp
了代替,*p = tmp
当我构建了一个完整的示例来查找该错误时,我也使用*p[count]
了代替(*p)[count]
。很抱歉,但这确实强调了我的观点。在处理指针,尤其是指向指针的指针时,真的要考虑你在写什么。*p[count]
相当于*(*(p+count))
while(*p)[count]
相当于*((*p) + count)
which 完全不同,不幸的是,即使我用-Wall -Wextra -std=c18 -pedantic-errors
.
您在下面的评论中提到您需要转换realloc
. 这可能意味着您正在使用 C++ 编译器,在这种情况下您需要强制转换,它应该是(double *)
. 在这种情况下,更改为:
double *tmp = (double*)realloc(*p, (count+1)*sizeof(**p));
if(!tmp) {
fprintf(stderr, "Fail allocating");
exit(EXIT_FAILURE);
}
*p = tmp;
请注意,我还更改了指针的类型。在 C 中,指针的类型无关紧要tmp
,但在 C++ 中,它要么必须是 a,double*
要么您需要进行另一个强制转换:*p = (double*)tmp
推荐阅读
- kendo-ui - 在剑道 ui 网格中获取 id
- amazon-web-services - AWS ALB 是否支持反向代理和发布重定向?
- javascript - 在新选项卡中的组件之间传递数据
- javascript - 如何直接从我的计算机自动发送 http 请求
- php - 当页面加载/刷新时,我的 PHP 表单正在发送空白条目
- powershell - 如何使用运行 sudo 命令的 Powershell 远程进入 Centos 机器?
- vim - 如何在vim中组织列?
- css - Squarespace 中的中心字体弹出按钮
- ballerina - 芭蕾舞女演员:相同的类型是不相容的
- python - Windows:如何配置多个版本的 Python 协同工作?