了解C中的字符串赋值

时间:2012-02-09 02:27:24

标签: c string char return strcat

好的,我已经在SO和其他很多地方阅读了大量的答案,但我似乎无法掌握这个简单的功能。请原谅我这么简单我8年多来没有做过c / c ++代码而且我非常想重新学习,所以请耐心等待......

我尝试了许多不同的方法,通过将值转换为直接返回它来为函数参数指定一个字符串,但似乎没有什么工作可做。我在编译期间也没有错误,但我确实在运行时获得了段错误。我非常想找出为什么以下函数不起作用...我只是不明白为什么else返回正常类型char * content,但是strcat(content,line);才不是。即使strcat的手册页显示strcat的定义应该是(char * DEST,const char * SRC)。正如我目前所理解的那样,试图在while中的行变量上对一个const char进行强制转换只会向指针返回一个整数。所以我很难过,希望有那些有时间的人接受教育!

char * getPage(char *filename) {
    FILE *pFile;
    char *content;
    pFile = fopen(filename, "r");
    if (pFile != NULL) {
        syslog(LOG_INFO,"Reading from:%s",filename);
        char line [256];
        while (fgets(line, sizeof line, pFile) != NULL) {
            syslog(LOG_INFO,">>>>>>>Fail Here<<<<<<<");
            strcat(content, line);
        }
        fclose(pFile);
    } else {
        content = "<!DOCTYPE html><html lang=\"en-US\"><head><title>Test</title></head><body><h1>Does Work</h1></body></html>";
        syslog(LOG_INFO,"Reading from:%s failed, serving static response",filename);
    }
    return content;
}

非常感谢这篇文章中的所有精彩答案。我会在讨论中给每个人一个勾选标记但不幸的是我不能......

6 个答案:

答案 0 :(得分:2)

您需要为content分配内存。对于整个文件,它必须足够大,就像你一样。您可以预先分配一个巨大的缓冲区并希望获得最佳,或者分配一个较小的缓冲区并根据需要重新分配它。

更好的是重新安排代码以避免同时存储整个文件,尽管如果您的调用者需要整个网页作为字符串,那可能很难。

另请注意,您需要从两个代码路径返回相同类型的内存。有时您不能返回静态字符串,有时也不能返回堆分配的字符串。这可以保证调用头痛和/或内存泄漏。因此,如果要将文件内容复制到内存块中,还应将静态字符串复制到相同类型的块中。

答案 1 :(得分:2)

这很简单,但如果您习惯使用更高级别的语言,则会非常惊讶。 C不为您管理内存 C实际上没有字符串content变量是一个指针,而不是一个字符串。在调用strcat之前,您必须手动分配字符串所需的空间。编写此代码的正确方法是这样的:

FILE *fp = fopen(filename, "r");
if (!fp) {
    syslog(LOG_INFO, "failed to open %s: %s", filename, strerror(errno));
    return xstrdup("<!DOCTYPE html><html lang=\"en-US\"><head><title>Test</title>"
                  "</head><body><h1>Does Work</h1></body></html>");
} else {
    size_t capacity = 4096, offset = 0, n;
    char *content = xmalloc(capacity);
    size_t n;
    while ((n = fread(content + offset, 1, capacity - offset, fp)) > 0) {
        offset += n;
        if (offset == capacity) {
            capacity *= 2;
            content = xrealloc(content, capacity);
        }
    }
    if (n < 0)
        syslog(LOG_INFO, "read error from %s: %s", filename, strerror(errno));
    content[offset] = '\0';
    fclose(fp);
    return content;
}

注意:

  1. I / O失败触发的错误消息应始终包含strerror(errno)
  2. xmallocxreallocxstrdup是围绕其对应方的包装函数,没有前导x;他们使程序崩溃而不是返回NULL。这种情况几乎总是比在每一个可能发生的地方手动从内存中恢复而悲伤。
  3. 我在失败打开的情况下返回xstrdup("...")而不是"...",以便来电者可以随时拨打free(content)。在字符串文字上调用free会使程序崩溃。
  4. 天哪,那是很多工作,不是吗?这就是人们倾向于使用更高级语言编写Web应用程序的原因。 ; - )

答案 2 :(得分:1)

content只是指向字符串而不是实际字符串的指针 - 它为字符串保留了0字节的空间。您需要分配足够大的内存以容纳小时字符串。请注意,在您必须释放它之后

char *content=malloc(256);

你的代码应该没问题 - 哦,我建议使用strncat

第二次内容分配工作正常 - 因为您将指针设置为指向const字符串。如果您将内容更改为malloc的内存区域 - 那么您还需要将固定字符串格式化为内容。

理想情况下,如果您可以使用C ++ std :: string。

答案 3 :(得分:1)

content是一个狂野的指针;变量包含垃圾,所以它指向左侧的字段。使用strcat将数据复制到数据库时,数据将转移到某个随机位置(可能是坏位置)。解决这个问题的方法是让content点好点。因为你希望它比你的函数调用更长,所以它需要在函数的调用堆栈之外的某个地方分配。您需要使用malloc()在堆上分配一些空间。然后调用者将拥有内存,并应在不再需要时调用free()删除它。

您还需要更改直接分配给else的{​​{1}}部分,以使用content,以便strcpy始终有效。你不能释放你没有分配的东西!

通过所有这些代码,请确保您记住使用free()分配了多少空间,并且不要写入比空间更多的数据,否则会导致更多崩溃。

答案 4 :(得分:1)

char *foo只是指向某个内存块的指针,该内存中包含构成字符串的字符。因此,您无法使用strcat,因为您没有要复制的内存。在if语句中,您在堆栈上使用char line[256]分配本地内存来保存该行,但由于该函数的本地内存将在它返回后消失,因此您不能{{1} }。

所以你真正想要的是分配一些持久性内存,例如:使用return line;strdup,以便您可以从函数中返回它。请注意,您不能混合常量和已分配的内存(因为您的函数的用户必须malloc内存 - 只有当它不是常量时才可以。)

所以你可以使用这样的东西:

free

这不是最有效的方法(因为char * getPage(const char *filename) { FILE *pFile; char *content; pFile = fopen(filename, "r"); if (pFile != NULL) { syslog(LOG_INFO,"Reading from:%s",filename); /* check the size and allocate memory */ fseek(pFile, 0, SEEK_END); if (!(content = malloc(ftell(pfile) + 1))) { /* out of memory ... */ } rewind(pFile); /* set the content to be empty */ *content = 0; char line [256]; while (fgets(line, sizeof line, pFile) != NULL) { syslog(LOG_INFO,">>>>>>>Fail Here<<<<<<<"); strcat(content, line); } fclose(pFile); } else { content = strdup("<!DOCTYPE html><html lang=\"en-US\"><head><title>Test</title></head><body><h1>Does Work</h1></body></html>"); syslog(LOG_INFO,"Reading from:%s failed, serving static response",filename); } return content; } 必须每次都找到结束),但对代码的修改最少。

答案 5 :(得分:1)

早先的回答提出了解决方案:

char content[256];

当执行content时,此缓冲区的大小不足以容纳除{x>和指针return content;之外的任何内容都超出范围。 (你的早期行content = "static..";没问题,因为字符串放在.rodata data segment中,并且它的指针总是指向相同的数据,在程序的整个生命周期内。)

如果您使用contentmalloc(3)分配内存,则可以“增加”realloc(3)所需的空间,但这会引发可能出现的错误 - 无论您递交什么当数据完成后,内存分配后必须清理指针(否则你会泄漏内存),并且它不能简单地调用free(3)因为content指针可能要静态分配内存。

所以,你有两个简单的选择:

  • 每次需要时使用strdup(3) 复制静态字符串,并使用content = malloc(size);作为非静态路径
  • 让你的来电者负责提供记忆;每次调用都需要提供足够的内存来处理文件静态字符串的内容。

我可能更喜欢第一种方法,只是因为在调用之前无法知道第二种方法所需的大小。