gpt4 book ai didi

C 指针段错误

转载 作者:太空宇宙 更新时间:2023-11-04 06:32:49 24 4
gpt4 key购买 nike

我有这个 C 代码:

#include <errno.h>
#include <sys/errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include<fcntl.h>
#include <unistd.h>
#include <sys/stat.h>

char *buf;
int c,s; int port=45678;

int recv_m(int c,char *buf);

void get(){

char fileNameBuf[20];
int i=0;
char *s = buf;

if (*s=='/') {
s++;
while (*s!=' ') {

fileNameBuf[i]=*s;
*s++;
i++;
}
fileNameBuf[i]='\0';

}
}

int main(){

//server connected
while ((c = accept(s, (struct sockaddr *) &client, (socklen_t *) &clientlen)) > 0){
// Do whatever a web server does.

char recv_buf[50];
char *r=recv_buf;
while(recv(c, r , 1, 0)!=0){
//stores the received message in recv_buf
}


recv_buf[i]='\0';

if (strncmp(recv_buf, "GET ", 4)==0){
buf=recv_buf+4;
get();
}

}
return (0);
}

*buf 指向字符串 /index.html HTTP/1.0 。在函数结束时,fileNameBuf 应该存储字符串 index.html

while 循环中的次数应为 10。当我运行此代码时,i = 381 并且出现段错误(核心转储)。

我究竟做错了什么?

这是整个代码,所以 *buf 是问题所在?

最佳答案

要么您对 buf 中的内容的假设一定是错误的,要么我们对您所说的意思的解释有误:

*buf points to string "/index.html HTTP/1.1".



如果您声明 char **buf; 并设置:
char *str = "/index.html HTTP/1.1";
char **buf = str;

然后 *buf 指向字符串的开头。这就是为什么创建 SSCCE ( Short, Self-Contained, Correct Example) 很重要的原因;它消除了歧义。

一个SSCCE

这段代码:
#include <stdio.h>

const char *buf = "/index.html HTTP/1.1";

static
void get(void)
{
char fileNameBuf[10];
int i=0;

if (*buf=='/')
{
buf++;
while (*buf!=' ')
{
fileNameBuf[i]=*buf;
buf++;
i++;
printf("%d\n", i);
}
}
printf("%.*s\n", (int)sizeof(fileNameBuf), fileNameBuf);
}

int main(void)
{
get();
return 0;
}

产生这个输出:
1
2
3
4
5
6
7
8
9
10
index.html

当然,我必须注意不要打印超出数组的末尾。你的数组是最小的;它不能包含包含文件名的字符串(空终止符没有空格)。但它不应该崩溃——如果 char *buf = "/index.html HTTP/1.1"; !

完成的代码 - 阶段 1

这与作为程序提交的内容密切相关。它编译得很干净——我没有试过运行它。
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/socket.h>

char *buf;
int c, s; int port = 45678;
struct sockaddr_in server, client;
char *ipaddress = "127.0.0.1";
int clientlen = sizeof(client);
int portset = 0;

int recv_m(int c, char *buf);

static
void get(void)
{
printf("in get method\n");
char fileNameBuf[20];
int i = 0;
printf("%s\n", buf);
char *s = buf;

if (*s == '/')
{
printf("buf==/\n");
s++;
while (*s != ' ')
{
// printf("%c\n",*buf);
// printf("in while\n");
fileNameBuf[i] = *s;
s++;
i++;
printf("%d\n", i);
}
fileNameBuf[i]='\0';
printf("<<%s>>\n", fileNameBuf);
}
else
{
printf("!= '/'\n");
}
}

int main(void)
{
bzero(&server, sizeof(server));

server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(port);

// if (!inet_aton(ipaddress, &server.sin_addr))
// fprintf (stderr, "inet_addr() conversion error\n");

s = socket(AF_INET, SOCK_STREAM, 0); // Create socket
if (!s) {
perror("socket");
exit(0);
}

if (bind(s, (struct sockaddr *) &server, sizeof(server)) < 0) {
perror("bind");
exit(0);
}
printf("binded\n");
if (listen(s, SOMAXCONN) < 0) {
perror("listen");
exit(0);
}
printf("Waiting for connection\n");
while ((c = accept(s, (struct sockaddr *) &client, (socklen_t *) &clientlen)) > 0)
{
// Do whatever a web server does.
printf("got connected\n");
char recv_buf[50];
char el[4] = "\r\n\r\n";
int h = 0; int i = 0;
char *r = recv_buf;
while (recv(c, r, 1, 0) != 0)
{

if (h == 4) break;

if (*r == el[h]) {
h++;
}
r++;
i++;

if (h == 4) break;
}

recv_buf[i] = '\0';

printf("%s\n", recv_buf);


if ( strncmp(recv_buf, "GET ", 4) == 0) {
printf("check get\n");
buf = recv_buf+4;
printf("%s\n", buf);
get();
}

}
return(0);

}

这不是 SSCCE。所有与设置套接字和从套接字读取相关的代码都应该与手头的问题相切。

精简代码——第 2 阶段

减少过程包括消除不必要的。
#include <stdio.h>
#include <string.h>

char *buf;

static void get(void)
{
printf("in get method\n");
char fileNameBuf[20];
int i = 0;
printf("%s\n", buf);
char *s = buf;

if (*s == '/')
{
printf("buf==/\n");
s++;
while (*s != ' ')
{
fileNameBuf[i] = *s;
s++;
i++;
printf("%d\n", i);
}
fileNameBuf[i]='\0';
printf("<<%s>>\n", fileNameBuf);
}
else
{
printf("!= '/'\n");
}
}

int main(void)
{
char recv_buf[50];
strcpy(recv_buf, "GET /index.html HTTP/1.1\r\n\r\n");

printf("<<%s>>\n", recv_buf);

if (strncmp(recv_buf, "GET ", 4) == 0)
{
printf("check get\n");
buf = recv_buf+4;
printf("%s\n", buf);
get();
}
return(0);
}

这也可以干净地编译;不幸的是,它也为我成功运行(GCC 4.8.1,Mac OS X 10.8.4):
<<GET /index.html HTTP/1.1

>>
check get
/index.html HTTP/1.1


in get method
/index.html HTTP/1.1


buf==/
1
2
3
4
5
6
7
8
9
10
<<index.html>>

有时会发生这种情况;你清理的太狠了。所以,你必须回到前面的代码,更慢地删除东西。

裁员——第三阶段

让我们从第 1 阶段获取完整代码并在本地运行它。浏览器可以连接到 localhost:45678/index.html,输出为:
binded
Waiting for connection
got connected
GET /index.html HTTP/1.1
Host: localhost:45678

check get
/index.html HTTP/1.1
Host: localhost:45678

in get method
/index.html HTTP/1.1
Host: localhost:45678

buf==/
1
2
3
4
5
6
7
8
9
10
<<index.html>>

没有任何内容发送回等待的浏览器(它仍在等待,但很快就会超时)。代码循环回到下一个接受;目前尚不清楚它是否正确关闭了商店,但它并没有在第一个周期崩溃。

所以,这是一个有点徒劳的练习......你的代码似乎工作正常。它仍然应该改进——首先将这些全局变量中的每一个都变成 main() 中的局部变量,然后将 buf 传递给带有签名 get() 的修改后的 void get(char *buf)

您显示的代码真的会崩溃吗?如果是这样,调试器为什么会崩溃?

防弹——第四阶段

在确定 buf 指向的字符串实际上是 "/index.html\r\n\r\n" and not "/index.html HTTP/1.1\r\n\r\n"` 之后,很明显我没有确保代码不会读到结尾以 null 结尾的字符串,也不写超出缓冲区的末尾。然而,这正是 SSCCE 如此重要的原因,以及诊断打印如此重要的原因。如果问题包含正在扫描的实际字符串,则发现问题会简单得多。

这段代码更接近于防弹。在其他主要更改中,它尝试在单个 recv() 操作中读取请求,而不是逐字节读取请求。这使避免 recv() 溢出的责任。所有的全局变量都消失了; buf 作为参数传递给 get()get() 已被编写用于检测 EOS 和超长名称,以及处理名称直到第一个空格。它仍然具有文件名中每个字符的调试代码。 main() 中的代码已被修饰,以发送回一个有效 HTTP(或足够有效的 HTTP)的响应,其中包含每次处理时都会更改的一些 HTML。看到浏览器发出的请求很有趣。还有一个错误报告函数,它写入标准错误,采用格式字符串和参数,与 printf() 等一样,还为系统错误添加正确的错误号和消息,然后以失败状态退出。这使得错误报告不那么痛苦;对于每个错误,一行调用就足够了,而不是 3 或 4 行(取决于您选择的格式)。错误也可以比 perror() 更具表现力。
#include <ctype.h>
#include <errno.h>
#include <netinet/in.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/socket.h>
#include <unistd.h>

static void err_exit(const char *fmt, ...);

static
void get(char *buf)
{
printf("in get method\n");
char fileNameBuf[256];
size_t i = 0;
printf("%s\n", buf);
char *s = buf;

if (*s == '/')
{
printf("buf==/\n");
s++;
while (*s != '\0' && *s != ' ' && i < sizeof(fileNameBuf))
{
printf("i = %3d: c = %3d = 0x%.2X = '%c'\n",
(int)i, *s, *s & 0xFF, isprint(*s) ? *s : '.');
fileNameBuf[i++] = *s++;
}
fileNameBuf[i]='\0';
printf("<<%s>>\n", fileNameBuf);
}
else
{
printf("!= '/'\n");
}
}

int main(void)
{
char *buf;
int fd;
int s;
int port = 45678;
struct sockaddr_in server, client;
int clientlen = sizeof(client);
int msgnum = 314159;

bzero(&server, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(port);

s = socket(AF_INET, SOCK_STREAM, 0);
if (!s)
err_exit("socket()\n");
if (bind(s, (struct sockaddr *) &server, sizeof(server)) < 0)
err_exit("bind()\n");
printf("bound to address\n");
if (listen(s, SOMAXCONN) < 0)
err_exit("listen()\n");
printf("Waiting for connection\n");

while ((fd = accept(s, (struct sockaddr *) &client, (socklen_t *) &clientlen)) > 0)
{
printf("got connection\n");
char recv_buf[4096];
char el[5] = "\r\n\r\n";
ssize_t length;
/* Read message in one go; leave space for a null at the end */
if ((length = recv(fd, recv_buf, sizeof(recv_buf)-1, 0)) > 0)
{
recv_buf[length] = '\0';
if (strstr(recv_buf, el) == 0)
err_exit("Incomplete message (%d bytes and no CRLF, CRLF pair)\n", length);
printf("%d: <<%s>>\n", (int)length, recv_buf);

if (strncmp(recv_buf, "GET ", 4) == 0)
{
printf("check get\n");
buf = recv_buf + 4;
printf("<<%s>>\n", buf);
get(buf);
char message[256];
char format1[] =
"<html><head><title>Hello World!</title></head>"
"<body><h1>This is no fun at all (%d).</h1></body></html>\r\n\r\n";
int msg_len = snprintf(message, sizeof(message), format1, msgnum++);
char format2[] =
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n"
"Content-Length: %d\r\n"
"Content-Encoding: UTF-8\r\n\r\n%s";
char response[1024];
size_t nbytes = snprintf(response, sizeof(response), format2,
msg_len, message);
write(fd, response, nbytes);
}
}
close(fd);
}
return(0);
}

static void err_exit(const char *fmt, ...)
{
int errnum = errno;
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
fprintf(stderr, "%d: %s\n", errnum, strerror(errnum));
exit(1);
}

关于C 指针段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18798192/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com