簡體   English   中英

C在函數中操縱“對象”

[英]C manipulating “object” in function

我回來了另一個“為什么這行得通,但那不行”的問題。 我正在嘗試構建我的C代碼,以便能夠提高復雜性並使用指向結構的指針,因此具有如下功能

Spline *new_spline() {
    \\code to set up "object" here
    Spline *toReturn = malloc(sizeof(*toReturn));        
    if (toReturn == NULL) perror("malloc toReturn failed in new_spline()\n");
    toReturn->x_vals = x_vals; \\double*
    toReturn->y_vals = y_vals; \\double*
    toReturn->coeffs = coeffs; \\double*
    toReturn->lines = lines; \\int
    toReturn->xmin = xmin; \\double
    toReturn->xmax = xmax;  \\double
    return toReturn;
}

等價地

int free_spline(Spline *s) {
    free(s->x_vals);
    free(s->y_vals);
    free(s->coeffs);
    free(s);
    s = NULL;
    return 0;
}

現在,當我嘗試通過此函數修改樣條曲線時,問題就來了:

int scale_spline(Spline *spline, double scale_fac) {
    double *ys = malloc(spline->lines * sizeof(*ys));
    if (ys == NULL) {
        printf("err in scale_spline()\n");
        exit(0);
    }
    for (int i = 0; i < spline->lines; i++) {
        ys[i] = scale_fac * spline->y_vals[i];
    }
    Spline *toReturn = new_spline(spline->lines, spline->x_vals, ys);
    free_spline(spline);
    free(ys);
    *spline = *toReturn;
    return 0;
}

最初沒有錯誤,並且修改似乎可以正常進行,但是隨后在代碼中不相關的malloc()隨后失敗,出現了段錯誤。 我認為這是因為free_spline()后接* spline = * toReturn並沒有執行我想要的操作,這就是使該指針指向* toReturn指向的數據。 該功能有效的版本是:

int scale_spline(Spline **spline, double scale_fac) {
    double *ys = malloc((*spline)->lines * sizeof(*ys));
    if (ys == NULL) {
        printf("err in scale_spline()\n");
        exit(0);
    }
    for (int i = 0; i < (*spline)->lines; i++) {
        ys[i] = scale_fac * (*spline)->y_vals[i];
    }
    Spline *toReturn = new_spline((*spline)->lines, (*spline)->x_vals, ys);
    free_spline(*spline);
    free(ys);
    *spline = toReturn;
    return 0;
}

為什么scale_spline()的第一個版本確實不好,以及如何修改它以使其仍可與Spline *一起使用? 此代碼可能有很多錯誤,因此歡迎提出任何批評。 謝謝!

注意:

new_spline(spline->lines, spline->x_vals, ys);

復制spline->x_vals 您只是在新樣條曲線中使用了相同的x值集! 因此,如果使用free_spline釋放舊樣條free_spline ,則釋放x值,如果釋放新樣條線,則x值已被釋放,從而導致問題。

要復制它,請添加new_spline

double *x_valsnew= malloc(lines, sizeof(double)); // or xmin?
memcpy(x_valsnew, x_vals, lines*sizeof(double));

(要分配的行數可能與lines有所不同;這取決於您。關鍵是您必須分配新的內存並進行復制。)

在帶有指針的第二個函數中,您可以更改指向的輸入指針。 執行該函數時,輸入指針會在該函數之外獲取實際的新值。

如果僅在最后執行spline = toReturn則第一個函數可以工作,但是由於spline線將值復制為參數,因此該函數之外的值沒有意義。

使用雙指針,可以實現更改指針指向函數外部的位置。

問題出在這里:

free_spline(spline);
free(ys);
*spline = *toReturn;

free_spline(spline); ,您明確地結束於調用free(spline) 因此,您已經完全釋放了spline最初指向的位置。 當您以后將toReturn作為spline副本復制到splinetoReturn其復制到懸空指針,即未定義行為。 如果您只想修改原始的Spline結構,則應該執行以下操作:

    Spline *toReturn = new_spline(spline->lines, spline->x_vals, ys); // compute new spline
    free(spline->x_vals);         // free internals of original one
    free(spline->y_vals);
    free(spline->coeffs);
    free(ys);                     // free intermediate array
    *spline = *toReturn;          // copy the internals to original spline
    free(toReturn);               // free the temp one
    return 0;
}

或者,如果僅y_vals已更改:

    free(spline->y_vals);
    spline->y_vals = ys;
    return 0
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM