-1

Am newbie in using WinAPI in C++. Just searched the internet for similar issues but unable to find correct one.

Am trying to read a file, which includes integer values and to save the values to a string Buffer. Then I need to convert the string to int array in order to calculate average values of all array elements.

At this moment I experience a problem, that values from a file are not being saved correctly - there is redundantion of some values at output.

As example, the input file looks like this: 1 2 5 3 96 72 33 47 43 91 The code is throwing values like: 1 2 5 3 96 72 33 47 43 91 43 91 43 91 43 91 43

Please see my code:

#include <iostream>
#include <Windows.h>
#include <string>
#include <tchar.h>
#include <cstdlib>
#include <ctime>
using namespace std;

int main( int argc, TCHAR *argv[] )
{
HANDLE hfile = CreateFile("RandomValues.txt",GENERIC_READ,0,NULL,OPEN_EXISTING,0,NULL); 
    DWORD dwBytesRead = 0;
    int SizeofFile=GetFileSize(hfile,NULL);
    LPSTR Buffer=NULL;
    DWORD dwSizeofBuffer = sizeof(Buffer);
    Buffer =( LPSTR ) GlobalAlloc( GPTR, MAX_PATH * sizeof(CHAR) );
    cout<<SizeofFile<<endl;
    for(unsigned int i=0;i<dwSizeofBuffer;i++)
    {
        ReadFile( hfile, Buffer, dwSizeofBuffer, &dwBytesRead, NULL );
        Buffer[i] = (wchar_t)Buffer[i];
        cout<<Buffer<<" ";  //checking, if values are read correct to Buffer
        
    }
    GlobalFree(Buffer);
    CloseHandle(hfile); 
    return 0;
}

UPDATE: I was asked to put the latest code - it's simpler (I think) and uses vector array and stoi function, although the input looks like: 11111. One user suggested to paste the new code here as edit:

#include <iostream>
#include <Windows.h>
#include <string>
#include <tchar.h>
#include <cstdlib>
#include <ctime>
#include <fstream>
#include <vector>
using namespace std;

int main( int argc, TCHAR *argv[] )
{
    //proces 2 uzyskuje dostep do plilu z liczbami i oblicza srednia liczb a wynik podaje na ekranie
    fstream File;
    File.open("RandomValues.txt", ios::in | ::ios::out);
    string Buffer = " ";
    if( File.good() ){
        for(int i=0;!File.eof();i++)
    {
        getline(File,Buffer);
        cout<<Buffer;
    }
    }
    
    
    //int str_length = Buffer.length(); 
    //int* Values;
    //Values = new int[str_length];
    vector <int> Values; 
    int j = 0;
    for (int i = 0; Buffer[i] != '\0'; i++) { 
  
         
         if (Buffer[i] == ' '){ 
            // Increment j to point to next 
            // array location 
            j++; 
        } 
        else { 
  
            // subtract str[i] by 48 to convert it to int 
            // Generate number by multiplying 10 and adding 
            // (int)(str[i]) 
           // Values[j] = Values[j] * 10 + (Buffer[i] - 48); //tries as well as *(Values + j) = *(Values + j) * 10 + (*(Buffer + i) -48) and with stoi(Buffer)
           Values.push_back(stoi(Buffer)); 
        } 
    } 
  
    for (unsigned int i = 0; i <= Values.size(); i++) { 
        cout << Values[i] << " "; 
         
    } 
//  delete [] Values;
    File.close();
    return 0;
}
wiki11ful
  • 29
  • 1
  • 8
  • 1
    Out-of-context: Better use C++ standards like `fstream` rather than using Windows specific APIs. It will be easier and cross-platform too – Asesh Aug 01 '20 at 16:10
  • it's too easy ;) – wiki11ful Aug 01 '20 at 16:13
  • It does what it claims it does. Are you looking at dwBytesRead? – Kenny Ostrom Aug 01 '20 at 16:13
  • There are lots of issues with the above code. The size of buffer calculation is wrong for instance. Can we just get a couple of facts straight. The integers are stored as binary, correct? How many bytes for each integer? – john Aug 01 '20 at 16:14
  • The buffer size is not `dwSizeofBuffer` (the size of pointer is assigned) but `MAX_PATH * sizeof(CHAR)`. – MikeCAT Aug 01 '20 at 16:14
  • MAX_PATH * sizeof(CHAR) almost work - it reads all file's values although last value is redundant. I think that's because of variable '''int SizeofFile=GetFileSize(hfile,NULL);''' – wiki11ful Aug 01 '20 at 16:22
  • @wiki11ful `MAX_PATH * sizeof(CHAR)` is completely wrong, Two questions, are your integers stored as binary and if so how many bytes per integer? If you don't know the answers to these questions then just say so. – john Aug 01 '20 at 16:26
  • @wiki11ful The size of the buffer should be related to the size of the file in your calculation it is not. But I am assuming binary integers, something which your code suggests but which you haven't confirmed. – john Aug 01 '20 at 16:27
  • as far as I know, the values are not stored as binary – wiki11ful Aug 01 '20 at 16:27
  • it is just simple .txt file – wiki11ful Aug 01 '20 at 16:27
  • @wiki11ful OK but your code is reading them as binary. So obviously you need to start over. – john Aug 01 '20 at 16:29
  • @wiki11ful The Win32 API has no support for reading integers as text. So I recommend you use the standard C++ I/O as suggested earlier. – john Aug 01 '20 at 16:29
  • Of course, I have a version of this program which use standard fstream method - it reads the file correctly with getline() method. – wiki11ful Aug 01 '20 at 16:33
  • Although when converting the string which contains readed values to int array it shows some random values: – wiki11ful Aug 01 '20 at 16:34
  • https://pastebin.com/hH1WuSYA – wiki11ful Aug 01 '20 at 16:36
  • 1
    @wiki11ful You seem to be making a simple operation very difficult. I'm a bit lost as to where you are. I suggest you start again, but if your file really is text, then don't use the Win32 API, it will only make things more difficult. – john Aug 01 '20 at 16:38
  • @wiki11ful Judging by the code on pastebin there are commas in your data. Why didn't you mention that before? Where in the code at the top of this page are you dealing with the commas? – john Aug 01 '20 at 16:43
  • `int SizeofFile=GetFileSize(hfile,NULL);` is not bad. `for(unsigned int i=0;i – MikeCAT Aug 01 '20 at 16:52

2 Answers2

0

Here's how you can read integers from a file into a vector. I am assuming that the integers are separated by white space only (i.e. there are no commas or similar characters in the file). If this is not true then the code has to be slightly more complicated (but not much).

// open the file
ifstream File("RandomValues.txt", ios::in);
if (!File.is_open())
    cerr << "failed to open file\n";

vector<int> Values;
// read the values (three lines of code !!!)
int val;
while (File >> val)
    Values.push_back(val);

// print out the values
for (unsigned int i = 0; i < Values.size(); i++) { 
    cout << Values[i] << " ";
cout << '\n';
john
  • 85,011
  • 4
  • 57
  • 81
  • I need to add that it worked fine for first combinantion of values in the file, today I generated random numbers and saved tchem to a file, now it reads only first one value – wiki11ful Aug 03 '20 at 18:23
  • @wiki11ful Anything different about the file? For instance if there were commas between the numbers then this code would fail after the first number. – john Aug 03 '20 at 19:48
  • Actually, there is no coma between values in the file, there is just space between them. It is simple .txt file, which includes randomly generated values caused by ```srand``` function – wiki11ful Aug 04 '20 at 09:37
  • @wiki11ful I have no explanation then. If it worked before it should work now, something must have changed somewhere. – john Aug 04 '20 at 12:49
  • I noticed, that the file contains more than 1 white space between the integer values, that might be the reason - I've checked txt file and it has 2 spaces, when the value have only 1 number, there can be 3 spaces – wiki11ful Aug 04 '20 at 16:18
  • No, that won't be it. When `File >> val` reads a integer it skips as much whitespace as it needs to. – john Aug 04 '20 at 16:59
  • Case solved- previously I wrote values to file using WinAPI methods, I changed it to easy fstream method ;) – wiki11ful Aug 06 '20 at 15:21
  • @wiki11ful OK good. Like I said earlier Win32API has no built in support to text I/O. So you were probably writing the integers as binary. That would explain my code was failing. – john Aug 06 '20 at 19:14
-2

I was suggested to use standard fstream method, of course I have it and it reads the file content correctly, the problem started while converting the values from string to int array. I put here full code to see it better than on pastebin:

#include <iostream>
#include <Windows.h>
#include <string>
#include <tchar.h>
#include <cstdlib>
#include <ctime>
#include <fstream>
using namespace std;

int main( int argc, TCHAR *argv[] )
{
    //proces 2 uzyskuje dostep do plilu z liczbami i oblicza srednia liczb a wynik podaje na ekranie
    fstream File;
    File.open("RandomValues.txt", ios::in | ::ios::out);
    string Buffer = " ";
    for(int i=0;!File.eof();i++)
    {
        getline(File,Buffer);
        cout<<Buffer;
    }
    
    int str_length = Buffer.length(); 
    int* Values = new int(str_length);
    int j = 0;
    for (int i = 0; Buffer[i] != '\0'; i++) { 
  
         
         if (Buffer[i] == ' '){ 
            // Increment j to point to next 
            // array location 
            j++; 
        } 
        else { 
  
            // subtract str[i] by 48 to convert it to int 
            // Generate number by multiplying 10 and adding 
            // (int)(str[i]) 
            Values[j] = Values[j] * 10 + (Buffer[i] - 48); //tries as well as *(Values + j) = *(Values + j) * 10 + (*(Buffer + i) -48) and with stoi(Buffer)
        } 
    } 
  
    for (unsigned int i = 0; i <= sizeof(Values); i++) { 
        cout << Values[i] << " "; 
         
    } 
    delete [] Values;
    File.close();
    return 0;
}
wiki11ful
  • 29
  • 1
  • 8
  • 1
    Your usage of `!File.eof()` is [wrong](https://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong) and you should check if reading is successful **before** trying to print what is read. – MikeCAT Aug 01 '20 at 16:53
  • Also `int* Values = new int(str_length);` is wrong: this is allocating one `int` and initializing it to the value `str_length` instead of allocating an array. Also note that `sizeof(Values)` is not the number of elements but the size of the pointer. You should use `std::vector`. – MikeCAT Aug 01 '20 at 16:56
  • by using ```int* Values = new int(str_length);``` I wanted to define the size of the array ```Values``` which should be ```str_length``` – wiki11ful Aug 01 '20 at 17:04
  • Array allocation will be like `int* Values = new int[str_length];` (use `[]` instead of `()`) Note that allocated elements will not be automatically initialized in this case. – MikeCAT Aug 01 '20 at 17:05
  • [stoi, stol, stoll](https://en.cppreference.com/w/cpp/string/basic_string/stol). Or [strtol, stroll](https://en.cppreference.com/w/cpp/string/byte/strtol). – IInspectable Aug 01 '20 at 17:34
  • I've changed it to ```Values = new int[str_length];``` although random values still shows. I tried as wel using vector array - it does not contain any value at all – wiki11ful Aug 01 '20 at 18:01
  • Additionally in second loop I used ```(sizeof( Values ) / sizeof( Values[ 0 ] ))``` instead of ```sizeof(Values)``` – wiki11ful Aug 01 '20 at 18:03
  • @wiki11ful Both `sizeof(Values)` and `sizeof( Values ) / sizeof( Values[ 0 ]` are wrong because `Values` is a pointer not an array. You seem to be struggling whatever method you choose, but using a vector is defintely the easiest method because it avoids the complexities of pointers. So I would try using a vector again. – john Aug 01 '20 at 18:09
  • @wiki11ful Reading a comma separated file of integers is a common thing to want to do. You should be able to find some code on SO. – john Aug 01 '20 at 18:11
  • @wiki11ful For instance [here](https://stackoverflow.com/questions/63063814/read-comma-separated-integers-from-getline) is someone asking exactly that question. The answer from Remy Lebeau seems the best. – john Aug 01 '20 at 18:12
  • I changed the array type to Vector as @john suggestes. – wiki11ful Aug 01 '20 at 18:21
  • It partially work - tried to push the values from Buffer using ```Values.push_back(stoi(Buffer)); ``` receiving just 1 values – wiki11ful Aug 01 '20 at 18:22
  • @wiki11ful Would need to see the latest code to help further. – john Aug 01 '20 at 18:24
  • @john I've updated my original question with new code – wiki11ful Aug 02 '20 at 07:36
  • @wiki11ful I hate to say it but the code is just a mess. For instance you read each line of the file into a single variable `Buffer`. So obvously all lines in the file are going to be ignored except the last one. The when you try an process `buffer` so part of the code are treating buffer as an array of characters (e.g. `if (Buffer[i] == ' '){`) while other parts of the code are treating buffer as a single string e.g. `stoi(Buffer)`. Honestly this code can be thrown away, – john Aug 02 '20 at 08:03
  • Reading a file of integers and storing them in an vector should be **three lines of code**. It's a simple task. I will write an answer that show how it should be done. – john Aug 02 '20 at 08:05
  • Is this post showing your solution to your problem or is this to provde another version of the code which still has a problem? It does not really read like "This is the solution...". – Yunnosch Dec 23 '20 at 21:44