我在以下C代码中遇到了分段错误:
#include#include #include #include #include #include #include #include #include #include #define PORT 6667 #define MAXDATASIZE 1024 int bot_connect(char *hostname); int bot_connect(char *hostname) { int sockfd, numbytes, s; char buf[MAXDATASIZE]; struct addrinfo hints, *servinfo, *p; int rv; char m[1024]; char *message; char *nick = "Goo"; char *ident = "Goo"; char *realname = "Goo"; memset(&hints,0,sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; rv = getaddrinfo(hostname, PORT, &hints, &servinfo); if (rv != 0) { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); return 1; } for (p = servinfo; p != NULL; p = p->ai_next) { sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol); if (sockfd == -1) { perror("Client: socket"); continue; } if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) { close(sockfd); perror("Client: connect"); continue; } break; } if (p == NULL) { fprintf(stderr, "Client: failed to connect \n"); return 2; } freeaddrinfo(servinfo); strcat(m, "NICK "); strcat(m, nick); message = m; s = send(sockfd, message, strlen(message), 0); strcat(m, "USER "); strcat(m, ident); strcat(m, " * * :"); strcat(m, realname); message = m; s = send(sockfd, message, strlen(message), 0); message = "JOIN #C&T"; s = send(sockfd, message, strlen(message), 0); close(sockfd); }
我知道你试图用你不允许做的内存做一些分段错误,比如改变只读内存,但据我所知,这个程序不会这样做.有没有人知道细分故障的来源?
你strcat( m, "NICK" );
在初始化m之前打电话.在strcat之前,尝试m[0] = '\0';
或者memset( m, 0, sizeof( m ) );
,或者先strcat
改为strcpy
此外,在套接字上发送NICK线后,strcat
再次调用,这会将USER线附加到NICK线.再说一遍,你应该把第一个更改strcat
为strcpy
格雷姆对"什么"是正确的,所以这里是"为什么",以防你不熟悉.在C中,字符串被定义为由空字符'\ 0'终止的一系列字符.字符串具有终止字符的原因是代码可以找出字符串逻辑结束的位置.即使你声明一个这样的字符串:
char m[1024];
在C中没有办法给出m给出的代码可以找出它分配了1024个字节,更不用说弄清楚这些字节有多少是有意义的,而没有一个空字符划分有意义字节的结尾.
strcat是一个可以处理两个C字符串的函数,因此它希望它的两个参数都符合规范,即有一个空字节标记有意义输入的结束.如果m未初始化,则其内容是随机的,因此空字节可以是任何位置,或者根本不存在空字节.为了连接,strcat将查看第一个参数的字符,试图找到标记字符串结尾的空字节.如果偶然,没有空字节未初始化数组中存在,它会很乐意继续寻找过去的字符串的末尾,成可以对应于其它变量的任意存储位置,或内部堆栈信息等
当strcat最终找到一个空字节时,它会愉快地写出从该位置开始的第二个参数的内容,如果该位置超过m的结尾,它将覆盖其他一些变量或其他信息.如果它是一个分配给其他变量的内存地址,那么问题可能是沉默的,很难找到.幸运的是,在你的情况下,它是一个不应写入的位置,所以你的程序崩溃了一个明显的错误.
这也提示你应该使用strncat而不是strcat.strncat允许您指定要创建的字符串的最大长度.我之前注意到strcat无法确定m是否有1024个字节分配给它,所以如果你试图将m与m长于1023个字符的东西连接起来,你最终会遇到相同的内存覆盖问题.strncat接受第三个参数,该参数指定结果字符串的最大长度,并且具有返回代码,该返回代码将指示是否由于达到此长度而截断了连接.