我一直试图将正整数从一个数组中移动到另一个数组中,其值为数值 51 144 5 16 8 0 -2 14 6 -4 173 263 11 9345 -135 777
我的代码是
void pullfilename (string, string&);
void pullnegativenumbers (ofstream&, int, int[], int[]);
void pullpositivenumbers (ofstream&, int, int[], int[]);
int main()
{
ifstream input;
ofstream output;
string fname;
pullfilename("input", fname);
input.open(fname.c_str());
pullfilename("output", fname);
output.open(fname.c_str());
int n=0;
int list[50];
int positive[50];
input>>list[n];
while (input)
{
n++;
input>>list[n];
}
pullnegativenumbers(output, n, list, positive);
pullpositivenumbers(output, n, list, positive);
return 0;
}
void pullfilename(string filetype,string& fname)
{
cout<<"Enter name of"<<filetype<<"file"<<endl;
cin>>fname;
}
void pullnegativenumbers(ofstream& out, int n, int list[], int positive[])
{
int ncount=0;
int pcount=0;
int nsum=0;
int naverage=0;
int i;
for (i=0; i<n; i++)
{
if (list[i]<0)
{
ncount++;
nsum=nsum+list[i];
naverage=nsum/ncount;
out<<left<<setw(15)<<"Negative Values"<<endl;
out<<left<<setw(6)<<"Count:"<<right<<setw(10)<<ncount<<endl;
out<<left<<setw(4)<<"Sum:"<<right<<setw(10)<<nsum<<endl;
out<<left<<setw(8)<<"Average"<<right<<setw(10)<<naverage<<endl;
}
}
}
void pullpositivenumbers(ofstream& out, int n, int list[], int positive[])
{
int i;
for (i=0; i<n; i++)
if (n>=0)
{
list[i]=positive[i];
}
`out<<positive[i]<<endl;
}
它以我喜欢的方式将我的负数拉到一边,但正数组文件中的输出结果是-123908309 ???
答案 0 :(得分:2)
但我仍然不知道如何将其余的积极因素复制到 单独的数组,以便我以后再使用它们。
您有一系列值,并且您希望将满足特定条件的值放入数组中。这需要一个简单的循环,如果你使用特定的算法函数,即使这是不必要的。
首先,您的代码出错的地方在于您使用list
数组不仅可以获取原始值,还可以执行此操作:
void pullpositivenumbers(ofstream& out, int n, int list[], int positive[])
{
int i;
for (i=0; i<n; i++)
if (n>=0)
{
list[i]=positive[i]; // you are storing an uninitialized value in list[i]
}
out<<positive[i]<<endl;
}
这是完全错误的,因为你用positive
数组中的某些值覆盖了你读入的原始数组。
第二件事是错误的是positive
和list
必须使用不同的索引。您正在使用索引list
从i
进行阅读,但您需要positive
的单独索引变量。如果你有这个怎么办:
list -> -1, -2, -3, -4, 10
当你到达list[4]
时,你会到达10
。但是,您应该在positive[0]
而不是positive[4]
存储10,因为10之前的数字都是负数。
第三个错误是你的检查是肯定的。您应该比较list[i]
以查看它是否为负数,而不是n
:
if (n>=0)
应该是
if (list[i] >= 0)
所以代码的修复程序似乎就是这样:
void pullpositivenumbers(ofstream& out, int n, int list[], int positive[])
{
int i;
int j = 0;
for (i=0; i<n; i++)
if ( list[i] >= 0)
{
positive[j] = list[i];
++j;
}
}
现在,说完所有这些,你的整个逻辑可以被一些算法函数调用所取代,并且不需要引入任何循环来获取负数或正值。
#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>
using namespace std;
int main()
{
// your test values
int values[] = {51, 144, 5, 16, 8, 0, -2, 14, 6, -4, 173, 263, 11, 9345, -135, 777};
// partition negatives to left, positives to right of partition
auto it = std::stable_partition(begin(values), end(values), [] (int i) { return i < 0;});
// copy positives to vector
std::vector<int> positives;
copy_if(it, end(values), back_inserter(positives), [] (int i) { return i > 0;});
// sum negatives
// number of negatives is known, by getting the distance
// between the start of the array and where partition point is
size_t numNegatives = std::distance(begin(values), it);
// get the sum of those negative numbers
int sum = accumulate(begin(values), it, 0);
// get the average
double avg = 0;
if ( numNegatives > 0 )
avg = static_cast<double>(sum) / numNegatives;
// output results
cout << "Here are the negatives:\n";
copy(begin(values), it, ostream_iterator<int>(cout, " "));
cout << "\nSum: " << sum << "\n";
cout << "Avg: " << avg << "\n\n";
// Output the positive numbers
cout << "Here are the positive:\n";
copy(positives.begin(), positives.end(), ostream_iterator<int>(cout, " "));
}
请注意使用std::stable_partition
来更改顺序,以便排列负数和正数,使负数落在左侧,正数落在分区点的右侧(it
)。
此外,std::accumulate
用于累加底片的用法是使用上面的代码完成的。复制到输出也会使用std::copy
将输出流式传输到cout
。
正如您所看到的,没有任何手写循环来处理数据。相反,代码更具说明性(partition,accumulate,copy,copy_if)。
另外,我使用std::vector
来存储积极因素。这将确保我们在存储正数时不限于50个输入项,并且更容易擦除可能在向量中的任何0。如果您仍想坚持使用(不安全)positive
数组,那么这一行:
// copy positives to vector
std::vector<int> positives;
copy(it, end(values), back_inserter(positives));
将被替换为:
// copy positives to vector
int positives[50];
//...
// get number of positives
size_t numItems = std::distance(it, end(values));
// copy this number of items or 50 items, whichever is smaller, to the positives array
copy(it, it + std::min(50, numItems), positives));
请注意我们如何将项目数量限制为最多50项。
答案 1 :(得分:0)
这是根据我认为你想要实现的目标编写的程序。我已经包含了一个带有一些有用功能的实用程序类。它具有错误处理功能。在我的大项目中,我有实际的类,它们将记录到控制台和/或文本文件,处理异常,管理文件句柄以读取和写入特定类型,如基本文本文件,纹理(图像)文件或自定义数据结构文件类型。我没有包括这些,因为它会使这个简单的基本任务程序变得很大,从而不再需要实现和算法。我删除了我的可重用库,只包含了我认为需要的内容以及其他一些有用的有用功能。这段代码可以清除错误,并且可以很好地处理许多常见任务。
<强> stdafx.h中强>
#ifndef STDAFX_H
#define STDAFX_H
//#define VC_EXTRALEAN
//#include <Windows.h>
//#include <process.h>
//#include <memory>
//#include <numeric>
#include <array>
#include <vector>
#include <list>
#include <unordered_map>
#include <queue>
//#include <regex> - included in <queue> and <array> - needed for std::transform
#include <algorithm>
#include <iterator>
#include <tchar.h>
#include <conio.h>
#include <string>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <fstream>
enum ReturnCode {
RETURN_OK = 0,
RETURN_ERROR = 1,
}; // ReturnCode
#endif // STDAFX_H
我评论了在这种情况下不需要的常见基本有用包括,并删除了所有其他完全不相关的包含,如DirectX,OpenGL,OpenAL,OggVorbis,GLM包括等。
<强> stdafx.cpp 强>
#include "stdafx.h"
<强> Utility.h 强>
#ifndef UTILITY_H
#define UTILITY_H
class Utility {
public:
static void pressAnyKeyToQuit();
static std::string toUpper( const std::string& str );
static std::string toLower( const std::string& str );
static std::string trim( const std::string& str, const std::string elementsToTrim = " \t\n\r" );
static std::vector<std::string> splitString( const std::string& strStringToSplit, const std::string& strDelimiter, const bool keepEmpty = true );
static unsigned convertToUnsigned( const std::string& str );
static int convertToInt( const std::string& str );
static float convertToFloat( const std::string& str );
private:
Utility(); // Private - Not A Class Object
Utility( const Utility& c ); // Not Implemented
Utility& operator=( const Utility& c ); // Not Implemented
template<typename T>
static bool stringToValue( const std::string& str, T* pValue, unsigned uNumValues );
template<typename T>
static T getValue( const std::string& str, std::size_t& remainder );
}; // Utility
#include "Utility.inl"
#endif // UTILITY_H
<强> Utility.inl 强>
// ----------------------------------------------------------------------------
// stringToValue()
template<typename T>
static bool Utility::stringToValue(const std::string& str, T* pValue, unsigned uNumValues) {
int numCommas = std::count(str.begin(), str.end(), ',');
if (numCommas != uNumValues - 1) {
return false;
}
std::size_t remainder;
pValue[0] = getValue<T>(str, remainder);
if (uNumValues == 1) {
if (str.size() != remainder) {
return false;
}
}
else {
std::size_t offset = remainder;
if (str.at(offset) != ',') {
return false;
}
unsigned uLastIdx = uNumValues - 1;
for (unsigned u = 1; u < uNumValues; ++u) {
pValue[u] = getValue<T>(str.substr(++offset), remainder);
offset += remainder;
if ((u < uLastIdx && str.at(offset) != ',') ||
(u == uLastIdx && offset != str.size()))
{
return false;
}
}
}
return true;
} // stringToValue
<强> Utility.cpp 强>
#include "stdafx.h"
#include "Utility.h"
// ----------------------------------------------------------------------------
// pressAnyKeyToQuit()
void Utility::pressAnyKeyToQuit() {
std::cout << "Press any key to quit" << std::endl;
_getch();
} // pressAnyKeyToQuit
// ----------------------------------------------------------------------------
// toUpper()
std::string Utility::toUpper(const std::string& str) {
std::string result = str;
std::transform(str.begin(), str.end(), result.begin(), ::toupper);
return result;
} // toUpper
// ----------------------------------------------------------------------------
// toLower()
std::string Utility::toLower(const std::string& str) {
std::string result = str;
std::transform(str.begin(), str.end(), result.begin(), ::tolower);
return result;
} // toLower
// ----------------------------------------------------------------------------
// trim()
// Removes Elements To Trim From Left And Right Side Of The str
std::string Utility::trim(const std::string& str, const std::string elementsToTrim) {
std::basic_string<char>::size_type firstIndex = str.find_first_not_of(elementsToTrim);
if (firstIndex == std::string::npos) {
return std::string(); // Nothing Left
}
std::basic_string<char>::size_type lastIndex = str.find_last_not_of(elementsToTrim);
return str.substr(firstIndex, lastIndex - firstIndex + 1);
} // trim
// ----------------------------------------------------------------------------
// getValue()
template<>
float Utility::getValue(const std::string& str, std::size_t& remainder) {
return std::stof(str, &remainder);
} // getValue <float>
// ----------------------------------------------------------------------------
// getValue()
template<>
int Utility::getValue(const std::string& str, std::size_t& remainder) {
return std::stoi(str, &remainder);
} // getValue <int>
// ----------------------------------------------------------------------------
// getValue()
template<>
unsigned Utility::getValue(const std::string& str, std::size_t& remainder) {
return std::stoul(str, &remainder);
} // getValue <unsigned>
// ----------------------------------------------------------------------------
// convertToUnsigned()
unsigned Utility::convertToUnsigned(const std::string& str) {
unsigned u = 0;
if (!stringToValue(str, &u, 1)) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " Bad conversion of [" << str << "] to unsigned";
throw strStream.str();
}
return u;
} // convertToUnsigned
// ----------------------------------------------------------------------------
// convertToInt()
int Utility::convertToInt(const std::string& str) {
int i = 0;
if (!stringToValue(str, &i, 1)) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " Bad conversion of [" << str << "] to int";
throw strStream.str();
}
return i;
} // convertToInt
// ----------------------------------------------------------------------------
// convertToFloat()
float Utility::convertToFloat(const std::string& str) {
float f = 0;
if (!stringToValue(str, &f, 1)) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " Bad conversion of [" << str << "] to float";
throw strStream.str();
}
return f;
} // convertToFloat
// ----------------------------------------------------------------------------
// splitString()
std::vector<std::string> Utility::splitString( const std::string& strStringToSplit, const std::string& strDelimiter, const bool keepEmpty ) {
std::vector<std::string> vResult;
if ( strDelimiter.empty() ) {
vResult.push_back( strStringToSplit );
return vResult;
}
std::string::const_iterator itSubStrStart = strStringToSplit.begin(), itSubStrEnd;
while ( true ) {
itSubStrEnd = search( itSubStrStart, strStringToSplit.end(), strDelimiter.begin(), strDelimiter.end() );
std::string strTemp( itSubStrStart, itSubStrEnd );
if ( keepEmpty || !strTemp.empty() ) {
vResult.push_back( strTemp );
}
if ( itSubStrEnd == strStringToSplit.end() ) {
break;
}
itSubStrStart = itSubStrEnd + strDelimiter.size();
}
return vResult;
} // splitString
我从Utility类中删除了很多函数。例如,我有其他转换函数,将字符串转换为GLM :: Vec2,Vec3,Vec4对象的int,浮点数和双精度数,转换为不同的自定义枚举等。以及其他函数用于测试不同的东西。而不是有一堆常见的有用函数只是浮动处理基本的重复性任务,大多数都处理简单的字符串,转换,测试常见条件等,我喜欢将它们放在类充当类的类中所有这些函数的容器都声明为static。如果您注意到构造函数是私有的,并且该类只有方法没有成员变量。您无法创建实用程序对象。它的工作方式类似于命名空间,您需要使用的是用于访问实用程序功能的范围解析运算符。
<强>的main.cpp 强>
#include "stdafx.h"
#include "Utility.h"
void parseLine( std::string& strLine, std::vector<int>& vPositiveInts, std::vector<int>& vNegativeInts ) {
if ( strLine.size() == 0 ) {
// Skip Blank Line
return;
}
std::vector<std::string> vElements = Utility::splitString( strLine, " " );
int value = 0;
for ( unsigned u = 0; u < vElements.size(); u++ ) {
value = Utility::convertToInt( vElements.at( u ) );
if ( value > 0 ) {
vPositiveInts.push_back( value );
} else if ( value < 0 ) {
vNegativeInts.push_back( value );
} else {
// value = 0? Not Sure What User Wants To Do With 0
continue;
}
}
} // parseLine
int main() {
try {
std::string strFilename;
std::cout << "Enter the filename to read in data." << std::endl;
std::getline( std::cin, strFilename );
std::fstream in;
in.open( strFilename.c_str(), std::ios_base::in );
if ( !in.is_open() ) {
std::ostringstream strStream;
strStream << "Error reading in file " << strFilename << std::endl;
throw strStream.str();
}
if ( in.eof() ) {
std::ostringstream strStream;
strStream << "No Data in " << strFilename << std::endl;
throw strStream.str();
}
std::string strLine;
std::getline( in, strLine );
std::vector<int> vPositiveInts;
std::vector<int> vNegativeInts;
parseLine( strLine, vPositiveInts, vNegativeInts );
std::cout << "\nPositive Integers" << std::endl;
for ( unsigned u = 0; u < vPositiveInts.size(); u++ ) {
std::cout << vPositiveInts.at( u ) << " ";
}
std::cout << std::endl;
std::cout << "\nNegative Integers" << std::endl;
for ( unsigned u = 0; u < vNegativeInts.size(); u++ ) {
std::cout << vNegativeInts.at( u ) << " ";
}
std::cout << std::endl << std::endl;
// User Can Use Similar Methods To Write Data To Their Corresponding Files
// And Perform The Appropriate Calculations On This Data Using The Vectors Above
} catch ( std::string& str ) {
std::cout << "Exception Thrown: " << str << std::endl;
Utility::pressAnyKeyToQuit();
return RETURN_ERROR;
} catch ( ... ) {
std::cout << __FUNCTION__ << " Caught Unknown Exception" << std::endl;
Utility::pressAnyKeyToQuit();
return RETURN_ERROR;
}
Utility::pressAnyKeyToQuit();
return RETURN_OK;
} // main
这基于文本文件中的数据在单行上以空格分隔。如果文件中有多行,或者分隔符是其他内容(如逗号或半冒号),则可以稍微修改。我没有编写代码来将这些值写入文件,也没有编写任何代码来对上述数据进行任何计算,因为我将留给您完成。然而,我确实将它们打印到控制台。我只是简单地告诉你如何轻松地将整数分成正负两组。另外,作为注释,从文件中的字符串中找到的任何0都将被丢弃,并且不予考虑。还有另一个声明,只有在考虑0时才会继续。您可以通过更改第一个if语句中的比较将这些添加到肯定的情况中,但是因为0不是正数也不是负数,所以我没有将它包含在任何一个中。您可以使用另一个vector<int>
来存储所有0,以便在需要时跟踪它们。
<强> integers.txt 强>
51 144 5 16 8 0 -2 14 6 -4 173 263 11 9345 -135 777
节目输出
Enter the filename to read in data. integers.txt Positive Integers 51 144 5 16 8 14 6 173 263 11 9345 777 Negative Integers -2 -4 -135 Press any key to quit