【问题标题】:Storing data into a dynamic array with structs in C使用 C 中的结构将数据存储到动态数组中
【发布时间】:2015-02-24 21:48:52
【问题描述】:

我在将文件中的数据存储到我的动态数组中时遇到问题。我知道我现在拥有的东西是不正确的,但它目前就在那里。我有一个文件,它在第一行基本上包含数据行的数量。以下行有两个并排的整数来表示有序对。我想将这两个整数存储到一个结构 point 中,它表示一个有序对。此外,还有一个具有这样一个结构的数组,它位于另一个结构 list 内部,其中包含数组的大小,或当前存储在数组中的数据量和容量,即空间总量在数组中。

我想将这两个整数存储到int 类型的变量中,然后将它们存储到我的数组内部的point 中,该数组位于我的list 结构中。 我对有两个结构感到非常困惑,并且不确定这是否是正确的方法。欢迎任何反馈。

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

typedef struct
{
    int x;
    int y;
} point;

typedef struct
{
    int size;
    int capacity;
    point *A;
} list;

// Compute the polar angle in radians formed
// by the line segment that runs from p0 to p
double polarAngle(point p, point p0)
{
    return atan2(p.y - p0.y, p.x - p0.x);
}

// Determine the turn direction around the corner
// formed by the points a, b, and c. Return a
// positive number for a left turn and negative
// for a right turn.
double direction(point a, point b, point c)
{
    return (b.x - a.x)*(c.y - a.y) - (c.x - a.x)*(b.y - a.y);
}

int whereSmallest(point A[], int begin, int end, point p0)
{
    point min = A[begin];
    int where = begin;
    int n;
    for (n = begin + 1; n < end; n++)
        if (polarAngle(A[n], p0) < polarAngle(min, p0))
        {
            min = A[n];
            where = n;
        }
    return where;
}
void selectionSort(point A[], int N, point p0)
{
    int n, s;
    point temp;
    for (n = 0; n < N; n++)
    {
        s = whereSmallest(A, n, N, p0);
        temp = A[n];
        A[n] = A[s];
        A[s] = temp;
    }
}

// Remove the last item from the list
void popBack(list *p)
{
    int x;
    x = p->size - 1;
    p->A[x] = p->A[x + 1];
}

// Return the last item from the list
point getLast(list *p)
{
    point value;
    value = p->A[p->size];
    return value;
}

// Return the next to the last item
point getNextToLast(list *p)
{
    point value;
    value = p->A[p->size - 1];
    return value;
}

int main(int argc, const char *argv[])
{
    point p0, P;
    FILE *input;
    list *p;
    int N, n, x, y;

    /*Assuming that the first piece of data in the array indicates the amount of numbers in the array then we record this number as a reference.*/
    N = 0;
    input = fopen("points.txt", "r");
    fscanf(input, "%d", &N);

    /*Now that we have an exact size requirement for our array we can use that information to create a dynamic array.*/
    p = (point*)malloc(N*sizeof(point));
    if (p == NULL)//As a safety precaution we want to terminate the program in case the dynamic array could not be successfully created.
        return -1;

    /*Now we want to collect all of the data from our file and store it in our array.*/
    for (n = 0; n < N; n++)
    {
        fscanf(input, "%d %d", &P.x, &P.y);
        p->A[n] = P.x;
        p->A[n] = P.y;
    }
    fclose(input);

    free(p);
    return 0;
}

【问题讨论】:

  • //As a safety precaution we want to terminate the program in case the dynamic array could not be successfully created. 非常好的主意,但不要忘记fclose() 文件。还有Don't cast the result of malloc().
  • 该代码能编译吗?
  • @iharob 没必要,C 标准保证在正常退出时为您关闭文件(通过调用 exit() 或从 main 返回)。
  • @orlp 当然,但是你自己做会好很多,因为你可以从一个指示分配失败的函数中返回NULL,如果你在这种情况下忘记这样做,你会在那种情况下也忘了它,所以我相信总是清理所有东西是个好习惯。
  • @iharob 我只转换结果是因为我的导师建议我们这样做,以防学生的编译器不同。

标签: c arrays file struct


【解决方案1】:

首先,你的代码无法编译,因为这个

p->A[n] = P.x;
p->A[n] = P.y;

错了,应该是

p->A[n].x = P.x;
p->A[n].y = P.y;

因为A 具有point 类型,您应该访问结构的成员以便为它们分配值。

但这只是问题的开始,你没有为A指针分配空间,所以这不起作用。

  1. 你需要为list类型的实例分配空间,这样做是这样的

    p = malloc(sizeof(*p));
    
  2. 那你需要初始化p的成员,为之

    p->values   = malloc(N * sizeof(point));
    p->capacity = N;
    p->size     = 0;
    

    如您所见,空间已分配给 values 成员。

  3. 检查fscanf() 以确保数据完整性并避免未定义的行为,如果fscanf() 失败,您将永远不会知道您的代码,并且您可能会访问导致未定义行为的未初始化变量。

  4. 在两个 int 变量中捕获从文件中扫描的值,并仅在 where 成功读取时将它们复制到数组中

    for (n = 0 ; ((n < N) && (fscanf(input, "%d%d", &x, &y) == 2)) ; n++)
    /* check that the values were read from the file _______^ */
    {
        /* store them in the array */
        p->values[n].x = x;
        p->values[n].y = y;
        p->size       += 1;
    }
    
  5. 检查文件是否打开。

我建议以下代码

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

typedef struct
{
    int x;
    int y;
} point;

typedef struct
{
    int size;
    int capacity;
    point *values;
} list;

// Compute the polar angle in radians formed
// by the line segment that runs from p0 to p
double polarAngle(point p, point p0)
{
    return atan2(p.y - p0.y, p.x - p0.x);
}

// Determine the turn direction around the corner
// formed by the points a, b, and c. Return a
// positive number for a left turn and negative
// for a right turn.
double direction(point a, point b, point c)
{
    return (b.x - a.x)*(c.y - a.y) - (c.x - a.x)*(b.y - a.y);
}

int whereSmallest(point values[], int begin, int end, point p0)
{
    point min = values[begin];
    int where = begin;
    int n;
    for (n = begin + 1; n < end; n++)
        if (polarAngle(values[n], p0) < polarAngle(min, p0))
        {
            min = values[n];
            where = n;
        }
    return where;
}
void selectionSort(point values[], int N, point p0)
{
    int n, s;
    point temp;
    for (n = 0; n < N; n++)
    {
        s         = whereSmallest(values, n, N, p0);
        temp      = values[n];
        values[n] = values[s];
        values[s] = temp;
    }
}

// Remove the last item from the list
void popBack(list *p)
{
    int x;
    x = p->size - 1;
    p->values[x] = p->values[x + 1];
}

// Return the last item from the list
point getLast(list *p)
{
    point value;
    value = p->values[p->size];
    return value;
}

// Return the next to the last item
point getNextToLast(list *p)
{
    point value;
    value = p->values[p->size - 1];
    return value;
}

int main(int argc, const char *argv[])
{
    FILE *input;
    list *p;
    int   N, n, x, y;

    /*Assuming that the first piece of data in the array indicates the amount of numbers in the array then we record this number as a reference.*/
    N     = 0;
    input = fopen("points.txt", "r");
    if (input == NULL)
        return -1;
    if (fscanf(input, "%d", &N) != 1)
    {
        fclose(input);
        return -1;
    }

    p = malloc(sizeof(*p));
    if (p == NULL)
        return -1;

    /*Now that we have an exact size requirement for our array we can use that information to create a dynamic array.*/
    p->values   = malloc(N * sizeof(point));
    p->capacity = N;
    p->size     = 0;
    if (p->values == NULL)//As a safety precaution we want to terminate the program in case the dynamic array could not be successfully created.
    {
        free(p);
        fclose(input);

        return -1;
    }

    /*Now we want to collect all of the data from our file and store it in our array.*/
    for (n = 0 ; ((n < N) && (fscanf(input, "%d%d", &x, &y) == 2)) ; n++)
    {
        p->values[n].x = x;
        p->values[n].y = y;
        p->size       += 1;
    }
    fclose(input);

    free(p->values);
    free(p);
    return 0;
}

正如您所看到的,您可以对代码进行另一项改进,这不是很重要,但可以避免使用不必要的 Nn 变量。

注意:在使用函数之前,请尝试通读它的文档,这将防止各种意外结果,例如fscanf(),将帮助您更多地了解我的修复。

【讨论】:

  • 在分配 p 失败时忘记了 fclose。在 for 循环之后检查 n == N 是否会很好地查看 fscanf 是否失败。
  • 我唯一的问题是第4点。在for循环中,为什​​么要检查它是否等于2?
  • 因为你要的是2参数,而*scanf()family返回的是与格式字符串匹配的参数个数,阅读this
  • 感谢您的帮助。我一定会坚持这个链接。
【解决方案2】:

变量p 应该是list p

points数组分配是p.A = (point*)malloc(N*sizeof(point));

在填充循环中,由于 A[n] 是一个点,因此您不能将其分配为 int P.x 或 P.y。您可以像这样直接将值放入 A[n] 点:

for (n = 0; n < N; n++)
{
    fscanf(input, "%d %d", &(p.A[n].x), &(p.A[N].y));
}

列表的大小和容量应该被初始化:p.capacity = N;在内存分配成功之后和p.capacity = n;在填充数组之后

最后你应该调用free(p.A)而不是free(p)

【讨论】:

  • 这个主意不错,但是你的代码还是有bug,很严重,因为你忽略了fscanf()的返回值。
  • 对。但是由于结构混乱而请求帮助,而不是完整的代码审查。
猜你喜欢
  • 2021-06-27
  • 2017-06-02
  • 1970-01-01
  • 2021-06-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-01
  • 1970-01-01
相关资源
最近更新 更多