将字符串复制到 malloc 的 char 数组中失败并出现分段错误
string copy into malloc'd char array fails with segmentation fault
我正在练习C语言的客户端-服务器应用程序。在应用程序中,客户端首先向服务器注册并获得return中的client_id
。下一次开始,客户端将消息发送到服务器,并在消息前加上 client_id
。以下代码片段来自服务器,服务器收到消息后,从消息数组中取出client_id
,这是一个3字符长的字符串,起始地址为1,结束地址为4。例如。在消息 "1001CLIENT:001:MESSAGE:01"
中,位置 0 的“1”是出于某种目的,“001”是 client_id
,"CLIENT:001:MESSAGE:01"
是来自客户端的消息。
char *create_dynamic_string(int str_size)
{
char *dyn_string = malloc(str_size*sizeof(char));
if(!dyn_string)
{
printf("Dynamic string could not be created");
return NULL;
}
dyn_string[0] = '[=10=]';
return dyn_string;
}
void free_dynamic_string(char *dyn_string)
{
free(dyn_string);
}
//char *message is dynamically allocated char array.
char *retrieve_client_id(char *message)
{
char *client_id;
int i;
client_id = create_dynamic_string(CLIENT_ID_SIZE + 1);
if(!client_id)
{
printf("Client_id is NULL");
return NULL;
}
//for(i = 1; i < (CLIENT_ID_SIZE + 1); i++)
// client_id[i-1] = message[i];
//strncpy(client_id, message + 1, CLIENT_ID_SIZE);
memcpy(client_id, message + 1, CLIENT_ID_SIZE);
client_id[CLIENT_ID_SIZE] = '[=10=]';
printf("client_id retrieved=%s", client_id);
return client_id;
}
服务器接受来自客户端的连接并在不同的线程中处理消息。多线程和消息处理的工作已成功测试。下面的代码编译成功并且大部分时间都有效。但有时它会在 retrieve_client_id()
中的 memcpy()
处出现分段错误。我无法弄清楚为什么它会以这种方式失败。
我使用 gdb
来获取更多信息。如下。
Program terminated with signal 11, Segmentation fault.
#0 0x00000000004017ef in retrieve_client_id (message=0x1b904f40 "1000CLIENT:000:MESSAGE:02") at src/server.c:46
46 memcpy(client_id, message + 1, CLIENT_ID_SIZE);
(gdb) print message
= 0x1b904f40 "1000CLIENT:000:MESSAGE:02"
(gdb) print message+1
= 0x1b904f41 "000CLIENT:000:MESSAGE:02"
(gdb) print CLIENT_ID_SIZE
= 3
(gdb) print client_id
= 0xffffffffcc0008c0 <Address 0xffffffffcc0008c0 out of bounds>
(gdb)
需要帮助来理解当应用程序失败时到底发生了什么。我已验证 malloc
成功且 client_id
不为 NULL。正如您看到的注释代码,我还尝试使用 strcpy()
并将字符从源数组一一复制到目标数组。但是我也看到了失败。
我猜测 create_dynamic_string
和 retrieve_client_id
在不同的编译单元中,并且在编译后者时您没有正确的前者可见原型。
这个地址 0xffffffffcc0008c0
看起来像一个合理的堆地址 0xcc0008c0
添加了额外的位。
添加这一行:
extern char *create_dynamic_string(int);
就在 retrieve_client_id
.
的定义之上
如果这解决了问题(它应该),然后将 create_dynamic_string
的原型添加到适当的头文件,并将其 #include
添加到定义 retrieve_client_id
.[=26 的源代码中=]
I did not understand why it did not give compilation error
在 C 中,未声明的函数假定具有以下原型:
int undeclared(...);
因此,以下任何呼叫都不会被拒绝:
int x = undeclared();
int y = undeclared(1);
char *z = undeclared(1, 2, 3);
您可以询问 GCC 警告您缺少原型,特别是 -Wmissing-prototypes
,但最佳做法是使用 -Wall
和 [=23 进行编译=].后者不会让您忽略警告并强制您修复它们。
还建议添加 -Wextra
,尽管它有时会给出误报警告。
我正在练习C语言的客户端-服务器应用程序。在应用程序中,客户端首先向服务器注册并获得return中的client_id
。下一次开始,客户端将消息发送到服务器,并在消息前加上 client_id
。以下代码片段来自服务器,服务器收到消息后,从消息数组中取出client_id
,这是一个3字符长的字符串,起始地址为1,结束地址为4。例如。在消息 "1001CLIENT:001:MESSAGE:01"
中,位置 0 的“1”是出于某种目的,“001”是 client_id
,"CLIENT:001:MESSAGE:01"
是来自客户端的消息。
char *create_dynamic_string(int str_size)
{
char *dyn_string = malloc(str_size*sizeof(char));
if(!dyn_string)
{
printf("Dynamic string could not be created");
return NULL;
}
dyn_string[0] = '[=10=]';
return dyn_string;
}
void free_dynamic_string(char *dyn_string)
{
free(dyn_string);
}
//char *message is dynamically allocated char array.
char *retrieve_client_id(char *message)
{
char *client_id;
int i;
client_id = create_dynamic_string(CLIENT_ID_SIZE + 1);
if(!client_id)
{
printf("Client_id is NULL");
return NULL;
}
//for(i = 1; i < (CLIENT_ID_SIZE + 1); i++)
// client_id[i-1] = message[i];
//strncpy(client_id, message + 1, CLIENT_ID_SIZE);
memcpy(client_id, message + 1, CLIENT_ID_SIZE);
client_id[CLIENT_ID_SIZE] = '[=10=]';
printf("client_id retrieved=%s", client_id);
return client_id;
}
服务器接受来自客户端的连接并在不同的线程中处理消息。多线程和消息处理的工作已成功测试。下面的代码编译成功并且大部分时间都有效。但有时它会在 retrieve_client_id()
中的 memcpy()
处出现分段错误。我无法弄清楚为什么它会以这种方式失败。
我使用 gdb
来获取更多信息。如下。
Program terminated with signal 11, Segmentation fault.
#0 0x00000000004017ef in retrieve_client_id (message=0x1b904f40 "1000CLIENT:000:MESSAGE:02") at src/server.c:46
46 memcpy(client_id, message + 1, CLIENT_ID_SIZE);
(gdb) print message
= 0x1b904f40 "1000CLIENT:000:MESSAGE:02"
(gdb) print message+1
= 0x1b904f41 "000CLIENT:000:MESSAGE:02"
(gdb) print CLIENT_ID_SIZE
= 3
(gdb) print client_id
= 0xffffffffcc0008c0 <Address 0xffffffffcc0008c0 out of bounds>
(gdb)
需要帮助来理解当应用程序失败时到底发生了什么。我已验证 malloc
成功且 client_id
不为 NULL。正如您看到的注释代码,我还尝试使用 strcpy()
并将字符从源数组一一复制到目标数组。但是我也看到了失败。
我猜测 create_dynamic_string
和 retrieve_client_id
在不同的编译单元中,并且在编译后者时您没有正确的前者可见原型。
这个地址 0xffffffffcc0008c0
看起来像一个合理的堆地址 0xcc0008c0
添加了额外的位。
添加这一行:
extern char *create_dynamic_string(int);
就在 retrieve_client_id
.
如果这解决了问题(它应该),然后将 create_dynamic_string
的原型添加到适当的头文件,并将其 #include
添加到定义 retrieve_client_id
.[=26 的源代码中=]
I did not understand why it did not give compilation error
在 C 中,未声明的函数假定具有以下原型:
int undeclared(...);
因此,以下任何呼叫都不会被拒绝:
int x = undeclared();
int y = undeclared(1);
char *z = undeclared(1, 2, 3);
您可以询问 GCC 警告您缺少原型,特别是 -Wmissing-prototypes
,但最佳做法是使用 -Wall
和 [=23 进行编译=].后者不会让您忽略警告并强制您修复它们。
还建议添加 -Wextra
,尽管它有时会给出误报警告。