函数接收一个指向double的指针,分配内存并填充生成的double数组 [英] Function receives a pointer to double, allocates memory and fills resulted array of doubles

查看:106
本文介绍了函数接收一个指向double的指针,分配内存并填充生成的double数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的目标是将一个指向double的指针传递给一个函数,在函数内部动态分配内存,用double值填充结果数组,并返回fill数组.在潜伏在StackOverflow中的各个地方之后,我发现了两个相关的主题,即在C C动态增长数组的单独函数中初始化指针.因此,我尝试编写自己的代码.但是,结果与上述主题中描述的结果不同.该程序是同时使用gcc和Visual Studio运行的.

My goal is to pass a pointer to double to a function, dynamically allocate memory inside of the function, fill resulted array with double values and return filled array. After lurking attentively everywhere in StackOverflow, I have found two related topics, namely Initializing a pointer in a separate function in C and C dynamically growing array. Accordingly, I have tried to write my own code. However, the result was not the same as it was described in aforementioned topics. This program was run using both gcc and 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;
}

(来自编译器的警告是关于不兼容的参数类型.请忽略它.)

(Here comes the warning from compiler about incompatible argument type. Ignore it).

输入:

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中完美运行.

I tried this method on several different *nix machines, it fails when the loop uses realloc. SURPRISINGLY, this code works perfect using Visual Studio.

我的问题是:第一个代码允许分配和重新分配内存,甚至将所有分配的内存传递给main(),但是,所有值都为零.问题是什么?至于第二个程序,分割错误的原因是什么?

My questions are: first code allows to allocate and reallocate the memory and even passes all this allocated memory to main(), however, all the values are zeroed. What is the problem? As for the second program, what is the reason of the segmentation error?

推荐答案

正确的做法是这样的:

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

如果将指针传递给函数,并且不仅要更改其指向的值,还希望更改其指向的地址,则必须使用双指针.否则根本不可能.

If you pass a pointer to a function and you want to change not only the value it is pointing at, but change the address it is pointing to you HAVE to use a double pointer. It is simply not possible otherwise.

通过使用sizeof(var)而不是sizeof(type)节省一些麻烦.如果您编写int *p; p = malloc(sizeof(int));,则您将编写两次相同的内容(int),这意味着如果它们不匹配,您可能会弄乱它们,这正是您所经历的.这也使得以后更改代码变得更加困难,因为您需要在多个位置进行更改.如果您改为写int *p; p = malloc(sizeof(*p));,那风险就消失了.

And save yourself some trouble by using sizeof(var) instead of sizeof(type). If you write int *p; p = malloc(sizeof(int));, then you are writing the same thing (int) twice, which means that you can mess things up if they don't match, which is exactly what happened to you. This also makes it harder to change the code afterwards, because you need to change at multiple places. If you instead write int *p; p = malloc(sizeof(*p)); that risk is gone.

另外,不要转换malloc .完全没有必要.

Plus, don't cast malloc. It's completely unnecessary.

分配(和重新分配)时,您始终应该做的另一件事是检查分配是否成功.像这样:

One more thing you always should do when allocating (and reallocating) is to check if the allocation was successful. Like this:

if(count == 0) 
    *p = malloc(sizeof(**p));
else 
    *p = realloc(*p, (count+1)*sizeof(**p));

if(!p) { /* Handle error */ }

还请注意,可以重新分配NULL指针,因此在这种情况下malloc是不必要的.仅在不使用if语句的情况下使用realloc调用.值得一提的是,如果您希望在重新分配失败时能够继续执行,则不应将p赋值给返回值.如果realloc失败,您将失去以前的一切.改为这样:

Also note that it is possible to reallocate a NULL pointer, so in this case the malloc is not necessary. Just use the realloc call only without the if statement. One thing worth mentioning is that if you want to be able to continue execution if the realloc fails, you should NOT assign p to the return value. If realloc fails, you will lose whatever you had before. Do like this instead:

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是地址p中存在的值. **p是地址*p上存在的值.地址运算符&*有点相反,因此*&xx相同.还要记住,用于索引的[]运算符只是语法糖.它的工作方式如下:p[5]转换为*(p+5),具有有趣的效果,即p[5]5[p]相同.

You mentioned in comments below that you're having troubles with pointers in general. That's not unusual. It can be a bit tricky, and it takes some practice to get used to it. My best advice is to learn what * and & really means and really think things through. * is the dereference operator, so *p is the value that exists at address p. **p is the value that exists at address *p. The address operator & is kind of an inverse to *, so *&x is the same as x. Also remember that the [] operator used for indexing is just syntactic sugar. It works like this: p[5] translates to *(p+5), which has the funny effect that p[5] is the same as 5[p].

在上述代码的第一个版本中,我使用p = tmp而不是*p = tmp,并且当我构建一个完整的示例来查找该错误时,我还使用了*p[count]而不是(*p)[count].抱歉,但这确实强调了我的观点.当处理指针,尤其是指向指针的指针时,请真正考虑您正在编写的内容. *p[count]等同于*(*(p+count)),而(*p)[count]等同于*((*p) + count),这是完全不同的,而且不幸的是,即使我使用-Wall -Wextra -std=c18 -pedantic-errors进行编译,也没有发现任何错误.

In my first version of above code, I used p = tmp instead of *p = tmp and when I constructed a complete example to find that bug, I also used *p[count] instead of (*p)[count]. Sorry about that, but it does emphasize my point. When dealing with pointers, and especially pointers to pointers, REALLY think about what you're writing. *p[count] is equivalent to *(*(p+count)) while (*p)[count] is equivalent to *((*p) + count) which is something completely different, and unfortunately, none of these mistakes was caught even though I compiled with -Wall -Wextra -std=c18 -pedantic-errors.

您在下面的评论中提到,您需要转换realloc的结果.这可能意味着您正在使用C ++编译器,在这种情况下,您需要进行转换,并且应该为(double *).在这种情况下,请更改为:

You mentioned in comments below that you need to cast the result of realloc. That probably means that you're using a C++ compiler, and in that case you need to cast, and it should be (double *). In that case, change to this:

double *tmp = (double*)realloc(*p, (count+1)*sizeof(**p));
if(!tmp) {
    fprintf(stderr, "Fail allocating");
    exit(EXIT_FAILURE);
}

*p = tmp;

请注意,我还更改了指针的类型.在C语言中,tmp指针的类型无关紧要,但是在C ++中,它必须是double*指针,或者您需要执行另一种强制转换:*p = (double*)tmp

Note that I also changed the type of the pointer. In C, it does not matter what type of pointer tmp is, but in C++ it either has to be a double* or you would need to do another cast: *p = (double*)tmp

这篇关于函数接收一个指向double的指针,分配内存并填充生成的double数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆