我有以下代码段:
struct client {
char* ip_address;
int port;
struct timeval last_seen;
};
/* setup socket */
struct client** clients = malloc(0);
unsigned int n_clients = 0;
for (uint32_t iter = 0; ; iter++) {
/* some socket code, that populates client_ip_address, client_prt and timestamp */
n_clients++;
struct client client = {client_ip_address, client_port, timestamp};
clients = realloc(clients, n_clients * sizeof(struct client*));
memcpy(clients[n_clients-1], client, sizeof client);
}
基本上,我试图跟踪阵列clients
内连接到我的套接字的所有客户端的IP,端口和时间戳。但是,memcpy
行导致分段错误,我在做什么错了?
答案 0 :(得分:1)
从注释继续,没有必要将指针分配给 struct client
,然后为每个 struct 分配。简单分配/重新分配 struct数组会更有意义。您还必须确保您的:
/* some socket code populates ip_address, port and timestamp */
实际上为char *ip_address;
分配了存储空间,因为它只是一个指针,在使用之前必须指向有效的存储空间。
您的分配/重新分配方案也有些混乱。您想在尝试使用阵列中的其他存储之前检查是否需要重新分配。另外,您总是realloc
到一个临时指针,以避免丢失指向您数据的指针,因为realloc
在返回NULL
时失败。如果您使用原始指针重新分配,例如clients = realloc (clients, ...)
和realloc
返回NULL
,您用NULL
覆盖了指针地址,丢失了指针并造成了内存泄漏。
调整顺序并实现临时指针的使用,您可以执行以下操作:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NSTRUCT 8 /* initial number of struct to allocate */
struct client {
char *ip_address; /* must be allocated separately */
int port;
struct timeval last_seen;
};
int main (void) {
size_t n_clients = 0, /* number of clients filled */
n_alloced = NSTRUCT; /* number of clients allocated */
struct client *clients = malloc (n_alloced * sizeof *clients);
if (!clients) { /* validate every allocation */
perror ("malloc-clients");
return 1;
}
for (uint32_t iter = 0; ; iter++) {
if (n_clients == n_alloced) { /* check if realloc required */
/* always realloc with a temporary pointer, or risk data loss */
void *tmp = realloc (clients, 2 * n_alloced * sizeof *clients);
if (!tmp) { /* validate reallocation */
perror ("realloc-clients");
break; /* don't exit, original clients still valid */
}
clients = tmp; /* assign reallocated block to clients */
n_alloced *= 2; /* update allocated number of struct */
}
struct client client = {client_ip_address, client_port, timestamp};
/* some socket code populates ip_address, port and timestamp */
if (/* client filled correctly */) {
memcpy (&clients[n_clients], &client, sizeof client);
n_clients++;
}
}
}
(注意:client.ip_address
的存储必须是分配的类型,此外,由于client
只是一个结构,clients[n_clients] = client;
就足够了-并且{{ 1}}上必须没有其他成员或需要复制副本已分配成员的子成员。)
当不再需要分配的内存时,别忘了client
。
编辑-一些套接字代码未分配 free()
由于您的client.ip_address
包含一个指向char的指针作为struct client
成员,因此,如果您的.ip_address
没有为"some socket code"
分配存储空间,则您将必须分别复制该成员(深复制)。使用具有自动存储持续时间的成员简单分配,您可以分别将.ip_address
分配并复制到client.ip_address
,如下所示:
clients[n_clients].ip_address
(这也意味着您必须分别 /* some socket code populates ip_address, port but doesn't
* allocate storage for client.ip_address -- you must copy.
*/
if (/* client filled correctly */) {
/* assignment is sufficient for non-allocated members */
clients[n_clients] = client;
size_t len = strlen (client.ip_address);
clients[n_clients].ip_address = malloc (len + 1);
if (!clients[n_clients].ip_address) {
perror ("malloc-clients[n_clients].ip_address");
break;
}
memcpy (clients[n_clients].ip_address, client.ip_address,
len + 1);
n_clients++;
}
每个free()
成员才能释放数组)
如果您的编译器提供了.ip_address
,则可以将strdup()
的副本简化为:
.ip_address
答案 1 :(得分:0)
首先,我们需要处理该错误。
cc -Wall -Wshadow -Wwrite-strings -Wextra -Wconversion -std=c99 -pedantic -g `pkg-config --cflags glib-2.0 --cflags json-glib-1.0 --cflags json-c` -c -o test.o test.c
test.c:23:34: error: passing 'struct client' to parameter of incompatible type
'const void *'
memcpy(clients[n_clients-1], client, sizeof client);
^~~~~~
memcpy
使用指针。 client
不存储指针,而是存储整个结构。您需要传递&client
。
问题是您正在尝试将结构复制到指向该结构的指针的位置。
struct client** clients
是struct client*
的数组。就是这样,它是一个指针数组。 clients = realloc(clients, n_clients * sizeof(struct client*));
正在为n_clients
中的clients
指针分配空间。很好。
memcpy(clients[n_clients-1], &client, sizeof client);
试图将整个结构复制到仅应使用指针的空间中。它会将16个字节推入8个字节的空间(假定为64位)。
client
正在使用自动堆栈存储器,一旦离开该块,该堆栈存储器将被覆盖。您需要为其分配堆内存,将其复制到该内存,然后将指向堆内存的指针存储在clients
中。
n_clients++;
// Put the struct in stack memory
struct client client = {client_ip_address, client_port};
// Allocate space for the pointer in the list.
clients = realloc(clients, n_clients * sizeof(struct client*));
// Allocate space for the struct in heap memory.
struct client *tmp = malloc(sizeof(struct client));
// Copy the struct from stack to heap memory
memcpy(tmp, &client, sizeof client);
// Store the pointer to heap memory
clients[n_clients-1] = tmp;
但是跳过栈内存并首先将client
分配为堆内存会更容易。
n_clients++;
// Allocate heap memory for the struct.
struct client* client = malloc(sizeof(struct client));
// Initialize the struct.
client->ip_address = client_ip_address;
client->port = client_port;
// Allocate space for the pointer.
clients = realloc(clients, n_clients * sizeof(struct client*));
// Store the pointer.
clients[n_clients-1] = client;