C++动态数组导致赋值时出现分段错误

C++ dynamic array causes segmentation fault at assignment

本文关键字:分段 错误 赋值 动态 数组 C++      更新时间:2023-10-16

我正在做一个使用套接字的应用程序,所以我在一个套接字处理的数组中。我有以下代码:

while(0 == 0){
    int * tx = (int*)(malloc((nr_con + 2) * sizeof(int)));
    if (conexiuni != NULL)
    {
        syslog(LOG_NOTICE,"Ajung la eliberare %d",nr_con);
        memcpy(&tx[0],&conexiuni[0],(sizeof(int) * (nr_con)));
        syslog(LOG_NOTICE,"Ajung la eliberare %d",nr_con);
        free(conexiuni);
    }
    conexiuni = tx;
    syslog(LOG_NOTICE,"Ajung la mama %d",nr_con);
    //The line bellow causes a segfault at second connection
    if ((conexiuni[nr_con] = accept(hsock,(sockaddr*)(&sadr),&addr_size)) != -1)
    {
        nr_con++;
        syslog(LOG_NOTICE,"Primesc de la %s",inet_ntoa(sadr.sin_addr));
        syslog(LOG_NOTICE,"kkt %d",conexiuni[nr_con - 1]);
        int * sz = (int*)malloc(sizeof(int));
        *sz = conexiuni[nr_con - 1];
        syslog(LOG_NOTICE,"after %d",*sz);
        pthread_create(&tidi,0,&ConexiuniHandler, sz);
    }
}

当我第二次连接时,当我分配数组时,程序崩溃。我做错了什么?我在Windows上尝试了同样的代码,它运行得很好,但在Linux上它崩溃了。

使用std::vector

一个封装动态大小数组的序列容器。

我假设您想要做的是让一个接受连接的服务器,然后在接受连接时,启动一个线程来处理该连接请求。因此,每次执行accept时,您都希望启动一个线程并将套接字句柄赋予它。您还可以使用数组中的所有套接字句柄,当您接受新的连接请求时,这些句柄会动态增加。

以下是建议的方法。我没有做任何测试,甚至没有编译这个代码段,但这是一个起点。我正在做的一件事是,每次调整数组大小时,将套接字句柄数组增加16个块。我这样做是因为它可以通过减少对malloc()的调用次数,使内存管理器的工作变得更容易,并减少碎片数量。

int nr_con = 0;      // we start off with no connections
int block_con = 16;  // number of blocks to allocate each time we increase the array
SOCKET  *conexiuni = malloc ((nr_con + block_con) * sizeof(SOCKET));
while(1) {
syslog (LOG_NOTICE, "Ajung la mama %d", nr_con);
// wait for a connection request to come in.  if it does, log the request
// then create a thread to handle the request providing the socket to the thread.
// we are keeping an array of the sockets that is dynamically increased so
// we will allocate blocks of 16 at a time as we lengthen the array.
if ((conexiuni[nr_con] = accept (hsock, (sockaddr*)(&sadr), &addr_size)) != -1)
{
block_con--;
if (block_con < 1) {
{
// so lets add another block to our array by allocating the memory
// then copying the current array to the new memory area then freeing
// the old memory area which is no longer needed.
block_con = 16;
SOCKET *pTemp = malloc(nr_con + block_con) * sizeof(SOCKET));
syslog (LOG_NOTICE, "Ajung la eliberare %d", nr_con);
memcpy (pTemp, conexiuni, (sizeof(SOCKET) * (nr_con + 1)));
syslog (LOG_NOTICE, "Ajung la eliberare %d", nr_con);
free (conexiuni);
conexiuni = pTemp;
}
syslog (LOG_NOTICE, "Primesc de la %s", inet_ntoa(sadr.sin_addr));
syslog (LOG_NOTICE, "kkt %d", conexiuni[nr_con]);
SOCKET  *sz = conexiumi + nr_con;
syslog (LOG_NOTICE, "after %d", *sz);
// start the thread which is to service this connection request.
pthread_create (&tidi, 0, &ConexiuniHandler, sz);
nr_con++;
}
}

然而,这样的事情也有一些问题。首先,在上面的例子中,如果malloc()由于无法提供内存请求而返回NULL指针,我不会处理内存不足错误。

第二个问题是,在数组被动态扩展之前,线程可能不会访问指向套接字的指针,从而导致所提供的指针无效,因为它在动态重新分配期间被释放。因此,如果你有很多快速连接,这可能是一个问题。线程至少应该做的第一件事是制作套接字句柄的本地副本。

另一个问题是,如何返回数组,以确定哪些套接字仍然有效且打开,哪些套接字在连接关闭时已过时。您是否只是在连接请求到来时不断动态分配空间,直到服务器启动并运行几天后内存耗尽?

与其使用int,不如使用SOCKET,因为它是实际的数据类型。我意识到,在大多数情况下,SOCKET实际上是int,但在这些情况下,通常更准确。