无法在C中正确使用struct指针

时间:2016-11-23 15:13:02

标签: c arrays pointers struct

我是C的初学者,目前正努力在函数中使用结构体。即使我给我的函数指向我的struct并使用它来改变它们的值,看起来我的函数无法自己改变指针的值

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <assert.h>

typedef struct Vector
{
    int n;
    double *entry;
}Vector; 

//defining the struct vector with n for its length and entry as a pointer which will become an array for its values
Vector *newVector(int n)
{
    int i = 0;
    Vector *X = NULL;
    assert(n > 0);
    X = malloc(sizeof(Vector));
    assert(X != NULL);
    X->n = n;
    X->entry = malloc(n+1*sizeof(double));
    assert(X->entry != NULL);
    X->entry[0] = 0;
    for (i=1; i<n+1; ++i) {
        scanf("%lf",&X->entry[i]);
    }
    return X;
}

//making  a new vector struct from the size given and returning its pointer (the array is made so it goes from 1-n instead of 0-(n-1)
void delVector(Vector *X)
{
    assert(X != NULL);
    assert(X->entry != NULL);
    free(X->entry);
    free(X);
    X = NULL;
}

int getVectorLength (Vector *X)
{
    assert(X != NULL);
    return X->n;
}

void setVectorLength(Vector *X, int k)
{
    assert(X != NULL);
    assert(k>0);
    delVector(X);
    printf("so far.\n");
    X = newVector(k);
} //deleting the vector and then replacing it with the new sized vector

double getVectorEntry (Vector *X, int h)
{
    return X->entry[h];
}

void setVectorEntry (Vector *X, int h)
{
    printf("Value %d.\n",h);
    scanf("%lf",&X->entry[h]);
}

main()
{
    Vector *h = NULL;
    h = newVector(3);
    printf("%f\n",h->entry[1]);
    printf("%f\n",getVectorEntry(h,1));
    setVectorEntry(h,1);
    printf("%f\n",getVectorEntry(h,1));
    printf("%d\n",getVectorLength(h));
    setVectorLength(h,6);
    printf("%f\n",getVectorEntry(h,6));
    setVectorEntry(h,6);
    printf("so far.\n");
    printf("%f\n",getVectorEntry(h,6));
}

运行代码一旦到达delVector就会崩溃。如果我要评论delVector它会在X = newVector(k);崩溃,原因我也找不到(它启动函数newVector,但在我输入之前崩溃)。那导致错误的原因是什么? 非常感谢提前!

4 个答案:

答案 0 :(得分:6)

让我们只关注setVectorLength函数

void setVectorLength(Vector *X, int k)
{
    assert(X != NULL);
    assert(k>0);
    delVector(X);
    printf("so far.\n");
    X = newVector(k);
}

这里,Vector * X是一个仅存在于此函数中的局部变量。它指向内存中的某个位置,但使用它您无法修改原始指针。所以有两种方法可以解决它。 1.您不删除并重新创建矢量。而是做这样的事情

void setVectorLength(Vector *X, int k)
{
    X->entry = realloc(X->entry, k*sizeof(double)); // frees X->entry and allocates it to a new heap array
    X->k = k;
}

2。使用指针指针。请注意,这将更慢并且是不必要的。转到1解决方案。

void setVectorLength(Vector **X, int k)
{
    assert(*X != NULL);
    assert(k>0);
    delVector(*X);
    printf("so far.\n");
    *X = newVector(k);
}

变量Vector ** X指向原始变量,因此您可以对其进行修改。

答案 1 :(得分:3)

问题似乎在于功能

Vector *newVector(int n)
{
    int i = 0;
    Vector *X = NULL;
    assert(n > 0);
    X = malloc(sizeof(Vector));
    assert(X != NULL);
    X->n = n;
    X->entry = malloc(n+1*sizeof(double));
    assert(X->entry != NULL);
    X->entry[0] = 0;
    for (i=1; i<n+1; ++i) {
        scanf("%lf",&X->entry[i]);
    }
    return X;
}

在上述声明中,您使用X->entry分配n + sizeof(double),但根据您的要求,您应该分配(n + 1) * sizeof(double)

您应该将X->entry的内存分配为

X->entry = malloc((n + 1) * sizeof(double));

答案 2 :(得分:0)

您的分配错误,您必须将n1分组,就像您在纸上一样。并非您n + 1 * sizeof(double)表达的含义与n + sizeof(double)相同。

X->entry = malloc((n + 1) * sizeof(*X->entry));

将是正确的方式!

实际上,您的代码会调用未定义的行为,一旦可能导致程序崩溃。很可能是因为试图从其内存空间中访问内存,因此发生了分段错误。

答案 3 :(得分:0)

void setVectorLength(Vector *X, int k)
{
    assert(X != NULL);
    assert(k>0);
    delVector(X);
    printf("so far.\n");
    X = newVector(k);
}

在此函数中,X是调用者传入的指针变量的副本。它包含地址的副本。修改函数参数不会更改调用者的值。正如执行k = 0对调用者没有任何影响一样,重新分配X是调用者看不到的本​​地更改。

如果您希望来电者查看newVector(k)的结果,您可以选择几种方式。您可以将setVectorLength()更改为newVector()返回新指针。

Vector *setVectorLength(Vector *X, int k) {
    ...
    printf("so far.\n");
    return newVector(k);
}

int main() {
    ...
    h = setVectorLength(h, 6);
}

或者您可以添加另一层间接 - 使X指向指针的指针。这将要求调用者传递他们想要更改的变量的地址。不是通过h,而是通过&h

void setVectorLength(Vector *X, int k) {
    ...
    printf("so far.\n");
    *X = newVector(k);
}

int main() {
    ...
    setVectorLength(&h, 6);
}

顺便说一下,你写setVectorLength()的方式,它会破坏向量中的任何现有数据。您可能希望将旧向量中的数据复制到新向量。 (或者,as @pi_pi3 suggests,修改矢量而不是销毁它并创建一个新的。)