将char动态数组atoi转换为int

时间:2015-10-03 04:07:32

标签: c++ arrays dynamic-arrays atoi

我的文本文件有15个数字,最后一个数字为15。并且,我想阅读它,我做的步骤:

  • 首先,我试着计算txt档中有多少个号码。
  • 因此,创建了动态尺寸数组。
  • 试图将数字保存到与其索引相对应的动态数组中。

现在,我的问题是,因为我正在以{strong>字符串的形式从txt文件中读取数字。因此,我如何将char转换为int动态数组。并且,我使用的算法在转换为int时在终端上生成垃圾值。无法弄清楚它有什么问题。

我的代码:

#include <iostream>
#include <fstream>

using namespace std;

int main(int argc, char* argv[])
{
    char *nPtr = argv[1];
    char *buffer = new char[5];
    int index = 0;

    ifstream fin(nPtr); //open the file

    if (argc > 1)
    {
        // allocate the memory
        if (!fin)
        {
            cout << "can't read the file!!" << endl;
            return -1;
        }

        if (fin)
        {
            cout << "Open sucessues!! " << endl;
        }

        while (!fin.eof())
        {
            fin >> buffer;
            index++; //counting here!!!
        }

        cout << "index: " << index << endl; //print out the counting results!
        cout << "buffer: " << buffer << endl; // checking the last number!  should "15"

        delete[] buffer; // 
        buffer = NULL;

        int *number = new int[index];
        char *temp = new char[index];
        int *home = number; //home

        while (!fin.eof())
        {
            fin >> temp;
            *number = atoi(temp); //im confessing right here!!!
            number++;
            temp++;
        }

        number = home;

        for (int i = 0; i < index; ++i)
        {
            cout << *number << endl; //*number print out garbage, i don't know why!
            number++;
        }
        fin.close();
    }
    return 0;
}

垃圾输出:

Open sucessues!!  
index: 15
buffer: 15
0
1073741824
0
1073741824
2136670223
32767
-1680479188
32767
0
0
0
0
0
0
0

2 个答案:

答案 0 :(得分:0)

你错过了&#39; \ 0&#39;在你的缓冲区。制作缓冲区size + 1并在其末尾添加\0,然后垃圾必须消失。

答案 1 :(得分:0)

while (!fin.eof())

Is one of the common sins of C++。它没有做你想做的事。过度简化是你无法知道你是否已经到达文件的末尾,除非你试图阅读它。这意味着如果您没有测试该读取是否成功,那么您将获得一个失败的额外读取和未定义的结果。

测试阅读成功非常简单,几乎涵盖了您在学校作业中可能遇到的每一个失败案例,包括EOF。

while (fin >> buffer)
{
    // do stuff
}

这意味着您的大部分读取逻辑都压缩为:

if (!fin)
{
    cout << "can't read the file!!" << endl;
    return -1;
}
while (fin >> buffer)
{
    // do stuff
}

在我们开始进行任务所需的工作之前,正确的方法是做你想做的事情

int tempnumber;
std::vector<int> numbers;
while (fin >> tempnumber) // read directly into a number. No further parsing needed.
{
    numbers.push_back(tempnumber);
}
if (fin.eof()) // now is when you check eof. 
                // If we didn't get to the end of the file, 
                // there is something wrong with the file
{
    std::cout << "Before sort:" << std::endl;
    for (int number: numbers)
    {
        std::cout << "  " << number << std::endl;
    }

    // And because I know why you are doing this, you finish off with:

    std::sort(numbers.begin(), numbers.end());
    std::cout << "After sort:" << std::endl;
    for (int number: numbers)
    {
        std::cout << "  " << number << std::endl;
    }
}
else // stopped somewhere other than the end of the file. Bad file
{
    std::cerr << "improperly formatted file" << std::endl;
    return 0;
}
可悲的是OP有一位教练认为,要学会射击步枪,你应该首先学会制造步枪,因此OP无法利用C ++的更高级别的功能。我更多的是教学逻辑,然后教低级语言基础知识的人,所以当然我认为这种教学方式是次优的。

还要注意使用显式命名空间。在我看来,using namespace std; carries risks超过了输入一些额外字符的难度。

但是如何使用没有高级构造的动态大小的数组来做到这一点? OP读取文件两次:一次用于大小,第二次用于获取内容。慢,文件IO与你在计算机上做的任何事情相比都非常慢,但是很有效。为了不读取文件两次,一个简单的单链表可以工作,但是OP已经声明(in their previous question)他们最终需要一个数组来对列表进行排序。

如果没有未提及的要求,此解决方案将解决为不使用数组,不转换为数字,

while (fin >> buffer)
{
    cout << buffer<< endl;
}

完成。还有其他有趣的技巧可以将fin直接转储到cout,但实质上,它会这样做。

这可以通过定义一个动态数组繁重的类来解决,但为什么呢? std :: vector填补了这个市场利基,为什么要剥夺OP的教练可能是下一个任务呢?

所以让我们通过手动调整数组大小来做到这一点。我们要做的是蛮力和愚蠢。每次数组即将过流时,我们创建一个新数组大小的新数组,将旧数据复制到新数组中,释放旧数组并指向新数组。

#include <iostream>
#include <fstream>
#include <cstdlib>
#include <cstring>

using namespace std;

int main(int argc, char* argv[])
{
    if (argc > 1)
    {
        char buffer[100]; // no need for pointer. allocate a big buffer that is
                          // unlikely to overflow
        int * numbers = new int[10]; // make a dynamic array. 10 seems like a
                                     // good starting size

int *被称为原始指针。它没有受到保护。必须手动管理。如果出现任何问题,它往往会丢失,它所指出的内容实际上是无法恢复的。如果没有充分的理由可以诚实地向其他人证明和解释,不要在现实世界中使用原始指针。如果其中一个人说,&#34;但你可以这样做。&#34;而且他们是对的,而是这样做。

在考虑原始指针之前,先按顺序使用std::unique_ptr和[std::shared_ptr][5]进行检查。 There are a whole raft of better ways to do this,但教练拒绝允许他们的可能性很大。知道它们存在并尽可能地使用它们。他们会为你带来很多悲伤。

        size_t capacity = 10; // number of items that can go into numbers

制作索引变量时,请使用size_t。它是无符号的(没有值&lt; 0)并且保证能够存储可以构造的最大对象的字节大小。换句话说,如果它不够大,你的程序就无法工作。

        size_t size = 0; // number of items currently in numbers

        ifstream fin(argv[1]); //open the file

        while (fin >> buffer) // will read up to next whitespace in file.

这可以读取超过缓冲区的结尾。被警告。这就是为什么我们把缓冲区变大了。

        {
            int temp = atoi(buffer);

atoi是C的石器时代遗留下来的一个原始且容易出错的故障。我不会在这里遇到C。一个理智的C程序员使用它同样谨慎,因为它是一个非常古老和非常愚蠢的功能。只能在抗议或极端控制的情况下使用它。

首选strtol及其系列用于转换char数组和std::stoi以及转换为std::string的系列,因为它们可以为您捕获错误。首选使用std::string来查看数组。

            if (capacity == size) // need to resize numbers
            { // make a bigger array, copy into bigger array, replace smaller array
                int * temp = new int[capacity * 2]; // make a bigger array
                memcpy(temp, numbers, capacity * sizeof(numbers[0]));

atoi一样,memcpy很粗糙,但有效。如果vector用于此赋值,则std :: copy也可能不存在。 memcpy适用于int和double之类的简单值,但对结构和类有利std::copymemcpy无意识地复制对象或结构中的确切内容,他们经常在幕后进行其他事情,比如指针,在复制时需要特殊处理。

                delete numbers; // free the array currently used by numbers
                numbers = temp; // point at new, bigger array
                capacity *= 2; // update the capacity to the new size
            }
            numbers[size++] = temp;
        }
        std::cout << "Before sort:" << std::endl;
        for (size_t index = 0; index < size;  index++)
        {
            std::cout << "  " << numbers[index] << std::endl;
        }
        fin.close();
        // call to sorting function goes here.
    }
    return 0;
}

在一个切割好的块中:

#include <iostream>
#include <fstream>
#include <cstdlib>
#include <cstring>

using namespace std;

int main(int argc, char* argv[])
{
    if (argc > 1)
    {
        char buffer[100]; // no need for pointer. allocate a big buffer that is
                          // unlikely to overflow
        int * numbers = new int[10]; // make a dynamic array. 10 seems like a
                                     // good starting size
        size_t capacity = 10; // number of items that can go into numbers
        size_t size = 0; // number of items currently in numbers

        ifstream fin(argv[1]); //open the file

        while (fin >> buffer) // will read up to next whitespace in file.
        {
            int temp = atoi(buffer);
            if (capacity == size) // need to resize numbers
            { // make a bigger array, copy into bigger array, replace smaller array
                int * temp = new int[capacity * 2]; // make a bigger array
                memcpy(temp, numbers, capacity * sizeof(numbers[0]));
                delete numbers; // free the array currently used by numbers
                numbers = temp; // point at new, bigger array
                capacity *= 2; // update the capacity to the new size
            }
            numbers[size++] = temp;
        }
        std::cout << "Before sort:" << std::endl;
        for (size_t index = 0; index < size;  index++)
        {
            std::cout << "  " << numbers[index] << std::endl;
        }
        fin.close();
        // call to sorting function goes here.
    }
    return 0;
}

既然我们已经将逻辑降低了,那么还有很多改进。首先是从main中获取所有代码并将其转换为自己的read函数。这样主要是很好和干净的两个明确定义的子任务各自在他们自己的功能:readsort

为什么呢?人类的头脑理解小东西比大的东西容易得多。如果一次只有一个问题,那么保持人类思维集中也容易得多。 read函数比一个大readsort函数短。 readsort表示同时发生了两件事。当read干扰sort的运作时,最大的乐趣就来了。你调试哪个?他们都。将单独的工作分开,除非共同混合有显着的,可衡量的和完全必要的收益。

如果您将所有内容都投入mainyou get one massive, confused mess。阅读代码变得更难。这意味着调试变得更难。作业需要更长的时间。在更直接的方面,标记变得更难。等级变低。

在现实生活中,作为一名程序员,加上同行的嘲弄,失败的代码审查,最终从你的工作中解脱出来,因​​为你的个人生产力很差,清理你的代码会降低整个部门的绩效