c_str() 输入一个字符串 - 除第一行之外的所有其他行都将丢失

Posted

技术标签:

【中文标题】c_str() 输入一个字符串 - 除第一行之外的所有其他行都将丢失【英文标题】:c_str() ing a string - all other lines than the first line are lost 【发布时间】:2013-11-05 08:48:43 【问题描述】:

我有一个字符串流,其中包含多行文本。

例如,

f.html                            Sat Oct 19 22:59:47 2013         23675
folder                            Mon Nov  4 19:36:14 2013         4096
readdirpractice.cpp               Tue Nov  5 03:00:10 2013         1203
server.cpp                        Mon Nov  4 21:22:27 2013         11369
photo.jpg                         Wed Oct 23 01:45:04 2013         4360
qq                                Sun Nov  3 01:54:36 2013         66031
server.cpp~                       Mon Nov  4 21:22:25 2013         11368
myhttp.cpp                        Sun Nov  3 01:43:09 2013         1816
getoptpractice.cpp~               Sun Nov  3 01:15:25 2013         1324

这就是字符串流通常的样子。

当我把这个stringstream转换成string时,信息是一样的。

但是,当我将其转换为 C 字符串时,它只占用了第一行,其他所有行都丢失了。

只有

f.html                            Sat Oct 19 22:59:47 2013         23675

转换后。

为什么会这样,我该如何解决?

我附上了我的部分代码。

if(is_dir) 
    char dirname[1024];
    strncpy(dirname, requests[1].c_str(), sizeof(dirname));
    dirname[sizeof(dirname)-1] = 0;

    DIR           *d;
    struct dirent *dir;
    d = opendir(dirname);
    stringstream ss;
    if (d) 
        while ((dir = readdir(d)) != NULL) 
            char* file = dir->d_name;
            if(file[0] != '.') 
                struct stat sb;

                if (stat(file, &sb) == -1) 
                    cerr << "stat error" << endl;
                    exit(EXIT_FAILURE);
                

                char* lm = ctime(&sb.st_mtime);
                string lastmod(lm);
                lastmod.at(lastmod.size()-1) = '\0';
                string spacing = "                                  ";
                ss << file << spacing.substr(0, spacing.size() - strlen(file)) << lastmod << spacing.substr(0, spacing.size() - lastmod.size()) << sb.st_size << '\n';
            
        
        closedir(d);
    
    //cout << ss.str() << endl; // for testing
    char msg2[10000];
    strncpy(msg2, ss.str().c_str(), sizeof(msg2));
    msg2[sizeof(msg2)-1] = 0;
    msg = msg2;

【问题讨论】:

@kfsone stream &lt;&lt; std::endl 等价于stream &lt;&lt; '\n' &lt;&lt; std::flush。为什么 OP 应该使用std::endl 什么是“味精”? “msg2”的目的是什么? msg 是 std::string 吗?如果是这样,摆脱 msg2 并使用msg.assign(ss.str().c_str(), std::min(ss.str().size(), 10000); endl 执行通常不需要的刷新。在文件上使用它会强制执行系统(内核)调用。这不是一个好习惯。 msg 在if(is_dir) 之上定义为char *msg。它是返回值。 与其分配动态内存,不如使用封装动态字符串内存的类,比如std::string。使您的函数采用std::string&amp; msg,以便调用者必须提供std::string,然后您的函数所要做的就是填充它。 (请参阅我的答案中的示例) 【参考方案1】:

std::string 可能嵌入了 '\0' (NUL) 字符,当 char 序列被解释为 C 字符串时,这些字符会提前终止它。

尝试使用 std::remove 擦除 NUL 字节。

编辑 - 这可能是您的问题:

             lastmod.at(lastmod.size()-1) = '\0';

这只是自找麻烦。 std::string 忠实地存储了您的 NUL 字节并将其复制到输出中。

【讨论】:

+1 和 @user2418202 注意我在上面的 general-cmets 中的评论。如果您认为通过修复它“有效”,但您在函数中返回了指向本地缓冲区的指针,请再想一想。 谢谢@WhozCraig,我会这样做的。 但我想不出我将如何按照你说的去做。我以后肯定会花一些时间,但听起来没那么简单 @user2418202 是的。它只是多一点工作。如果您不熟悉如何操作,可能看起来很多,但就像所有事情一样,练习会变得更容易。【参考方案2】:

这些行看起来很可疑:

string lastmod(lm);
lastmod.at(lastmod.size()-1) = '\0';

将空字符插入字符串类实例的中间可能会产生意外行为(例如打印时字符串过早终止)。

我认为你不需要这样做。只需尝试删除 lastmod.at 行。

【讨论】:

【参考方案3】:

根据 cmets,您指出“msg”是返回值。

char msg2[10000];
strncpy(msg2, ss.str().c_str(), sizeof(msg2));
msg2[sizeof(msg2)-1] = 0;
msg = msg2;

"msg2" 被创建为局部变量,即在堆栈上。然后,您将字符串流复制到此堆栈区域,获取字符串的地址(在堆栈上),然后离开您的函数,此时堆栈的该区域被释放并由应用程序的其他部分使用。

您要么需要在堆上为字符串分配内存,要么需要从调用函数传入存储空间。

由于您已经在进行字符串操作,因此使用 std::string 来封装管理开销将是最合乎逻辑的。将标准字符串的引用作为参数:

void getDirListing(std::string& msg) 

然后调用

std::string dirListing = "";
getDirListing(dirListing);

【讨论】:

以上是关于c_str() 输入一个字符串 - 除第一行之外的所有其他行都将丢失的主要内容,如果未能解决你的问题,请参考以下文章

jQuery删除除第一行之外的所有表行

MySql:更新除第一行之外的所有内容[重复]

HTML表格在悬停时突出显示除第一行(标题)之外的行

使用 Oracle REGEXP_REPLACE 从字符串中删除除第一个之外的所有点

为啥我仍然可以在字符串范围之外访问 std::string::c_str() 返回的 char 指针? [复制]

删除 VIM 中除第一列之外的所有内容