我需要一些帮助,因为它让我在我的 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;
}
有帮助吗?

解决方案

使用无效指针readPage调用path - 它指向先前使用method指针分配的内存,该指针在调用malloc之前被释放。下一个<=>可以重复使用这个内存然后发生任何事情......

其他提示

嗯,显然这不可能发生: - )

我的猜测是你的堆已经被严重破坏了。

我会查看filepath,input和base使用的实际指针值。我想知道你是否会发现输入非常接近文件路径?

我还会看看最初如何创建filepath,base等,你可以在那里运行缓冲区吗?

试试这段代码:

#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,因为连接的字符串仍然只有一个空终止符。)

由于BASE_DIR值重复,filepathinput可能与sprintf内存重叠。

确保<=>和<=>确实已经分配了内存。

首先尝试在调用<=>之前制作<=>和<=>的本地副本。

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的价值吗?你真的打算泄漏分配的malloc() + strcpy()吗?您是否意识到BASE_DIR序列没有将input复制到filepath


代码的原始版本以:

结束
 printf("\n\nPATH: %s\n\n", filepath);

因此,原始建议的部分答案:

  

格式化为sprintf();你从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

弄清楚发生了什么的最简单方法是跟踪调试器中的执行(可能会直接跟踪汇编代码)。

关于可能发生的情况的一些猜测:

  • 另一个线程的内存损坏(如果这很容易重复的话似乎不太可能)
  • 损坏的堆(似乎也不太可能,因为您在 malloc() 称呼)
  • 正如 Jonathan Leffler 在评论中提到的,您可能会丢失标题(也许 stdio.h)并且编译器正在生成不正确的调用/堆栈清理序列 printf/sprintf 来电。如果是这种情况,我希望您会看到一些编译时警告 - 您应该注意这些警告。

您使用什么编译器/目标?

为了正确执行此操作,我将代码更改为:

/* 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;
}

建议


该计划没有明显的错误。 ( 更新: 嗯,现在有一些明显的东西。第一个小时只发布了几行,而且没有严重的错误。 )你将不得不发布更多。以下是一些想法:

  1. malloc(3)返回void *所以不需要强制转换它。如果您收到警告,则很可能意味着您未包含<stdlib.h>。如果你不是,你应该。 (例如,在64位系统上,不进行原型设计gcc可能非常严重。某些64位环境并不真正支持K <!> amp; R C.: - )
  2. 说到警告,请确保你全力以赴。使用-Wall,您可以使用<=>来启用大部分内容。
  3. 您没有检查<=>的错误返回值。
  4. 使用内存调试器,例如电围栏。有很多选择,请参阅我的链接。
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top