如何缩短数组?
How can I shorten an array?
我想创建一个函数,通过释放我不再需要的内存,从段数组中删除比给定数字长的段。问题是我创建的函数也释放了给定点之后分配的所有内存。我怎样才能限制它,以便它只释放一个指针而不损害其他指针?
这是我到目前为止编写的代码:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
typedef struct
{
double x1;
double y1;
double x2;
double y2;
} Segment;
double length(Segment* s)
{
return sqrt(pow(s->x1 - s->x2, 2) + pow(s->y1 - s->y2, 2));
}
// HERE IS THE PROBLEM!!
void delete_longer(Segment* as[], int n, double max_len)
{
for(int i = 0; i < n; i++)
{
if(length(as[i]) > max_len)
{
as[i] = NULL; // Those two lines should be swapped, but the problem remains
free(as[i]);
}
}
}
int main()
{
const int SIZE = 5;
Segment** arr = (Segment**)calloc(SIZE, sizeof(Segment*));
for(int i = 0; i < SIZE; i++)
{
arr[i] = (Segment*)malloc(sizeof(Segment));
}
srand(time(0));
for(int i = 0; i < SIZE; i++)
{
arr[i]->x1 = rand() % 100;
arr[i]->x2 = rand() % 100;
arr[i]->y1 = rand() % 100;
arr[i]->y2 = rand() % 100;
printf("Lungezza: %d\n", (int)length(arr[i]));
}
delete_longer(arr, SIZE, 80);
for(int i = 0; i < SIZE && arr[i]; i++)
{
printf("Lunghezza 2: %d\n", (int)length(arr[i]));
}
return 0;
}
你有两个主要问题:
在你写的删除函数中:
as[i] = NULL;
free(as[i]);
这是错误的顺序。您必须先释放内存,然后将元素设置为空。但请注意,这不是您感知到的问题的原因,它只会导致内存泄漏(即 as[i]
的内存变得不可访问)。你应该写:
free(as[i]);
as[i] = NULL;
您的第二个问题出在 for
循环中,该循环现在在第一个空元素处停止。所以不是删除后的所有内存,你就是不打印就行了。循环应该是例如:
for(int i = 0; i < SIZE; i++)
{
printf("Lunghezza 2: %d\n", arr[i]?(int)length(arr[i]):0);
}
注意:我同意 free(NULL)
可能依赖于库函数的旧实现的讨论。在我个人看来,永远不要传递 free
空指针。我认为这是不好的做法。
首先,free 函数应该在将指针设置为NULL 的指令之后,但这不是问题的主要原因。
导致我描述的行为的原因是主程序中的第二个 for 循环在找到第一个 NULL 指针后停止。相反,我应该写:
for(int i = 0; i < SIZE ; i++)
{
if(arr[i])
printf("Lunghezza 2: %d\n", (int)length(arr[i]));
}
无法在运行时更改数组的大小。编译器静态分配内存,甚至自动数组也是固定大小的(除非你使用最后一个 C 标准,在该标准中你可以在声明时指定不同的大小,但即使在那种情况下,数组大小一直保持到数组获取超出范围)。原因是,一旦分配,数组的内存就会被其他声明包围,这些声明是固定的,否则很难使用内存。
另一种方法是动态分配数组。您分配固定数量的单元格,并与数组一起存储,不仅是它的大小,还有它的容量(允许增长的最大单元格数量)认为擦除数组的一个元素需要将所有元素移到后面前面一个地方,这通常是一件昂贵的事情。如果您的数组中充满了对其他对象的引用,一种常见的技术是在未使用的数组单元格上使用 NULL
指针,或者将所有元素移动一个位置到开头。
尽管您使用了这种技术,但数组是访问多个相同类型对象的一种非常有效的方式,但它们很难缩短或延长。
最后,一种以您可以将其视为可变长度的方式处理数组的常用技术是分配固定数量的单元格(最初),如果您需要更多内存来分配双倍的 space原始的(还有其他方法,比如使用斐波那契序列来增长数组)并使用数组的大小和它的实际容量。只有在你的数组已满的情况下,你才调用一个函数来分配一个更大的新数组,调整容量,将元素复制到新副本,并释放旧数组。这将一直有效,直到您再次填充它。
你不会post任何代码,所以我也会这样做。如果您对某些精确代码有疑问,请在您的问题中毫不犹豫地 post,我会尽力为您提供可行的解决方案。
我想创建一个函数,通过释放我不再需要的内存,从段数组中删除比给定数字长的段。问题是我创建的函数也释放了给定点之后分配的所有内存。我怎样才能限制它,以便它只释放一个指针而不损害其他指针? 这是我到目前为止编写的代码:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
typedef struct
{
double x1;
double y1;
double x2;
double y2;
} Segment;
double length(Segment* s)
{
return sqrt(pow(s->x1 - s->x2, 2) + pow(s->y1 - s->y2, 2));
}
// HERE IS THE PROBLEM!!
void delete_longer(Segment* as[], int n, double max_len)
{
for(int i = 0; i < n; i++)
{
if(length(as[i]) > max_len)
{
as[i] = NULL; // Those two lines should be swapped, but the problem remains
free(as[i]);
}
}
}
int main()
{
const int SIZE = 5;
Segment** arr = (Segment**)calloc(SIZE, sizeof(Segment*));
for(int i = 0; i < SIZE; i++)
{
arr[i] = (Segment*)malloc(sizeof(Segment));
}
srand(time(0));
for(int i = 0; i < SIZE; i++)
{
arr[i]->x1 = rand() % 100;
arr[i]->x2 = rand() % 100;
arr[i]->y1 = rand() % 100;
arr[i]->y2 = rand() % 100;
printf("Lungezza: %d\n", (int)length(arr[i]));
}
delete_longer(arr, SIZE, 80);
for(int i = 0; i < SIZE && arr[i]; i++)
{
printf("Lunghezza 2: %d\n", (int)length(arr[i]));
}
return 0;
}
你有两个主要问题:
在你写的删除函数中:
as[i] = NULL;
free(as[i]);
这是错误的顺序。您必须先释放内存,然后将元素设置为空。但请注意,这不是您感知到的问题的原因,它只会导致内存泄漏(即 as[i]
的内存变得不可访问)。你应该写:
free(as[i]);
as[i] = NULL;
您的第二个问题出在 for
循环中,该循环现在在第一个空元素处停止。所以不是删除后的所有内存,你就是不打印就行了。循环应该是例如:
for(int i = 0; i < SIZE; i++)
{
printf("Lunghezza 2: %d\n", arr[i]?(int)length(arr[i]):0);
}
注意:我同意 free(NULL)
可能依赖于库函数的旧实现的讨论。在我个人看来,永远不要传递 free
空指针。我认为这是不好的做法。
首先,free 函数应该在将指针设置为NULL 的指令之后,但这不是问题的主要原因。 导致我描述的行为的原因是主程序中的第二个 for 循环在找到第一个 NULL 指针后停止。相反,我应该写:
for(int i = 0; i < SIZE ; i++)
{
if(arr[i])
printf("Lunghezza 2: %d\n", (int)length(arr[i]));
}
无法在运行时更改数组的大小。编译器静态分配内存,甚至自动数组也是固定大小的(除非你使用最后一个 C 标准,在该标准中你可以在声明时指定不同的大小,但即使在那种情况下,数组大小一直保持到数组获取超出范围)。原因是,一旦分配,数组的内存就会被其他声明包围,这些声明是固定的,否则很难使用内存。
另一种方法是动态分配数组。您分配固定数量的单元格,并与数组一起存储,不仅是它的大小,还有它的容量(允许增长的最大单元格数量)认为擦除数组的一个元素需要将所有元素移到后面前面一个地方,这通常是一件昂贵的事情。如果您的数组中充满了对其他对象的引用,一种常见的技术是在未使用的数组单元格上使用 NULL
指针,或者将所有元素移动一个位置到开头。
尽管您使用了这种技术,但数组是访问多个相同类型对象的一种非常有效的方式,但它们很难缩短或延长。
最后,一种以您可以将其视为可变长度的方式处理数组的常用技术是分配固定数量的单元格(最初),如果您需要更多内存来分配双倍的 space原始的(还有其他方法,比如使用斐波那契序列来增长数组)并使用数组的大小和它的实际容量。只有在你的数组已满的情况下,你才调用一个函数来分配一个更大的新数组,调整容量,将元素复制到新副本,并释放旧数组。这将一直有效,直到您再次填充它。
你不会post任何代码,所以我也会这样做。如果您对某些精确代码有疑问,请在您的问题中毫不犹豫地 post,我会尽力为您提供可行的解决方案。