I'm writing a code that reads a text file to create a matrix dinamically. I will then get the information from this matrix to write it in another text file.
I put in a 'for' loop that will create a matrix for each chunk of text that it reads, here it is:
for (cont = 0; cont < nPares; cont++){
ResultFile >> FlowOri;
ResultFile >> FlowDest;
ResultFile >> nPaths;
ResultFile >> largestPath;
double** iPathMatrix = (double**) new double[nPaths];
for (i = 0; i < nPaths; i++) {
iPathMatrix[i] = (double*) new double[largestPath + 2];
}
for (i = 0; i < nPaths; i++) {
for (j = 0; j < largestPath + 2; j++) {
ResultFile >> iPathMatrix[i][j];
}
}
for (i = 0; i < nPaths; i++) {
for (j = 0; j < largestPath + 2; j++) {
cout << iPathMatrix[i][j] << " ";
}
cout << "\n";
}
free(iPathMatrix);
}
'ResultFile' is an ifstream.
That 'cout' near the end was put there to check if it was creating the matrices as intended, which it is.
As you can see, I'm creating the matrix and then freeing the memory at the end of the loop to create it again, since it will have the same name. I can probably figure a way to work with this, but it'd be way easier if I could create a different matrix with each loop, perhaps naming each with the 'FlowOri' and 'FlowDest' variables, if that's possible, and after the loop stops, access them and write in my output file.
Is there a way to do it? How would I reference it afterwards?
As you can see, I'm creating the matrix and then freeing the memory at
the end of the loop to create it again,
No you aren't (at least not correctly). Each new[] must be paired with a delete[], so the correct code is
for (i = 0; i < nPaths; i++) {
delete[] iPathMatrix[i];
}
delete[] iPathMatrix;
Now since you are programming C++, you could avoid this by using vectors.
std::vector<std::vector<double>> iPathMatrix(nPaths, std::vector<double>(largestPath + 2));
Now you don't need to allocate or free anything, but the rest of your code is unchanged.
Now as for your actual question. If I understand it correctly you want to associate a matrix with the value of the flowOri variable. That's easy to do, you should use a std::map.
You haven't said what type flowOri is, I'm going to assume it's a std::string but you should be able to get this to work whatever type it is.
#include <vector>
#include <map>
#include <string>
// lets give a shorter name for the vector type
using MatrixRowType = std::vector<double>;
using MatrixType = std::vector<MatrixRowType>;
// and this is the map type that holds the matrices
using MatrixMapType = std::map<std::string, MatrixType>;
...
MatrixMapType matrixMap;
for (cont = 0; cont < nPares; cont++){
// read stuff
ResultFile >> FlowOri;
...
// read the matrix
MatrixType iPathMatrix(nPaths, MatrixRowType(largestPath + 2));
...
// save the matrix in the map keyed by FlowOri
matrixMap[FlowOri] = iPathMatrix;
}
Now later when you want to retrieve a matirx you just write matrixMap[something] where something is a variable with the name of the matrix you want to retrieve.
Variable names only have a meaning for the programmer and disappear from the executable unless you use a debug mode, so C++ does not allow to create dynamically named variables. Anyway even with languages that allow it, it is a terrible design.
But you can always create an array (or better a vector) of any object type. So if you want to store everything in the loop and process later the whole data, you could use a 3 level vector. With the magic of references, little has to be changed from your code:
std::vector<std::vector<std::vector<double>>> matrixes(nPares);
for (auto& iPathMatrix : matrixes) { // iPathMatrix is a reference inside matrixes
ResultFile >> FlowOri;
ResultFile >> FlowDest;
ResultFile >> nPaths;
ResultFile >> largestPath;
iPathMatrix = std::vector<std::vector<double>>(nPaths);
for (i = 0; i < nPaths; i++) {
iPathMatrix[i] = std::vector<double>(largestPath + 2];
}
for (i = 0; i < nPaths; i++) {
for (j = 0; j < largestPath + 2; j++) {
ResultFile >> iPathMatrix[i][j];
}
}
}
// control:
for (int i = 0; i < nPares; i++) {
for (int j = 0; j < matrixes[i].size(); j++) {
for (int k = 0; k < matrixes[i][j].size(); k++) {
std::cout << matrixes[i][j][k] << " ";
}
std::cout << '\n';
}
std::cout << '\n';
}
matrixes now contain all of your data
Related
Basically, I'm reading a file and trying to store the data in a 2D, for the differentiation between rows and columns I use the logic below:
int rows=0,column=0;
char arr[50][50];
while(my_file.eof()==0){
my_file.get(ch);
if(ch=='\n'){
rows++;
}
arr[rows][column]=ch;
column++;
}
for(int j=0;j<rows;j++){
for(int k=0;k<column;k++){
cout<<arr[j][k];}
}
But the when I run It shows the following output: https://i.stack.imgur.com/XzhST.png
And the text file data is:
I am going to school
hi!
Hello
guide me a bit...
Hmm, a 2D char array can indeed be used to store an number of lines, but you should control that you never try to store more than 50 characters for a single line, and that you never try to ouput more characters for a line than what it initially contained.
Here is a minimal fix of your code:
int rows = 0, column = 0;
char arr[50][50] = { {0 } }; // ensure the array is initialized with '\0' chars
for (;;) {
my_file.get(ch);
if (!my_file) break; // eof shall be tested AFTER a read operation
if (ch == '\n') {
rows++;
if (rows == 50) break; // no more than 50 lines
column = 0; // reset column index for next line
}
else if (column < 50) { // no more than 50 columns
arr[rows][column] = ch;
column++;
}
}
for (int j = 0; j < rows; j++) {
for (int k = 0; k < 50; k++) {
if (arr[j][k] == 0) break; // stop on end of line
std::cout << arr[j][k];
}
std::cout << '\n'; // and display the end of line
}
And as you have been said this is rather C-ish... I assume it is only for learning how 2D arrays can work.
As pointed out in comments, you'd be much better off using a std::vectorstd::string to store the strings.
But, this looks like a homework assignment to read then print each byte separately, so let's have a look... I'll add one of the ways this is usually done at the end of this post.
Your output looks like this:
It looks like you are displaying characters beyond the bondary of the strings, or that your strings are not null terminated... Turns out it's both.
Your code:
int rows = 0, column = 0;
char arr[50][50]; // <-- your array is not initialized, while that is not
// a big issue, filling the array with zeroes is easy:
// char arr[50][50] = {};
while (my_file.eof() == 0) {
my_file.get(ch);
if (ch == '\n') {
rows++; // <-- you pass to the next string, but do not put a
// null character to properly terminate your strings
// while this could have been avoided by initializing
// the array, it's best to do it explicitely.
// replace above line contents by:
arr[row][column] = '\0';
if (++row >= 50) // consider using named constants for the size of your array.
break; // No use keeping on reading strings if there is no
// more room to store them
}
arr[rows][column] = ch; // <-- I suspect a bunch un undefined stuff will
// start happening when column >= 50
column++;
// Try replacing above code with:
if (column < 50) // consider using named constants for the size of your array.
arr[rows][column++] = ch;
}
// make sure the last string is null terminated.
if (row < 50 && column < 50)
arr[row][column] = '\0';
// note that strings that are 50 bytes long are NOT null terminated.
// that's important to keep in mind, and only workss because we'll print
// byte by byte.
// your original print routine prints out all characters in the array, even
// stuff that was not in the original file...
for (int j = 0; j < rows; ++j){
for (int k=0 ; k < column; ++k){ // <-- you need to check for a null
// terminating character here...
// also, column is the length of the last
// string in the array. This is not a very
// useful value for displaying any other
// strings, is it?
// try this:
for (int k = 0; k < 50 && arr[j][k] != '\0'; ++k)
cout << arr[j][k];
}
cout << '\n'; // insert a newline after each string.
}
As you can tell, this is overly complex for doing a very common operation... Here's a more concise way of doing the same thing:
#include <vector>
#include <string>
#include <iostream>
#include <fstream>
int main()
{
std::vector<std::string> arr;
std::ifstream ifs("testfile.txt");
while (ifs && !ifs.eof())
{
std::string str;
std::getline(ifs, str);
arr.push_back(str);
}
for (size_t i = 0; i < arr.size(); ++i)
std::cout << arr[i] << '\n';
return 0;
}
Because you haven't compile the array yet
char arr[50][50];
for (int r = 0; r < 50; r++){
for (int c = 0; c < 50; c++){
arr[r][c] = ' ';}
}
My program opens a file which contains 100,000 numbers and parses them out into a 10,000 x 10 array correlating to 10,000 sets of 10 physical parameters. The program then iterates through each row of the array, performing overlap calculations between that row and every other row in the array.
The process is quite simple, and being new to c++, I programmed it the most straightforward way that I could think of. However, I know that I'm not doing this in the most optimal way possible, which is something that I would love to do, as the program is going to face off against my cohort's identical program, coded in Fortran, in a "race".
I have a feeling that I am going to need to implement multithreading to accomplish my goal of speeding up the program, but not only am I new to c++, I am new to multithreading, so I'm not sure how I should go about creating new threads in a beneficial way, or if it is even something that would give me that much "gain on investment" so to speak.
The program has the potential to be run on a machine with over 50 cores, but because the program is so simple, I'm not convinced that more threads is necessarily better. I think that if I implement two threads to compute the complex parameters of the two gaussians, one thread to compute the overlap between the gaussians, and one thread that is dedicated to writing to the file, I could speed up the program significantly, but I could also be wrong.
CODE:
cout << "Working...\n";
double **gaussian_array;
gaussian_array = (double **)malloc(N*sizeof(double *));
for(int i = 0; i < N; i++){
gaussian_array[i] = (double *)malloc(10*sizeof(double));
}
fstream gaussians;
gaussians.open("GaussParams", ios::in);
if (!gaussians){
cout << "File not found.";
}
else {
//generate the array of gaussians -> [10000][10]
int i = 0;
while(i < N) {
char ch;
string strNums;
string Num;
string strtab[10];
int j = 0;
getline(gaussians, strNums);
stringstream gaussian(strNums);
while(gaussian >> ch) {
if(ch != ',') {
Num += ch;
strtab[j] = Num;
}
else {
Num = "";
j += 1;
}
}
for(int c = 0; c < 10; c++) {
stringstream dbl(strtab[c]);
dbl >> gaussian_array[i][c];
}
i += 1;
}
}
gaussians.close();
//Below is the process to generate the overlap file between all gaussians:
string buffer;
ofstream overlaps;
overlaps.open("OverlapMatrix", ios::trunc);
overlaps.precision(15);
for(int i = 0; i < N; i++) {
for(int j = 0 ; j < N; j++){
double r1[6][2];
double r2[6][2];
double ol[2];
//compute complex parameters from the two gaussians
compute_params(gaussian_array[i], r1);
compute_params(gaussian_array[j], r2);
//compute overlap between the gaussians using the complex parameters
compute_overlap(r1, r2, ol);
//write to file
overlaps << ol[0] << "," << ol[1];
if(j < N - 1)
overlaps << " ";
else
overlaps << "\n";
}
}
overlaps.close();
return 0;
Any suggestions are greatly appreciated. Thanks!
i used to code in javascript, but my new school force me to learn c++.
Im kind new in this language, and here's the problem:
In javascript i can write such a code:
for(let i = 0; i < 10; i++){
var variable[i] = i+3;
}
for(let j = 0; j < 10; j++){
console.log(variable[j]);
}
You may say 'Why don't you just write the code into 1 for loop', but that's only example.
And now i'm trying to rewrite above code to cpp:
int n,k,w;
cin>>n>>k;
for(int i = 0; i < n; i++){
int w[i];
cin>>w[i];
}
//some code here
for(int i = 0; i < n; i++){
cout<<w[i];
}
And here's the question. How can i cout all variables w with index i, cause im getting an error [Error] invalid types 'int[int]' for array subscript.
What you probably want is:
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec;
int size = 0;
std::cin >> size;
for(int i = 0; i < size; i++){
int number = 0;
std::cin >> number;
vec.push_back(number);
}
for(int i : vec){
std::cout << i << " ";
}
}
std::vector<int> is a class designed to provide an interface to resizable array. The push_back() function appends the vector with given argument.
The last loop, which is called a ranged-based for(), is used to print all elements of the vector. You can replace it with plain old for() loop with indexing, since std::vector supports operator [], but if ranged-based approach is sufficient, it should be preferred.
EDIT: I don't know JavaScript, but I assume (from your example) that variables declared inside loops are visible everywhere. This is not the case in C++. Variables' visibility is dependent on the scope they are declared in. If you want your list/array/vector/any other container to be visible to those two for() loops, you have to declare it outside them - like in my example above.
EDIT2: While you should almost always use std::vector for such tasks, one could argue that they want to disable resizing the container. In this case, we are left with simple dynamic allocation. We reach for <memory> library, since we shouldn't manage it ourselves:
#include <iostream>
#include <memory>
int main() {
int size = 0;
std::cin >> size;
auto arr = std::make_unique<int[]>(size);
for(int i = 0; i < size; i++){
int number = 0;
std::cin >> number;
arr[i] = number;
}
for(int i = 0; i < size; i++){
std::cout << arr[i] << " ";
}
}
For auto, either read here or imagine that it's just a magic type that is (almost always) correct. It's like var in Python or JavaScript (but later on its type cannot be changed).
For std::unique_ptr<T[]>, either read here or imagine that it's just a dynamically allocated array that automatically delete[]s itself. If you did not learn about dynamic allocation yet, simply ignore what that means and wait until it's introduced.
Notice that we also got rid of the ranged-based for() loop. Unfortunately, it does not work with plain, dynamically allocated arrays.
Not all compilers support VLA so stick to the Standards; always specify a constant size for arrays. If you need some dynamically changed size then consider using another type of containers like: std::vector.
Also why you re-declared int w inside the for loop? It is local to for loop and changes to it won't affect the outer one.
You get a compile time error in the second loop that complains that w is not an array. To solve it make int w[] outer and on top of the two loops.
int n, k;
cin >> n >> k;
int w[n];
for(int i = 0; i < n; i++)
cin >> w[i];
//some code here
for(int i = 0; i < n; i++)
cout << w[i];
The alternative to VAL use std::vector:
std::vector<int> w;
int n, k;
std::cin >> n;
for(int i(0); i!= n; ++i){
std::cin >> k;
w.push_back(k);
}
for(auto i(0); i != w.length(); ++i)
std::cout << w[i] << ", ";
I've got a file that can be of any size and is a series of char values without any spaces between (except a blank space is treated as a blank cell of a grid).
xxxxxxx
xx xx
xxyyyxx
After some great help I've gone with the method to use a vector<vector<char> > however I cannot seem to populate it.
void readCourse(istream& fin) {
// using 3 and 7 to match example shown above
vector<vector<char> > data(3, vector<char>(7));
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 7; j++) {
fin.get(data[i][j]); // I believe the problem exists here
} // Does the .get() method work here?
} // Or does it need to be .push_back()?
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 7; j++) {
cout << data[i][j];
}
}
}
Is my method for populating my 2D vector valid? If not, can you please point me in the right direction?
I'd keep it simple and efficient with a single vector<char>:
vector<char> readCourse(istream& fin) {
vector<char> course(3*(7+2)); // 3x7 plus newlines
fin.read(course.data(), course.size());
course.resize(fin.gcount());
auto end = remove(course.begin(), course.end(), '\n');
end = remove(course.begin(), end, '\r');
course.erase(end, course.end()); // purge all \n and \r
return course;
}
That's a single input operation to get all the data, followed by removing the characters you don't need. You can then access the result in a 2D way like this:
course.at(x + y*7) // assuming width 7
That may seem a bit inconvenient, but it is efficient and compact--the overhead is always three pointers and a single heap allocation, instead of being proportional to the number of rows.
Solution I ended up using after ADT implementation:
void readCourse(std::istream& fin) {
std::vector<std::string> level
std::string line;
while(std::getline(fin, line) {
level.push_back(line);
}
for (std::size_t i = 0; i < 3; i++) {
for (std::size_t j = 0; j < 7; j++) {
std::cout << data[i][j];
}
std::cout << std::endl;
}
}
Basically i generated a adj_matrix and i want to make an adj_list from the adj_matrix...However I keep getting an error saying "no match for call..."
i tried it without aPair i still get the same error i can't seem to figure out what my problem is. Can anyone tell me why list isn't working? the list is at the very end of the code
int **gen_random_graph(int n)
{
srand(time(0));
int **adj_matrix = new int*[n];
for(int i = 0; i < n; i++)
{
for (int j = i; j < n; j++) //generating a N x N matrix based on the # of vertex input
{
adj_matrix[i] = new int[n];
}
}
for(int u = 0; u < n; u++)
{
for (int v = u; v < n; v++)
{
bool edgeOrNot = rand() % 2; //decide whether it has an edge or not
adj_matrix[u][v] = adj_matrix[v][u] = edgeOrNot;
if(adj_matrix[u][v] == true)
{
adj_matrix[v][u] = true;
if(u == v) //We can't have i = j in an undirected graph so we set it to false
{
adj_matrix[u][v] = -1;
}
}
else //if adj_matrix[u][v] is false set the symmetry to be false
{
adj_matrix[v][u] = adj_matrix[u][v] = -1;
}
}
}
for(int i = 0; i < n; i++)
{
for(int j = i; j < n; j++) //create the N x N with edges and sets the weight between the edge randomly
{
if(adj_matrix[i][j] == true)
{
int weight = rand() % 10 + 1;
adj_matrix[i][j] = adj_matrix[j][i] = weight;
cout << " ( " << i << "," << j << " ) " << "weight: " << adj_matrix[i][j] << endl;
}
}
}
for(int i = 0; i < n; i++)
{
vector<int> adj_list;
for(int j = i; j < n; j++)
{
if(adj_matrix[i][j] > 0)
{
int weight = adj_matrix[i][j];
adj_list.push_back(j);
cout << adj_list[i] << " " << endl;
}
}
}
print(n,adj_matrix);
return (adj_matrix);
}
I see that adj_list is not callable, so your code there is broken. There are a couple simple solutions to that. Taking a look at these docs, you may simply either access listObj.front() and listObj.back() OR you may also just create an iterator using listObj.begin() and iterating over the two elements (which may be desirable if you ever decide to put more than two elements in the list). See this tutorial for a simple example on creating an iterator for a list, in the code snippet right above the summary.
Note, here, your list object which I called listObj for simplicity/abstraction would simply be adj_matrix[i][j] in that bottom loop. That should fix your syntax error.
Also, aside from the syntax of your code, I don't get why you're trying to push weights to a list, then you're printing out and returning the adjacency matrix. I also don't get why you would use lists of pair objects when it seems like you only want to push integer weights onto it. For that, you can use a simple vector of integers (i.e.: vector <int> adj_list;)... or even simpler, you could use a simple array of integers... rather than using a vector of lists of pairs.
EDIT: After running the code locally and taking a look at the values, I realized the issue a bug in the OP's output was simply that he was using "true" in C++ in place of an integer, which was creating a bug, as explained in this SO post. The OP also has a further design decision to make where adjacency lists are concerned. More on what an adjacency list is, conceptually, found on Wikipedia.