我的代码包含一个应用程序,该应用程序由控制台一个客户端 (clientes
) 接收并将其添加到使用 malloc 创建的数组中。在我们可以删除这个客户之后。我们也可以添加一个新的行程 (viajes
) 并删除它(过程类似于代码中所示)。
正如我之前所说,我正在尝试删除使用 malloc 创建的结构数组的最后一项。我将向您展示代码(我如何添加新的 clientes
以及我如何尝试删除它)。还要说我得到的错误在产生错误的行中进行了注释,所以我认为它更直观。还说代码是 MCVE,所以只有复制代码才能运行。我的应用程序的代码是:
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
// DEFINE STRUCTS
struct viaje {
char *identificador;
char *ciudadDestino;
char *hotel;
int numeroNoches;
char *tipoTransporte;
float precioAlojamiento;
float precioDesplazamiento;
};
struct cliente {
char *dni;
char *nombre;
char *apellidos;
char *direccion;
int totalViajes;
struct viaje *viajes;
};
int main(){
// Variables
int i = 0;
int totalClientes = 0;
char dni[255];
char nombre[255];
char apellidos[255];
char direccion[255];
// Init array of struct cliente (in var clientes)
struct cliente *clientes = (struct cliente *)malloc(0);
printf("Input number of elements of struct clientes: ");
scanf("%i", &totalClientes);
fflush(stdin);
// ADDING NEW ELEMENTS INTO CLIENTES
for (i = 0; i < totalClientes; i++) {
// Receive parameters
printf("Input NIF: ");
gets(dni);
fflush(stdin);
printf("Input NAME: ");
gets(nombre);
fflush(stdin);
printf("Input SURNAME: ");
gets(apellidos);
fflush(stdin);
printf("Input ADDRESS: ");
gets(direccion);
fflush(stdin);
// Create memory for his child (MAX_TAM_* are #define int)
clientes = (struct cliente *)realloc(clientes, (i+1)*sizeof(struct cliente));
clientes[i].dni = (char *)malloc(200*sizeof(char));
clientes[i].nombre = (char *)malloc(200*sizeof(char));
clientes[i].apellidos = (char *)malloc(200*sizeof(char));
clientes[i].direccion = (char *)malloc(200*sizeof(char));
clientes[i].viajes = (struct viaje *)malloc(0); // Init clientes[i].viajes to 0 as previously done with clientes
// Adding received element
strcpy(clientes[i].dni, dni);
strcpy(clientes[i].nombre, nombre);
strcpy(clientes[i].apellidos, apellidos);
strcpy(clientes[i].direccion, direccion);
/* DANGER - ERROR HERE */
clientes[i].totalViajes = 0; // HERE I GET A NOT EXPECTED BEHAVIOR - int is not added to clientes[i].totalViajes - Receive NULL
// New element added sucessfully
}
// SHOW ELEMENTS CREATED
for (i = 0; i < totalClientes; i++) {
printf("\n");
printf("%i.\n", i);
printf("NIF: %s\n", clientes[i].dni);
printf("NAME: %s\n", clientes[i].nombre);
printf("SURNAME: %s\n", clientes[i].apellidos);
printf("ADDRESS: %s\n", clientes[i].direccion);
printf("TRAVELS_COUNT: %s\n", clientes[i].totalViajes);
printf("\n");
}
// DELETING AN ELEMENT OF CLIENTES
int posCliente = 0;
printf("Input position of struct clientes that you wanna delete: ");
// posCliente is the position (inside the array) of cliente we wanna remove
scanf("%i", &posCliente);
fflush(stdin);
// Rewind one position array clientes since cliente we want to remove
for (i = posCliente; i < totalClientes-1; i++) {
// Rewind one element array clientes
clientes[i] = clientes[i+1];
}
//freeing memory of this element (now, the element is the last of the array, we have moved it into last position with previously for)
free(clientes[totalClientes].dni);
free(clientes[totalClientes].nombre);
free(clientes[totalClientes].apellidos);
free(clientes[totalClientes].direccion);
clientes[totalClientes].totalViajes = 0;
// Remove / free memory of the element deleted
/* DANGER - ERROR HERE */
//free(clientes[totalClientes]); // HERE I GET AN ERROR: `error: incompatible type for argument 1 of 'free'`
// Now totalClientes is one less (we have deleted one element)
totalClientes--;
// Resize array clientes. It must have one less element (now totalClientes is totalClientes-1)
/* DANGER - ERROR HERE */
//clientes = (struct cliente *)realloc(clientes, (totalClientes)*sizeof(struct cliente)); // HERE I DO NOT GET AN ERROR BUT PROGRAM CRASH
// SHOW ELEMENTS AFTER DELETING
/* DANGER - ERROR HERE */
// if the max legnth is totalClientes+1 we can see that the last element removed with free cointinues existing, so free is not freeing memory well
for (i = 0; i < totalClientes; i++) {
printf("\n");
printf("%i.\n", i);
printf("NIF: %s\n", clientes[i].dni);
printf("NAME: %s\n", clientes[i].nombre);
printf("SURNAME: %s\n", clientes[i].apellidos);
printf("ADDRESS: %s\n", clientes[i].direccion);
printf("TRAVELS_COUNT: %s\n", clientes[i].totalViajes);
printf("\n");
}
}
最佳答案
这里有几个问题。第一:
printf("TRAVELS_COUNT: %s\n", clientes[i].totalViajes);
totalViajes
字段是一个整数,但您正在使用 %s
进行打印,它需要一个指向 null 终止的 char *
字符串。值 0 被解释为 NULL 指针,这就是打印 NULL 的原因。使用 %d
打印整数:
printf("TRAVELS_COUNT: %d\n", clientes[i].totalViajes);
其次,当您转到释放
已删除元素的字符串时,您正在删除错误的元素。您正在使用索引 totalClientes
,它位于数组的末尾。读取数组末尾以及尝试释放
未从malloc
接收的内存时,将调用undefined behavior。 .
您可能想对索引为 totalClientes-1
的最后一个元素执行此操作,但这也不正确,因为它包含列表中最后一个元素的字符串。指向您要删除的内存的指针位于索引 posCliente
中,您在移动元素时会覆盖它,从而导致内存泄漏。将对 free
的调用移动到移动元素的循环之前,并使用 posCliente
作为索引进行清理:
// Remove / free memory of the element deleted
free(clientes[posCliente].dni);
free(clientes[posCliente].nombre);
free(clientes[posCliente].apellidos);
free(clientes[posCliente].direccion);
// Rewind one position array clientes since cliente we want to remove
for (i = posCliente; i < totalClientes-1; i++) {
// Rewind one element array clientes
clientes[i] = clientes[i+1];
}
最后,您不能在数组的最后一个元素上调用 free
,因为 1) 它不是指针,并且 2) 即使您获取了它的地址,也不会返回该地址通过 malloc
。你注释掉的realloc
就可以了。它崩溃的原因是由于您的程序中较早出现的未定义行为。
此外,fflush(stdin)
无效,并且 gets
is insecure and should not be used因为它可以让你溢出你的缓冲区。使用 scanf
代替长度修饰符来指定最大尺寸:
printf("Input NIF: ");
scanf("%254s", dni);
printf("Input NAME: ");
scanf("%254s", nombre);
printf("Input SURNAME: ");
scanf("%254s", apellidos);
printf("Input ADDRESS: ");
scanf("%254s", direccion);
关于c - 使用 malloc 创建的结构数组不会使用 free 和 realloc 删除或调整最后一个元素的大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49451498/