调整动态分配数组的大小
Re-sizing dynamically allocated arrays
我已经编写了以下代码来调整数组的大小,如果一个项目在存储它时将超出范围。此代码按预期工作。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//! Our location struct for storing locations
struct location
{
char loc_name[35];
char description[85];
float latitude;
float longitude;
};
void runMenu();
void add_location(struct location** p_location_array, int* p_array_size, int* p_current_size);
void resize_array(struct location** p_location_array, int* p_array_size);
void print (struct location* p_array, int p_current_size);
// Print out the main menu to the user.
void runMenu()
{
printf("[A]dd additional Locations\n");
printf("[P]rint the current list of locations\n");\
printf("[Q]uit the program\n");
}
//! Resize the array to two times it's origional size.
void resize_array(struct location** p_location_array, int* p_array_size)
{
// Allocate enough space for two times the size of the array
int new_size = 2 * (*p_array_size);
struct location* new_location_array = malloc(new_size * sizeof(struct location));
if (!new_location_array)
{
printf ("Cannot add more elements heap has exhausted all space\n");
exit(1);
}
// Copy the old array to the new array.
memcpy(new_location_array, *p_location_array, ((*p_array_size ) * sizeof(struct location)));
// We will update the current size of the array for later checking.
*p_array_size = 2 * (*p_array_size);
// We have a copy of the old array so we can free it.
free(*p_location_array);
// The contents of the pointer reference get the array we malloced in this function
*p_location_array = new_location_array;
}
//! Add a new location to our array. If the array isn't large enough resize it then insert the new struct.
void add_location(struct location** p_location_array, int* p_array_size, int* p_current_size )
{
// Get the users input
struct location new_location;
printf("Enter the new location name\n ");
fscanf(stdin, "%s", new_location.loc_name);
printf("Enter a description of the location\n");
fscanf(stdin, "%s", new_location.description),
printf("Enter the latitude\n");
fscanf(stdin, "%f", &new_location.latitude);
printf("Enter the longitude\n");
fscanf(stdin, "%f", &new_location.longitude);
// Check to see if the size is correct.
if (*p_array_size <= *p_current_size)
{
// If not the correct size resize the array
resize_array(p_location_array, p_array_size);
}
// Insert our sruct
(*p_location_array)[*p_current_size] = new_location;
}
//! Loop over and print out the locations
void print (struct location* p_array, int p_current_size)
{
int i;
for (i = 0; i < p_current_size; i++)
{
struct location current = p_array[i];
printf("%s : %s : %f : %f\n", current.loc_name, current.description, current.latitude, current.longitude);
}
}
int main()
{
char choice = ' ';
short control = 1;
int size;
int currentSize = 0;
printf("Enter the inital size of the array\n");
scanf(" %d", &size);
// Make a new struct array from the heap
struct location* m_location_array =
malloc(size * sizeof(struct location));
// Make sure we have a valid chunk of the heap.
if (!m_location_array)
exit(1);
while(control)
{
runMenu();
scanf(" %c", &choice);
switch (choice)
{
case 'a':
case 'A':
// Do Add additional
add_location(&m_location_array, &size, ¤tSize);
currentSize++;
break;
case 'p':
case 'P':
// Do printing
print (m_location_array, currentSize);
break;
case 'Q':
case 'q':
control = 0;
break;
default:
printf("Invalid input\n");
}
}
// clean up after ourselves.
free (m_location_array);
return 0;
}
然而,当我最初编写这个函数时,我认为可以只传递一个指向数组的指针,而不是像这样传递对指针的引用:
void resize_array(struct location* p_location_array, int* p_array_size)
在不引用指针的情况下调用此函数会引发段错误,表明正在双重释放内存。那是因为传递给函数的指针以某种方式被释放并重新分配了吗?此外,为什么需要像这样通过引用传递指针?即使指针是原始指针的副本,它不仍然指向同一块内存吗?非常感谢任何正确方向的观点。
您提供了一个指向该函数的指针,并且您在那里调用了 free
。所以内存被释放了。之后使用该指针会导致未定义的行为,您可能无法使用它。
在函数内部修改指针变量不会改变函数外部的指针。这就是为什么你需要一个指向指针的指针,这样你就可以在函数外修改指针变量。
Even if the pointer is a copy of the original pointer wouldn't it still point to the same piece of memory?
是的,这就是重点:除非您更改它,否则它会一直指向同一个地方。如果你做一个新的 malloc
它将指向一个完全不同的地方。
还有一个提示:realloc
可能值得一试。
如果您将指针传递给函数,它就是原始函数的副本。那么即使你在函数内部给this指针赋值,比如
p_location_array = new_location_array;
原来的指针(函数外的指针)的值仍然没有改变。因此,如果原始指针指向某个内存区域并且您已将其传递给函数
void resize_array(struct location *p_location_array, int* p_array_size)
并且您在函数内部调用了 free()
并将 NULL
分配给了指针,在您的函数返回后,原始指针将变得不 NULL
。
// warning, changed prototype
void resize_array(struct location *p_location_array, int* p_array_size);
struct location *loc = malloc(size * sizeof(struct location)); // assume loc = 0x12345678
if (loc == NULL) EXIT_FAILURE;
// change pointer inside the function
// assign NULL to the pointer
resize_array(loc, size_p);
if (loc != NULL)
free(loc); // this will be called, loc is still 0x12345678,
// double free, UB
我已经编写了以下代码来调整数组的大小,如果一个项目在存储它时将超出范围。此代码按预期工作。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//! Our location struct for storing locations
struct location
{
char loc_name[35];
char description[85];
float latitude;
float longitude;
};
void runMenu();
void add_location(struct location** p_location_array, int* p_array_size, int* p_current_size);
void resize_array(struct location** p_location_array, int* p_array_size);
void print (struct location* p_array, int p_current_size);
// Print out the main menu to the user.
void runMenu()
{
printf("[A]dd additional Locations\n");
printf("[P]rint the current list of locations\n");\
printf("[Q]uit the program\n");
}
//! Resize the array to two times it's origional size.
void resize_array(struct location** p_location_array, int* p_array_size)
{
// Allocate enough space for two times the size of the array
int new_size = 2 * (*p_array_size);
struct location* new_location_array = malloc(new_size * sizeof(struct location));
if (!new_location_array)
{
printf ("Cannot add more elements heap has exhausted all space\n");
exit(1);
}
// Copy the old array to the new array.
memcpy(new_location_array, *p_location_array, ((*p_array_size ) * sizeof(struct location)));
// We will update the current size of the array for later checking.
*p_array_size = 2 * (*p_array_size);
// We have a copy of the old array so we can free it.
free(*p_location_array);
// The contents of the pointer reference get the array we malloced in this function
*p_location_array = new_location_array;
}
//! Add a new location to our array. If the array isn't large enough resize it then insert the new struct.
void add_location(struct location** p_location_array, int* p_array_size, int* p_current_size )
{
// Get the users input
struct location new_location;
printf("Enter the new location name\n ");
fscanf(stdin, "%s", new_location.loc_name);
printf("Enter a description of the location\n");
fscanf(stdin, "%s", new_location.description),
printf("Enter the latitude\n");
fscanf(stdin, "%f", &new_location.latitude);
printf("Enter the longitude\n");
fscanf(stdin, "%f", &new_location.longitude);
// Check to see if the size is correct.
if (*p_array_size <= *p_current_size)
{
// If not the correct size resize the array
resize_array(p_location_array, p_array_size);
}
// Insert our sruct
(*p_location_array)[*p_current_size] = new_location;
}
//! Loop over and print out the locations
void print (struct location* p_array, int p_current_size)
{
int i;
for (i = 0; i < p_current_size; i++)
{
struct location current = p_array[i];
printf("%s : %s : %f : %f\n", current.loc_name, current.description, current.latitude, current.longitude);
}
}
int main()
{
char choice = ' ';
short control = 1;
int size;
int currentSize = 0;
printf("Enter the inital size of the array\n");
scanf(" %d", &size);
// Make a new struct array from the heap
struct location* m_location_array =
malloc(size * sizeof(struct location));
// Make sure we have a valid chunk of the heap.
if (!m_location_array)
exit(1);
while(control)
{
runMenu();
scanf(" %c", &choice);
switch (choice)
{
case 'a':
case 'A':
// Do Add additional
add_location(&m_location_array, &size, ¤tSize);
currentSize++;
break;
case 'p':
case 'P':
// Do printing
print (m_location_array, currentSize);
break;
case 'Q':
case 'q':
control = 0;
break;
default:
printf("Invalid input\n");
}
}
// clean up after ourselves.
free (m_location_array);
return 0;
}
然而,当我最初编写这个函数时,我认为可以只传递一个指向数组的指针,而不是像这样传递对指针的引用:
void resize_array(struct location* p_location_array, int* p_array_size)
在不引用指针的情况下调用此函数会引发段错误,表明正在双重释放内存。那是因为传递给函数的指针以某种方式被释放并重新分配了吗?此外,为什么需要像这样通过引用传递指针?即使指针是原始指针的副本,它不仍然指向同一块内存吗?非常感谢任何正确方向的观点。
您提供了一个指向该函数的指针,并且您在那里调用了 free
。所以内存被释放了。之后使用该指针会导致未定义的行为,您可能无法使用它。
在函数内部修改指针变量不会改变函数外部的指针。这就是为什么你需要一个指向指针的指针,这样你就可以在函数外修改指针变量。
Even if the pointer is a copy of the original pointer wouldn't it still point to the same piece of memory?
是的,这就是重点:除非您更改它,否则它会一直指向同一个地方。如果你做一个新的 malloc
它将指向一个完全不同的地方。
还有一个提示:realloc
可能值得一试。
如果您将指针传递给函数,它就是原始函数的副本。那么即使你在函数内部给this指针赋值,比如
p_location_array = new_location_array;
原来的指针(函数外的指针)的值仍然没有改变。因此,如果原始指针指向某个内存区域并且您已将其传递给函数
void resize_array(struct location *p_location_array, int* p_array_size)
并且您在函数内部调用了 free()
并将 NULL
分配给了指针,在您的函数返回后,原始指针将变得不 NULL
。
// warning, changed prototype
void resize_array(struct location *p_location_array, int* p_array_size);
struct location *loc = malloc(size * sizeof(struct location)); // assume loc = 0x12345678
if (loc == NULL) EXIT_FAILURE;
// change pointer inside the function
// assign NULL to the pointer
resize_array(loc, size_p);
if (loc != NULL)
free(loc); // this will be called, loc is still 0x12345678,
// double free, UB