I have a simple program that tries to read 2-dimensional data into a heap allocated array of floating-points. The program is as follows.
#include <iostream>
#include <fstream>
void read_file(std::ifstream &inFile, float **arr, unsigned m, unsigned n)
{
for(unsigned i = 0; i < m; ++i) {
for(unsigned j = 0; j < n; ++j) {
inFile >> arr[i][j];
std::cout << arr[i][j];
}
std::cout << std::endl;
}
}
int main() {
const unsigned m = 20;
const unsigned n = 1660;
float **A = new float *[m]; // alloc pointers to rows 1,...,m
for(unsigned row = 0; row < m; row++) A[row] = new float [n]; // alloc columns for each row pointer
std::ifstream inFile("data.dat");
read_file(inFile, A, m, n);
// DEALLOC MEMORY
for(unsigned row = 0; row < m; row++) delete [] A[row]; // dealloc columns for each row pointer
delete [] A; // dealloc row pointers
return EXIT_SUCCESS;
}
The data is a table of 0-1 entries (see here: data) which is nicely row orientated and has 20 rows and 1660 columns. I added the printing into the read_file function to see what goes wrong and it prints only zeros, but the correct amount at least (20*1660 zeros).
The data seems to be tab delimitered; is that the problem or is my approach completely invalid?
It's exactly what may happen if the file doesn't exist.
You should check that the file exists after creating the inFile object, for instance like this:
std::ifstream inFile("data.dat");
if (!inFile)
{
std::cerr << "cannot open input" << std::endl;
return 1;
}
If file doesn't exist, cin doesn't put data in your array, and there are chances that you get 0 all the way (I had 0 + other strange stuff), so to sum it up undefined behaviour
Note that if the file exists, your program works as expected. It would be even better to check the file after having read a value to be sure that the file has as many values as expected:
for(unsigned j = 0; j < n; ++j) {
inFile >> arr[i][j];
if (!inFile)
{
std::cerr << "file truncated " << i << " " << j << std::endl;
return;
}
std::cout << arr[i][j];
}
Related
I have some code written but I'm not sure why the reversed array is not giving me the exact values I need. I created a second array the same size as the first and used nested for loops to fill the second with the contents of the first in reverse.
See below:
#include <iostream>
using namespace std;
int main()
{
// Ask for how big the array is
int n;
cout << "how big is the array?" << endl;
cin >> n;
// create array
int a[n];
// create second array
int b[n];
// ask for contents of the 1st array
cout << "what's in the array?" << endl;
for (int i = 0; i < n; i++)
{
cin >> a[i];
}
// reverse the array
for (int i = n - 1; i >= 0; i--)
{
for (int k = 0; k < n; k++)
{
b[k] = a[i];
break;
}
}
// print out the new array
for (int k = 0; k < n; k++)
{
cout << b[k] << endl;
}
return 0;
}
you don't need 2 bucles for fill the second array
try with:
//reverse the array
s = 0;
for (int i=n-1;i>=0;i--){
b[n]=a[s];
s++;
}
Try something like this:
#include <algorithm>
#include <iostream>
#include <vector>
namespace {
template <typename IStream>
[[nodiscard]] int readOneIntFrom(IStream& istream) {
int x;
istream >> x;
return x;
}
}
int main()
{
// Ask for how big the array is
std::cout << "how big is the array?" << std::endl;
auto n = readOneIntFrom(std::cin);
// create array
std::vector<int> a;
// ask for contents of the 1st array
std::cout << "what's in the array?" << std::endl;
for (int i = 0; i < n; i++)
{
a.emplace_back(readOneIntFrom(std::cin)); // Make a new entry at the end of a.
}
// Construct b from a backward. (Or do auto b = a; std::reverse(b.begin(), b.end());
auto b = std::vector<int>(a.rbegin(), a.rend());
// print out the new array
for (const auto& bi : b)
{
std::cout << bi << std::endl;
}
return 0;
}
I'm using C++ to read from two .txt files. The first number in the .txt file represents the rows. The second number represents the columns. Then the remaining numbers is for the matrix. I'm getting an error while trying to scan the dimensions. I tried declaring two ints. I also tried using constants and I still get errors.
This is the requirements to help understand what I'm trying to do.
[Matrix Addition1
Here is my code.
#include <iostream>
#include <fstream>
#include<iomanip>
#include<string>
using namespace std;
int main() {
/**
* Integer n and m are declared to store the row and column
* respectively
*/
const int n = 8;
const int m = 8;
int arr[n][m];
//int n, m;
/**
* below we create object of file named myFile for file matrix.txt
*/
string filename;
cout << "Enter file name: ";
getline(cin, filename);
ifstream myfile;
myfile.open(filename.c_str());
/**
* scanning dimensions of first matrix
*/
myfile >> n >> m;
/**
* Creating double type 2d array named matrix1
*/
double matrix1[n][m];
/**
* In following nested for loop we scan data into the array matrix1
*/
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
myfile >> matrix1[i][j];
}
}
cout << "MATRIX 1" << endl;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cout << right << setw(5) << matrix1[i][j];
}
cout << endl;
}
cout << endl;
/***
* Data scanning for matrix 2
*/
/**
* Integer p and q are declared to store the row and column
* respectively of matrix2
*/
const int p = 8;
const int q = 8;
int arr2 [p][q];
//int p, q;
/**
* scanning dimensions of first matrix
*/
myfile >> p >> q;
/**
* Creating double type 2d array named matrix2
*/
double matrix2[p][q];
/**
* In following nested for loop we scan data into the array matrix2
*/
for (int i = 0; i < p; i++) {
for (int j = 0; j < q; j++) {
myfile >> matrix2[i][j];
}
}
cout << "MATRIX 2" << endl;
for (int i = 0; i < p; i++) {
for (int j = 0; j < q; j++) {
cout << right << setw(5) << matrix2[i][j];
}
cout << endl;
}
cout << endl;
/**
* Check if matrix1 and matrix2 can be added
*/
if (n == p && m == q) {
double matrix3[n][m];
for (int i = 0; i < p; i++) {
for (int j = 0; j < q; j++) {
matrix3[i][j] = matrix1[i][j] + matrix2[i][j];
}
}
cout << endl;
cout << "ADDITION of MATRIX 1 AND MATRIX 2" << endl;
for (int i = 0; i < p; i++) {
for (int j = 0; j < q; j++) {
cout << right << setw(5) << matrix3[i][j];
}
cout << endl;
}
cout << endl;
}
else {
cout << "Both matrix cannot be added!" << endl;
}
return 0;
}
const int n = 8;
const int m = 8;
These two ints are constant. That means that their value cannot be changed. They are etched in stone. They will forever contain 8, both. That's what const means in C++.
myfile >> n >> m;
This attempts to read two integer value from myfile into n and m. However, that's impossible, because we've just determined that these two variables are constant. They cannot be changed. Their values cannot be read from a file, or set in any other way.
And you cannot simply remove the const keyword either, because:
int arr[n][m];
In C++ the sizes of all arrays are fixed and they must be specified as a constant value at compile time. I surmise that you initially declared n and m to be ordinary ints, your compiler complained that you can't do this unless they are constant, you then changed them to const ints, then the compiler complained that they are not initialized, then you tried initializing them from 8, and now you cannot figure out the reason for the current compilation error.
C allows you to declare an array whose size comes from a non-constant expression at a run time, but this is not valid in C++ (although some compilers will accept this as a non-standard C++ extension).
Your C++ programming assignment requires you to do one of two things: either allocate the matrix dynamically, or use std::vectors. Either of these approaches effectively implement arrays whose size is established at runtime.
int arr[n][m];
is not being used anywhere in the code. So that can be removed.
const declarations for m, n can be replaced by the code that has been commented out
int m, n;
With these changes there shouldn't be a problem reading the dimensions of the matrix from the file. But as Sam pointed out you need to dynamically allocate the 2D arrays using malloc/new or use a std::vectorstd::vector>. You can also use boost's Matrix class - https://www.boost.org/doc/libs/1_42_0/libs/numeric/ublas/doc/matrix.htm
I am new to c++ and learning how to declare, use and delete a two dimensional array of std::string.
Because this is a learning exercise I am ignoring the idea of using vectors (for now).
I wrote a program that creates a small two dimensional array, adds data and then deletes the 2d array trying to use best practices along the way.
Can someone suggest improvements? I am most concerned about cleaning up the 2d array after I'm done using it, so I can avoid the possibility of a memory leak.
Thanks in advance.
#include <iostream>
#include <string>
using namespace std;
void DIM(std::string **marray,unsigned int row,unsigned long cols)
{
if (marray[row] != nullptr) {
delete [] marray[row];
marray[row] = nullptr;
}
marray[row] = new std::string[cols];
}
void DIM_DELETE (std::string **marray,unsigned int row)
{
if (*&marray[row] != nullptr) {
delete[] marray[row];
marray[row] = nullptr;
}
}
void DIM_DELETE_ALL (std::string **marray,unsigned int rows)
{
for (int i=(rows-1); i>-1; i--) {
if (marray[i] != nullptr) {
delete[] marray[i];
marray[i] = nullptr;
}
}//next i
//now take care of marray
if (marray != nullptr) {
delete [] marray;
marray = nullptr;
}
}
std::string **create2darray(unsigned int rows,unsigned int cols)
{
//first create the pointer
std::string **my = nullptr; //create pointer , note: no data portion assigned yet
//now assign a data portion to the pointer (could do above in one step)
my = new std::string*[rows];// elements 0 through rows-1 //assigns data section (an array of std::strings)
//now set newly created rows to nullptr
for (unsigned int i = 0; i<rows; i++) {
my[i] = nullptr;
}
//dim each row for cols columns
for (unsigned int i = 0; i<rows; i++) {
DIM(my,i,cols);//dims the strings (creates data portion) my = new std::string*[x];//
}
return my;//returning a std::string **
}
int main()
{
unsigned int rows = 3;//3 rows (0 through 2)
unsigned int cols = 4;//4 columns (0 through 3)
std::string **myarray = create2darray(rows,cols);//2d array (3 rows, 5 cols)
cout << "2d array created" << endl << endl;
myarray[0][0] = "a0"; //row 0, col 0
myarray[1][0] = "b0"; //row 1, col 0
myarray[2][0] = "c0";
myarray[0][1] = "a1";
myarray[0][2] = "a2";
myarray[0][3] = "a3";
myarray[1][1] = "b1";
myarray[1][2] = "b2";
myarray[1][3] = "b3";
myarray[2][1] = "c1";
myarray[2][2] = "c2";
myarray[2][3] = "c3";
cout << "assigned data to rows 0 to 2 and cols 0 to 3" << endl << endl;
for (unsigned int i=0; i<rows; i++) {
cout << i << ",0: " << myarray[i][0] << " " << i << ",1: " << myarray[i][1] << " " << i << ",2: " << myarray[i][2] << " " << i << ",3: " << myarray[i][3] << endl;
}
cout << endl;
cout << "we are done with 2d array, let's delete it" << endl;
//tested dim_delete (seems to work)
/*
DIM_DELETE(myarray,0);//delete [] myarray[0]; myarray[0] = nullptr;
DIM_DELETE(myarray,1);
DIM_DELETE(myarray,2);
//still need to delete myarray
delete [] myarray;
myarray = nullptr;
*/
//delete all rows and delete the std::string that holds the rows
DIM_DELETE_ALL(myarray,rows);
cout << "array deleted, all done" << endl;
//hold cursor so user can see console messages
do {} while(cin.get()!='\n');
return 0;
}
If the second dimension of your array is constant, I think you can be fine using a single new and delete operators. Something like this:
#include <stdio.h>
#include <string>
int ROWS = 3;
const int COLS = 4;
typedef std::string arr4[COLS];
int main()
{
arr4 *a;
a = new arr4[ROWS];
for (int i = 0; i < ROWS; i++)
for (int j = 0; j < COLS; j++)
a[i][j] = std::to_string(j*ROWS + i);
for (int i = 0; i < ROWS; i++)
{
for (int j = 0; j < COLS; j++)
printf("%s ", a[i][j].c_str());
printf("\n");
}
printf("\n");
delete [] a;
}
void dualSort(int [], double [], int);
int main()
{
const int ARRAY_SIZE = 1000; // Array size
double accountNumbers[ARRAY_SIZE]; // Array with 1000 elements
double accountBalances[ARRAY_SIZE]; // Loop counter variable
int count = 0; // Input file stream object
ifstream inputFile;
// Open the file.
inputFile.open("FinalNumbers.txt");
// Read the numbers from the file into the array
while (count < ARRAY_SIZE && inputFile >> accountNumbers[count] >> accountBalances[count] ) {
count++;
}
inputFile.close();
// Display the read data
cout << "The bank account numbers are: " << endl;
for (int count = 0; count < ARRAY_SIZE; count++) {
cout << accountNumbers[count] << "\n" << accountBalances[count] << " " << endl;
}
void dualSort(int accountNumbers[], double accountBalances, int ARRAY_SIZE);
}
I am required to use the selection sort or bubble sort algorithm.
I have Bank Account Numbers that have to be correspondingly and ascending sorted with there Account Balance, all the data is read from a file.
After sorting the data I have to rewrite it into another file, which is the least of my worries.
So the question is how do I go about sorting my accountNumbers in ascending order along with their accountBalance following them.
You need to sort according to accountNumbers but apply every swap operation to both arrays.
Here is the code using selection sort:
void dualSort(int accountNumbers[], double accountBalances[], int ARRAY_SIZE)
{
int minIndex;
for(int i = 0; i < ARRAY_SIZE - 1; i++)
{
minIndex = i;
for(int j = i + 1; j < ARRAY_SIZE; j++)
{
if(accountNumbers[j] < accountNumbers[minIndex])
{
minIndex = j;
}
}
swap(accountNumbers[i], accountNumbers[minIndex]);
swap(accountBalances[i], accountBalances[minIndex]);
}
}
You can declare a struct:
struct Account{
int accountNum;
int accountBalance;
bool operator<(const Account& a);
};
Then overload the comparison operator:
bool Account::operator<(const Account& a);
{
return (accountNum < a.accountNum);
}
Then put all your data in a struct vector using for loops:
std::vector<Account> accVec;
Finally sort vector using std::sort()
std::sort(accVec.begin(), accVec.end());
Now you have your data neatly stored in a vector in ascending order of account number.
Alternatively you can apply regular bubbleSort to sort the elements, as shown by "abcOfJavaAndCPP"
for(int j = 1; j < accVec.size(); ++j)
for(int i = 1; i < accVec.size() ; ++i)
if(accVec[i-1] < accVec[i])
std::swap(accVec[i], accVec[i+1]);
to do bubble sort algorithm you must do 2 for loops and a temporary variable
int tempAccNumber=0;
int tempAccBalance=0;
for(int j=0;j<ARRAY_SIZE-1;++j)
for(int i=0;i<ARRAY_SIZE-1;++i)
if(accountNumbers[i]>accountNumbers[i+1])
{
tempAccNumber=accountNumbers[i];
accountNumbers[i]=accountNumbers[i+1];
accountNumbers[i+1]=tempAccNumber;
tempAccBalance=accountBalances[i];
accountBalances[i]=accountBalances[i+1];
accountBalances[i+1]=tempAccBalance;
}
just implement this to your function that do the bubble sort
Code can be simplified quite a bit by using some more modern C++ techniques:
#include <vector>
struct Account {
double balance;
int number;
};
bool operator<(const Account& lhs, const Account& rhs) {
return lhs.number < rhs.number;
}
void dualSort(vector<Account>& v) {
for (std::size_t i = 0; i != v.size() - 1; ++i) {
for (std::size_t j = 0; j != v.size() - 1; ++j) {
if (v[j] < v[j+1]) std::swap(v[j], v[j+1]);
}
}
}
int main()
{
const int ARRAY_SIZE = 1000; // Array size
std::vector<Account> v(ARRAY_SIZE);
std::ifstream inputFile;
// Open the file.
inputFile.open("FinalNumbers.txt");
for (std::size_t i = 0; i != ARRAY_SIZE; ++i) {
inputFile >> v[i].number >> v[i].balance;
}
inputFile.close();
// Display the read data
cout << "The bank account numbers are: " << endl;
for (int count = 0; count < ARRAY_SIZE; count++) {
cout << v[count].number << "\n" << v[count].balance << " " << endl;
}
void dualSort(v);
}
Would encourage you to learn about classes, or even just structs to start, and also get familiar with std::vector as you should be using it a lot.
I have to read from a file an array of numbers with an unknown size and save it as a matrix. The code must be as compact as possible, which is why I don't want to read file as string and then convert it to an int.
int main()
{
ifstream infile("array.txt");
int n, counter = 0, **p;
while (!infile.eof()) {
counter++;
}
counter = sqrt(counter);
cout << "counter is " << counter << endl;
p = new int*[counter];
for (int i = 0; i < counter; i++)
p[i] = new int[counter];
while (!infile.eof()) {
for (int i = 0; i < counter; i++) {
for (int j = 0; j < counter; j++)
p[i][j] = n;
}
}
for (int i = 0; i < counter; i++) {
for (int j = 0; j < counter; j++) {
cout << p[i][j] << " ";
}
cout << endl;
}
_getch();
return 0;
}
Here is my code, it was made for a square matrix. The problem is, I can't read the file at second time to save the numbers to the matrix.
You have a lot of problems in your code. A big one is that you have several infinite loops and aren't even reading from a file. An even bigger problem is that you're not using C++ constructs. I've written a small program that does what you're trying to do using more C++ concepts. In this case, you should use a std::vector - they will handle all the dynamic sizing for you.
test.cc
#include <iostream>
#include <vector>
#include <sstream>
#include <fstream>
#include <string>
// Nobody wants to write `std::vector<std::vector<int>>` more than once
using int_matrix = std::vector<std::vector<int>>;
void populate_matrix(int_matrix& mat, const std::string& line) {
int num;
std::stringstream ss(line);
std::vector<int> row;
// Push ints parsed from `line` while they still exist
while(ss >> num) {
row.push_back(num);
}
// Push the row into the matrix
mat.push_back(row);
}
// This is self-explanatory, I hope
void print_matrix(const int_matrix& mat) {
size_t n = mat.at(0).size();
for(size_t i = 0; i < n; ++i) {
for(size_t j = 0; j < n; ++j) {
std::cout << mat.at(i).at(j) << " ";
}
std::cout << std::endl;
}
}
int main(int argc, char** argv) {
int_matrix mat;
// Pass the file as a command-line arg. Then you don't need to worry about the path as much.
if(argc != 2) {
std::cout << "Number of arguments is wrong\n";
return EXIT_FAILURE;
}
// Open file with RAII
std::ifstream fin(argv[1]);
std::string line;
// Handle each line while we can still read them
while(std::getline(fin, line)) {
populate_matrix(mat, line);
}
print_matrix(mat);
return EXIT_SUCCESS;
}
This code assumes the text file looks something like this:
numbers.txt
1 2 3
4 5 6
7 8 9
i.e., n lines with n numbers per line separated by whitespace.
To compile and run this code, you can follow these steps:
13:37 $ g++ test.cc -std=c++14
13:37 $ ./a.out /path/to/numbers.txt
As far as I can see the program runs once through the file and later you run another while loop to read from the file. When you read from a file, then its like your "cursor" moves forward. So basicly, if you hit the end, you have to reset the cursor back to the start of the file.
You can set your cursor back with seekg(0).(http://www.cplusplus.com/reference/istream/istream/seekg/)