首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将部分字符串替换为n个大小的字符串,改为m大小字符串。

将部分字符串替换为n个大小的字符串,改为m大小字符串。
EN

Code Review用户
提问于 2019-09-16 14:44:26
回答 2查看 86关注 0票数 4

在为更大的项目进行文件路径操作之前,我想更好地理解内存和指针。这是简单的替换字符串测试函数的一部分,我需要将其重写为struct来调用。我使用作用域来测试内存泄漏和更改,我在Windows7、CygWin和notepad++上工作。

由于以下原因,我使用std::size_t作为大小表示:

一个大小不能由std::size_t表示的类型是优先选择提到的"std::size_t通常用于数组索引和循环计数“的错误形式。

我决定选择c样式的空终止字符数组,因为通过main(int argc, char **argv)传递的参数是空终止字符,系统调用接受最好的参数。对于我自己需要的代码部分来说,这似乎是有益的,而不是依赖于另一个库,而且跟踪用c_str()转换的代码和没有转换的代码是很累人的。

如前所述,此函数是项目的一部分,用于操作、更改和创建文件的完整或相对路径。字符数组帮助我使用stat ( CygWin附带的)能够自动测试路径、目录或文件是否是不可访问的。我可以使用std::string,但这是一个额外的头,我计划对文件路径进行认真的扩展,以包括一些自定义行为--这与此函数无关。

代码语言:javascript
复制
#include <iostream>

size_t get_str_size(const char* temp){
            size_t s=0;
            while( temp[s] != '\0' )s++;
            return s;
        }

int main(int argc, char **argv){ 

    const char * temp = "sublime/subliminal/sfit.exe"; // example string
    std::cout << &temp << "\t" << temp << std::endl; // prints out address and value
    { // wild scope to help me navigate and debug
        const char* shitcake = "sfitcake"; // string to be put in place of sfit
        size_t ldelim = 0;  // / last delimiter 
        size_t edelim = 0;  // . end delimiter
        size_t original_size = get_str_size(temp);

        // finding the necessary indexes of charachters  
        for( int i =0 ; i <= original_size; i++ ){
                if( temp[i]=='/' ){ldelim=i;}
                if( temp[i]=='.' ){edelim=i;}
            }

        // calculating size that influences the char array
        size_t old_size = edelim - ldelim -1;  // current char array size(-1 to remove last delimiter)
        size_t new_size = get_str_size(shitcake); // new char array size

        // char array duplication , since original string is const
        char* tempcopy = new char[original_size]; // holds the copy of the temp
        for( int i =0 ; i < original_size; i++ ){ tempcopy[i] = temp[i]; }

        // value to be constructed
        char *new_version = new char[ original_size + (new_size-old_size) ];

        // filling the part before replacement happen       
        for( int i =0 ; i <=ldelim; i++ )               { new_version[i] = tempcopy[i]; }
        // filling replaced char array
        for( int i =0 ; i <= new_size;i++ )             { new_version[i+1+ldelim] = shitcake[i]; }
        // the rest of original string
        for( int i =edelim ; i < original_size;i++ )    { new_version[i+old_size] = tempcopy[i];}

        //conversion back to const char* with expanded size and new value
        temp = (const char*)new_version;

        //deleting pointers
        delete tempcopy;
        delete new_version;
    }
    std::cout << &temp << "\t" << temp << std::endl;

    return 0;
}

我得到的输出是:

代码语言:javascript
复制
0xffffcbb8  sublime/subliminal/sfit.exe
0xffffcbb8  sublime/subliminal/sfitcake.exe

这意味着它可以工作,但我害怕指针不会改变内存地址,即使大小和值发生了变化。

对守则的主要关切和愿望:

  • 消除悬空指针的机会和内存问题
  • 快速可读的代码
EN

回答 2

Code Review用户

回答已采纳

发布于 2019-09-16 16:46:08

size_t的作用域没有定义。因为描述意味着您需要std::size_t,所以您需要

代码语言:javascript
复制
#include <cstddef>
using std::size_t

但我建议您只在使用std::size_t的地方完整地编写它--这对读者来说要清楚得多。

size_t get_str_size(const char* temp){ size_t s=0;while( tempS != '\0‘)s++;返回s;}

您只是无缘无故地重新实现了std::strlen()

char\* tempcopy = new char[original\_size]; // holds the copy of the temp char \*new\_version = new char[ original\_size + (new\_size-old\_size) ]; delete tempcopy; delete new\_version;

使用new[]分配的内存必须使用delete[] (而不是delete)释放。瓦兰会帮你抓到这个错误的。

如果第一次分配成功,而第二次分配失败,则会出现内存泄漏,因为如果抛出一个delete[] tempcopy,则不存在std::bad_alloc

我们在这里引用已删除的内存:

temp = (const char\*)new\_version; delete new\_version; std::cout << &temp << "\t" << temp << std::endl;

这是一种未定义的行为(而且也被Val差尔捕获--我确实建议您在Memcheck或您选择的任何类似工具下运行代码)。

int main(int argc,char **argv){

因为我们从不使用参数,所以没有必要给它们命名;而且,我们可以在没有参数的情况下使用main()的签名:

代码语言:javascript
复制
int main()

for( int i =0 ; i <= original\_size; i++ ){

避免将有符号值(如i)与无符号值(如original_size)进行比较。我们可能也希望i的范围匹配,所以这两种类型都使用相同的类型。

该代码对一系列输入不太健壮。特别是,如果edelim小于ldelim,则在计算old_size时会得到(无符号)整数溢出,并给出不正确的结果。

总的来说,代码看起来非常类似于C代码--而糟糕的C代码(例如,一次复制一个字符,而不是使用memcpy())。C++实现(使用std::string)要短得多,而且更自然。

票数 6
EN

Code Review用户

发布于 2019-09-18 13:40:08

您标记了这个C++,但是您的代码看起来一点也不像C++。它看起来像C,mallocnew代替,printfstd::cout代替。您可以使用C++标准库工具来简化代码。在这种情况下,您可以使用std::string简化代码:

代码语言:javascript
复制
#include <string>
#include <string_view>

std::string replace(std::string_view string, std::string_view pattern, std::string_view replace)
{
    std::string result;

    while (true) {
        auto index = string.find(pattern);
        result.append(string, 0, index);
        if (index == string.npos)
            break;
        string.remove_prefix(index + pattern.size());
        result += replace;
    }
    return result;
}

(现场演示)

票数 0
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/229117

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档