我需要一些帮助,因为它让我的C程序感到困惑
我有2个字符串(基础和路径)
BASE: /home/steve/cps730
PATH: /page2.html
这就是printf在我调用sprintf将它们的内容连接在一起之前的读取方式。这是代码块
int memory_alloc = strlen(filepath)+1;
memory_alloc += strlen(BASE_DIR)+1;
printf("\n\nAlloc: %d",memory_alloc);
char *input = (char*)malloc(memory_alloc+9000);
printf("\n\nBASE: %s\nPATH: %s\n\n",BASE_DIR,filepath);
sprintf(input, "%s%s",BASE_DIR,filepath); // :(
printf("\n\nPATH: %s\n\n",input);
现在,您能解释一下最终的printf语句如何返回
PATH: e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/stev
因为它根本不理解它。
**我在malloc语句中添加了9000以防止程序崩溃(因为字符串的大小明显大于31个字节。
完整输出
Alloc: 31
BASE: /home/steve/cps730
PATH: /page2.html
PATH: /home/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/stev
Sending:
HTTP/1.0 404 Not Found
Date: Sat, 12 Sep 2009 19:01:53 GMT
Connection: close
编辑..................所有使用这些变量的代码
const char *BASE_DIR = "/home/steve/cps730";
char* handleHeader(char *header){
//Method given by browser (will only take GET, POST, and HEAD)
char *method;
method = (char*)malloc(strlen(header)+1);
strcpy(method,header);
method = strtok(method," ");
if(!strcmp(method,"GET")){
char *path = strtok(NULL," ");
if(!strcmp(path,"/")){
path = (char*)malloc(strlen(BASE_DIR)+1+12);
strcpy(path,"/index.html");
}
free(method);
return readPage(path);
}
else if(!strcmp(method,"POST")){
}
else if(!strcmp(method,"HEAD")){
}
else{
strcat(contents,"HTTP/1.1 501 Not Implemented\n");
strcat(contents, "Date: Sat, 12 Sep 2009 19:01:53 GMT\n");
strcat(contents, "Connection: close\n\n");
}
free(method);
}
//Return the contents of an HTML file
char* readPage(char* filepath){
int memory_alloc = strlen(filepath)+1;
memory_alloc += strlen(BASE_DIR)+1;
printf("\n\nAlloc: %d",memory_alloc);
char *input = (char*)malloc(memory_alloc+9000);
printf("\n\nBASE: %s\nPATH: %s\n\n",BASE_DIR,filepath);
sprintf(input, "%s%s\0",BASE_DIR,filepath);
printf("\n\nPATH: %s\n\n",input);
FILE *file;
file = fopen(input, "r");
char temp[255];
strcat(contents,"");
if(file){
strcat(contents, "HTTP/1.1 200 OK\n");
strcat(contents, "Date: Sat, 12 Sep 2009 19:01:53 GMT\n");
strcat(contents, "Content-Type: text/html; charset=utf-8\n");
strcat(contents, "Connection: close\n\n");
//Read the requested file line by line
while(fgets(temp, 255, file)!=NULL) {
strcat(contents, temp);
}
}
else{
strcat(contents, "HTTP/1.0 404 Not Found\n");
strcat(contents, "Date: Sat, 12 Sep 2009 19:01:53 GMT\n");
strcat(contents, "Connection: close\n\n");
}
return contents;
}
答案 0 :(得分:6)
使用无效指针readPage
调用path
- 它指向先前使用method
指针分配的内存,该指针在调用readPage
之前被释放。下一个malloc
可以重用这个内存然后发生任何事情......
答案 1 :(得分:4)
嗯,显然这不可能发生: - )
我的猜测是你的堆已经被严重破坏了。
我会查看filepath,input和base使用的实际指针值。我想知道你是否会发现输入非常接近文件路径?
我还会看看最初如何创建filepath,base等,你可以在那里运行缓冲区吗?
答案 2 :(得分:1)
Aaah - 在我们试图解决问题的过程中,随着问题的变化,追逐的快感!
目前的代码如下:
const char *BASE_DIR = "/home/steve/cps730";
//Handles the header sent by the browser
char* handleHeader(char *header){
//Method given by browser (will only take GET, POST, and HEAD)
char *method;
method = (char*)malloc(strlen(header)+1);
strcpy(method,header);
method = strtok(method," ");
if(!strcmp(method,"GET")){
char *path = strtok(NULL," ");
if(!strcmp(path,"/")){
path = (char*)malloc(strlen(BASE_DIR)+1+12);
strcpy(path,"/index.html");
}
free(method);
return readPage(path);
}
...
问题:如果这是在Web服务器上运行,使用线程不安全函数strtok()
是否安全?我会假设“是的,这是安全的”,尽管我并不完全相信。你打印过header
字符串了吗?你打印过path
的价值了吗?你真的打算泄漏分配的path
吗?您是否意识到malloc() + strcpy()
序列未将BASE_DIR
复制到path
?
代码的原始版本以:
结束 printf("\n\nPATH: %s\n\n", filepath);
因此,原始建议的部分答案:
您格式化为
input
;你是从filepath
打印的吗?
filepath
指向已释放内存的几率是多少?当您分配内存时,您可能会在filepath
过去指向的准随机区域发生任何事情。另一种可能性是filepath
是指向已返回的函数中的局部变量的指针 - 因此它指向堆栈中随机的某个地方,正被其他代码重用,例如sprintf()
。 / p>
我还在评论中提到,您可能需要确保声明malloc()
并检查其返回值。 '(char *)
'强制转换在C语言中不是强制性的(它在C ++中),如果代码严格为C而不是C和C ++中的双语,许多人不喜欢包含强制转换。
此代码适用于我:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
const char *BASE_DIR = "/home/steve/cps730";
const char *filepath = "/page2.html";
int memory_alloc = strlen(filepath) + 1;
memory_alloc += strlen(BASE_DIR) + 1;
printf("\n\nAlloc: %d", memory_alloc);
char *input = (char*)malloc(memory_alloc + 9000);
printf("\n\nBASE: %s\nPATH: %s\n\n", BASE_DIR, filepath);
sprintf(input, "%s%s", BASE_DIR, filepath);
printf("\n\nPATH: %s\n\n", filepath);
printf("\n\nPATH: %s\n\n", input);
return(0);
}
它产生无关的空行加上:
Alloc: 31
BASE: /home/steve/cps730
PATH: /page2.html
PATH: /page2.html
PATH: /home/steve/cps730/page2.html
答案 3 :(得分:1)
该计划没有明显的错误。 ( 更新: 嗯,现在有一些明显的东西。第一个小时只发布了几行,而且没有严重的错误。 )你将不得不发布更多。以下是一些想法:
malloc(3)
返回void *
,因此无需投出它。如果您收到警告,则很可能意味着您未包含<stdlib.h>
。如果你不是,你应该。 (例如,在64位系统上,不是原型malloc(3)
可能非常严重。某些64位环境并不真正支持K&amp; R C.: - )gcc
,您可以使用-Wall
启用大部分内容。malloc(3)
的错误返回值。答案 4 :(得分:1)
试试这段代码:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
const char* BASE_DIR = "/home/steve/cps730";
const char* filepath = "/page2.html";
int memory_alloc = strlen(filepath);
memory_alloc += strlen(BASE_DIR)+1;
printf("\n\nAlloc: %d",memory_alloc);
char *input = (char*)malloc(memory_alloc);
printf("\n\nBASE: %s\nPATH: %s\n\n",BASE_DIR,filepath);
sprintf(input, "%s%s",BASE_DIR,filepath); // :(
printf("\n\nPATH: %s\n\n",input);
return 0;
}
如果这没有问题,那么代码中的其他地方一定有问题。这就是未定义的行为有时可能表现出来的方式(搞乱不相关的代码如何工作)。
(顺便说一下,我没有为两个strlen调用添加+1,因为连接的字符串仍然只有一个空终止符。)
答案 5 :(得分:1)
由于BASE_DIR
值重复,BASE_DIR
或filepath
可能与input
内存重叠。
确保BASE_DIR
和filepath
确实分配了内存。
首先尝试在致电BASE_DIR
之前制作filepath
和sprintf
的本地副本。
答案 6 :(得分:1)
找出正在发生的事情的最简单方法是在调试器中跟踪执行(可能会删除跟踪汇编代码)。
对可能发生的事情进行一些猜测:
malloc()
调用后转储2个组件字符串时似乎不太可能)stdio.h
)并且编译器正在为printf
/ {{1生成错误的调用/堆栈清理序列调用。如果是这种情况,我希望你能看到一些编译时警告 - 你应该注意的。您使用的是什么编译器/目标?
答案 7 :(得分:1)
为了正确执行此操作,我将代码更改为:
/* CHANGED: allocate additional space for "index.html" */
method = (char*)malloc(strlen(header)+1+10);
strcpy(method,header);
method = strtok(method," ");
if(!strcmp(method,"GET")){
char *path = strtok(NULL," ");
if(!strcmp(path,"/")){
/* CHANGED: don't allocate new memory, use previously allocated */
strcpy(path,"/index.html");
}
/* CHANGED: call function first and free memory _after_ the call */
char *result = readPage(path);
free(method);
return result;
}