在C中复制结构的指针

时间:2019-04-26 03:03:50

标签: c pointers segmentation-fault

我有以下代码段:

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行导致分段错误,我在做什么错了?

2 个答案:

答案 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** clientsstruct 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;