CodeEval 挑战:输入文件中的反转字符串

Posted

技术标签:

【中文标题】CodeEval 挑战:输入文件中的反转字符串【英文标题】:CodeEval Challenge: Reverse strings in input file 【发布时间】:2015-11-12 07:25:13 【问题描述】:

我决定在明年参加正式课程之前开始学习 C++,我已经从 CodeEval 和 Project Euler 的一些简单挑战开始。在这一个中,您必须获取一个包含单词字符串的输入文件,并且您必须输出文件的行,并将单词反转。这样一个具有以下输入的文件

1:这是第一行

2:这是第二行

最终会变成

1:一行是This

2:两行是This

我编写了以下程序来做到这一点,除了没有正确反转字符串,而是完全反转单词之外,尽管编译没有错误或警告,但它还是出现了分段错误。我假设我错过了一些关于 C++ 中正确内存管理的内容,但我不确定它是什么。那么有人可以告诉我我在内存管理方面错过了什么吗?

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
int main(int argc, char** argv)

  std::string filename = argv[1]; //has to be argv[1], argv[0] is program name
  std::string output_string; //final output
  std::string line; //Current line of file
  std::ifstream read(filename.c_str());
  if(read.is_open())
    while(std::getline(read,line))
      std::string temp;
      std::istringstream iss;
      iss.str(line);
      while(iss >> temp) //iterates over every word
        output_string.insert(0,temp); //insert at the start to reverse
        output_string.insert(0," "); //insert spaces between new words
      
      output_string.erase(0,1); //Removes the space at the beginning
      output_string.insert(0,"\n"); //Next line
    
    output_string.erase(0,1); //Remove final unnecessary \n character
    read.close();
  
  else
    std::cout<<"Unable to open file\n";
  
  for(unsigned int i = output_string.length(); i>=0;i--)
    std::cout<<output_string[i];
  
  std::cout<<"\n";

【问题讨论】:

【参考方案1】:
for(unsigned int i = output_string.length(); i>=0;i--)
   std::cout<<output_string[i];

段错误发生在这里;您可能会收到带有一些附加标志的编译器警告。例如g++ 不会产生带有-Wall 的警告,但会产生两个带有-Wextra 的警告:一个是关于argc 没有被使用,另一个是关于这个循环永远不会终止。

这里的问题是双重的:正如长颈鹿船长所说,你的开始超出了你的弦的实际长度;但条件i &gt;= 0 也将始终为真,因为i 是无符号的。因此,一旦它达到 0,下一次递减将导致它回绕到可能的最高值,然后您肯定会获得越界内存访问。

报告的警告是:

reverse.cpp:31:49: warning: comparison of unsigned expression >= 0 is always true [-Wtype-limits]
   for(unsigned int i = output_string.length(); i>=0;i--)

正如长颈鹿船长所说,您正在反转整个文件,而不仅仅是每一行。因此,您可以只反转每一行并在完成该行后将其输出,而不是将整个输出存储起来以备后用。

为了避免任何警告并获得正确的输出,这是整个程序的最小改动。主要变化是将output_string 的所有用法移到读取循环中。

int main(int argc, char** argv)

    if (argc != 2)
    
            std::cerr << "Need a file to process!" << std::endl;
            return 1;
    
    std::string filename = argv[1]; //has to be argv[1], argv[0] is program name
    std::string line; //Current line of file
    std::ifstream read(filename.c_str());
    if(read.is_open())
            while(std::getline(read,line))
                    std::string output_string; //final output
                    std::string temp;
                    std::istringstream iss;
                    iss.str(line);
                    while(iss >> temp) //iterates over every word
                            output_string.insert(0,temp); //insert at the start to reverse
                            output_string.insert(0," "); //insert spaces between new words
                    
                    output_string.erase(0,1); //Removes the space at the beginning
                    std::cout << output_string << std::endl;
            
            read.close();
    
    else
            std::cout<<"Unable to open file\n";
    

【讨论】:

您好,感谢您的帮助。另一方面,我一直在使用 -Werror 进行编译,但你会推荐作为标准使用 -Wextra 和 -Wall 进行编译吗? @Thallazar 警告越多越好。 -Wextra 添加了一些-Wall 不包括的额外警告。 -Werror 将通常“只是”警告的内容转换为实际停止编译的错误,特别是在学习时可以很好地使用。也许-Wall -Wextra -Werror 可能是个好主意。【参考方案2】:

将最后一个for语句改为

std::cout << output_string;

您通过在输出字符串中的最后一个字符之后打印来开始输出。这摆脱了段错误。现在您正尝试反向打印反向输出。

现在您发现您应该只反转每一行,而不是整个文本。您可以通过在插入中为每一行添加一个起始索引而不是 0 来轻松做到这一点。

所以不是

output_string.insert(0,temp); //insert at the start to reverse

你可以的

output_string.insert(start_of_line, temp); //insert at the start to reverse

【讨论】:

嗯,确实修复了段错误,但如果我的索引超出范围,为什么它会打印任何内容? 我试的时候没有打印出来。也许你的时钟设置为星期一,段错误处理程序有点慢。 奇怪,在我的它执行字符串的反转,打印它然后最后一行是一个段错误。

以上是关于CodeEval 挑战:输入文件中的反转字符串的主要内容,如果未能解决你的问题,请参考以下文章

Leetcode练习(Python):第345题:反转字符串中的元音字母:编写一个函数,以字符串作为输入,反转该字符串中的元音字母。

Leetcode练习(Python):第345题:反转字符串中的元音字母:编写一个函数,以字符串作为输入,反转该字符串中的元音字母。

如何从 Swift 中的输入音频文件生成相位反转音频文件?

LeetCode 344. 反转字符串

LeetCode:反转字符串中的元音字母345

345. 反转字符串中的元音字母