I am working through Accelerated C++ by Andrew Koenig and Barbara Moo (2000) and am stuck on code from Chapter 4. I think this code reads an external data file containing exam, final and homework grades for multiple students and returns a course grade for each student.
I have downloaded solutions for the exercises from Andrew Koenig from GitHub:
https://github.com/bitsai/book-exercises/tree/master/Accelerated%20C%2B%2B
I can run the first example in Chapter 4 (main1.cc) which returns a course grade for a single student when the midterm, final and homework grades are entered from the keyboard. Here is an example:
data: harriet 85 95 88 87 93 45 76 99
student name = harriet
midterm grade = 85
final grade = 95
median of six homework grades (88, 87, 93, 45, 76, 99) = 87.5
final grade = 90
0.2 * 85 + 0.4 * 95 + 0.4 * 87.5 = 90
But I cannot run the second example (main2.cc) in which data are read for multiple students from an external file. No error messages appear when I create or run the main2.exe file. The cursor in the Windows 10 command window simply moves to the next line when I try to run main2.exe and nothing is displayed, not even the directory. Here are the lines returned when I make the executables:
c:\Users\mark_\myCppprograms\mychapter04>make
g++ main1.cc -o main1
g++ main2.cc -o main2
g++ -c -o main3.o main3.cc
g++ -c -o grade.o grade.cc
g++ -c -o median.o median.cc
g++ -c -o Student_info.o Student_info.cc
g++ main3.o grade.o median.o Student_info.o -o main3
The code in main2.cc is long. The third example in Chapter 4 (main3.cc) breaks this code into multiple C++ and header files but I cannot get the main3.exe file to return anything either.
Here is the code for main2.cc. I changed #include "../minmax.h" to #include "minmax.h" and put a file "minmax.h" in the same folder as main2.cc. The file "minmax.h" did not come from the aforementioned GitHub site and I paste its contents below.
#include <algorithm>
#include <iomanip>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>
#ifdef _MSC_VER
//#include "../minmax.h"
#include "minmax.h"
#else
using std::max;
#endif
using std::cin;
using std::cout;
using std::domain_error;
using std::endl;
using std::istream;
using std::ostream;
using std::setprecision;
using std::setw;
using std::sort;
using std::streamsize;
using std::string;
using std::vector;
struct Student_info {
string name;
double midterm, final;
vector<double> homework;
}; // note the semicolon--it's required
// compute the median of a `vector<double>'
// note that calling this function copies the entire argument `vector'
double median(vector<double> vec) {
#ifdef _MSC_VER
typedef std::vector<double>::size_type vec_sz;
#else
typedef vector<double>::size_type vec_sz;
#endif
vec_sz size = vec.size();
if (size == 0)
throw domain_error("median of an empty vector");
sort(vec.begin(), vec.end());
vec_sz mid = size/2;
return size % 2 == 0 ? (vec[mid] + vec[mid-1]) / 2 : vec[mid];
}
// compute a student's overall grade from midterm and final exam grades and homework grade
double grade(double midterm, double final, double homework) {
return 0.2 * midterm + 0.4 * final + 0.4 * homework;
}
// compute a student's overall grade from midterm and final exam grades
// and vector of homework grades.
// this function does not copy its argument, because `median' does so for us.
double grade(double midterm, double final, const vector<double>& hw) {
if (hw.size() == 0)
throw domain_error("student has done no homework");
return grade(midterm, final, median(hw));
}
double grade(const Student_info& s) {
return grade(s.midterm, s.final, s.homework);
}
// read homework grades from an input stream into a `vector<double>'
istream& read_hw(istream& in, vector<double>& hw) {
if (in) {
// get rid of previous contents
hw.clear();
// read homework grades
double x;
while (in >> x)
hw.push_back(x);
// clear the stream so that input will work for the next student
in.clear();
}
return in;
}
istream& read(istream& is, Student_info& s) {
// read and store the student's name and midterm and final exam grades
is >> s.name >> s.midterm >> s.final;
read_hw(is, s.homework); // read and store all the student's homework grades
return is;
}
bool compare(const Student_info& x, const Student_info& y) {
return x.name < y.name;
}
int main() {
vector<Student_info> students;
Student_info record;
string::size_type maxlen = 0;
// read and store all the records, and find the length of the longest name
while (read(cin, record)) {
maxlen = max(maxlen, record.name.size());
students.push_back(record);
}
// alphabetize the records
sort(students.begin(), students.end(), compare);
#ifdef _MSC_VER
for (std::vector<Student_info>::size_type i = 0;
#else
for (vector<Student_info>::size_type i = 0;
#endif
i != students.size(); ++i) {
// write the name, padded on the right to `maxlen' `+' `1' characters
cout << students[i].name
<< string(maxlen + 1 - students[i].name.size(), ' ');
// compute and write the grade
try {
double final_grade = grade(students[i]);
streamsize prec = cout.precision();
cout << setprecision(3) << final_grade
<< setprecision(prec);
} catch (domain_error e) {
cout << e.what();
}
cout << endl;
}
return 0;
}
The code for main1.cc, main2.cc and main3.cc all compiles using a single makefile and make statement. Here are the contents of makefile. I do not believe main2.cc uses any of the header files mentioned in this makefile but I did not make any changes to the makefile. I have not pasted the contents of any of these header files here. If they are relevant to main2.cc I can provide them on request or they are all available at the GitHub site above.
CXX = g++
CC = g++
all: main1 main2 main3
Student_info.o: Student_info.cc Student_info.h
grade.o: grade.cc grade.h median.h Student_info.h
main3.o: main3.cc grade.h median.h Student_info.h
median.o: median.cc median.h
main3: main3.o grade.o median.o Student_info.o
test: all
./main1 <../data/single_grade
./main2 <../data/single_grade
./main2 <../data/grades
./main3 <../data/grades
clobber:
rm -f *.o *.exe core main1 main2 main3
I have created a subfolder called data and put two data files in it: grades and single_grade. Here are the contents of grades:
Moo 100 100 100 100 100 100 100 100
Moore 75 85 77 59 0 85 75 89
Norman 57 78 73 66 78 70 88 89
Olson 89 86 70 90 55 73 80 84
Peerson 47 70 82 73 50 87 73 71
Russel 72 87 88 54 55 82 69 87
Thomas 90 96 99 99 100 81 97 97
Vaughn 81 97 99 67 40 90 70 96
Westerly 43 98 96 79 100 82 97 96
Baker 67 72 73 40 0 78 55 70
Davis 77 70 82 65 70 77 83 81
Edwards 77 72 73 80 90 93 75 90
Franklin 47 70 82 73 50 87 73 71
Jones 77 82 83 50 10 88 65 80
Harris 97 90 92 95 100 87 93 91
Smith 87 92 93 60 0 98 75 90
Carpenter 47 90 92 73 100 87 93 91
Fail1 45 55 65 80 90 70 65 60
Fail2 55 55 65 50 55 60 65 60
Here are the contents of single_grade:
harriet 85 95 88 87 93 45 76 99
The only place I find these two data files mentioned in any of the above code is in the makefile which confuses me, but I guess the makefile associates main2.cc and the two data files.
Here are the contents of "minmax.h":
/**
* This file has no copyright assigned and is placed in the Public Domain.
* This file is part of the mingw-w64 runtime package.
* No warranty is given; refer to the file DISCLAIMER.PD within this package.
*/
#ifndef _INC_MINMAX
#define _INC_MINMAX
#ifndef __cplusplus
#ifndef NOMINMAX
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
#endif
#endif
#endif
Here is what is returned by c++ -v on my Windows 10 laptop:
c:\Users\mark_\myCppprograms>c++ -v
Using built-in specs.
COLLECT_GCC=c++
COLLECT_LTO_WRAPPER=c:/rtools/MINGW_64/bin/../libexec/gcc/x86_64-w64-mingw32/4.9.3/lto-wrapper.exe
Target: x86_64-w64-mingw32
Configured with: ../../../src/gcc-4.9.3/configure --host=x86_64-w64-mingw32 --build=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 --prefix=/mingw64 --with-sysroot=/home/Jeroen/mingw-gcc-4.9.3/x86_64-493-posix-seh-rt_v3-s/mingw64 --with-gxx-include-dir=/mingw64/x86_64-w64-mingw32/include/c++ --enable-static --disable-shared --disable-multilib --enable-languages=c,c++,fortran,lto --enable-libstdcxx-time=yes --enable-threads=posix --enable-libgomp --enable-libatomic --enable-lto --enable-graphite --enable-checking=release --enable-fully-dynamic-string --enable-version-specific-runtime-libs --disable-isl-version-check --disable-cloog-version-check --disable-libstdcxx-pch --disable-libstdcxx-debug --enable-bootstrap --disable-rpath --disable-win32-registry --disable-nls --disable-werror --disable-symvers --with-gnu-as --with-gnu-ld --with-arch=nocona --with-tune=core2 --with-libiconv --with-system-zlib --with-gmp=/home/Jeroen/mingw-gcc-4.9.3/prerequisites/x86_64-w64-mingw32-static --with-mpfr=/home/Jeroen/mingw-gcc-4.9.3/prerequisites/x86_64-w64-mingw32-static --with-mpc=/home/Jeroen/mingw-gcc-4.9.3/prerequisites/x86_64-w64-mingw32-static --with-isl=/home/Jeroen/mingw-gcc-4.9.3/prerequisites/x86_64-w64-mingw32-static --with-cloog=/home/Jeroen/mingw-gcc-4.9.3/prerequisites/x86_64-w64-mingw32-static --enable-cloog-backend=isl --with-pkgversion='x86_64-posix-seh, Built by MinGW-W64 project' --with-bugurl=http://sourceforge.net/projects/mingw-w64 CFLAGS='-O2 -pipe -I/home/Jeroen/mingw-gcc-4.9.3/x86_64-493-posix-seh-rt_v3-s/mingw64/opt/include -I/home/Jeroen/mingw-gcc-4.9.3/prerequisites/x86_64-zlib-static/include -I/home/Jeroen/mingw-gcc-4.9.3/prerequisites/x86_64-w64-mingw32-static/include' CXXFLAGS='-O2 -pipe -I/home/Jeroen/mingw-gcc-4.9.3/x86_64-493-posix-seh-rt_v3-s/mingw64/opt/include -I/home/Jeroen/mingw-gcc-4.9.3/prerequisites/x86_64-zlib-static/include -I/home/Jeroen/mingw-gcc-4.9.3/prerequisites/x86_64-w64-mingw32-static/include' CPPFLAGS= LDFLAGS='-pipe -L/home/Jeroen/mingw-gcc-4.9.3/x86_64-493-posix-seh-rt_v3-s/mingw64/opt/lib -L/home/Jeroen/mingw-gcc-4.9.3/prerequisites/x86_64-zlib-static/lib -L/home/Jeroen/mingw-gcc-4.9.3/prerequisites/x86_64-w64-mingw32-static/lib '
Thread model: posix
gcc version 4.9.3 (x86_64-posix-seh, Built by MinGW-W64 project)
c:\Users\mark_\myCppprograms>
I am aware that other people have uploaded solutions to Accelerated C++ exercises. I have looked at several. But I have not been able to get any of them to run with main2.cc or main3.cc and return the expected results.
I'm not sure how you actually run it, but in my case it works perfectly fine. If you take a closer look at main in main2.cc, you'll notice that there's a blocking read call, which causes the program to wait for user input. Take a look at test target from makefile:
test: all
./main1 <../data/single_grade
./main2 <../data/single_grade
./main2 <../data/grades
./main3 <../data/grades
< means that we'll be redirecting what's in single_grade to the process being run. It's implicitly assumed that in folder above to the executable binary will be a data directory with single_grade data file. So, when you run $ make test, you'll notice that everything works as expected (assuming the directory structure is unchanged). If you simply run $ ./main2, nothing is gonna happen as the program awaits for input. Or, assuming your data file is next to main2 binary, you could run $ main2 < single_grade. Or, alternatively, you could omit the files at all:
$ ./main2
$ Moo 100 100 100 100 100 100 100 100
$ Moore 75 85 77 59 0 85 75 89
$ EOF (in bash shell it's CTRL + D, on windows cmd: CTRL + Z)
Which yields:
Moo 100
Moore 79.4
Related
I was trying to create a program to print table of 12 using recursion as I wrote a simple program for this I did get table, but table was instead upto 144 (12times12=144) instead of 120(12times10=120) I am sharing my code and output with you guys I was writing code in C++
//we will print table of 12 using concept of recursion
//a table of 12 is like this
//12 24 36 48 60 72 84 96 108 120
#include<iostream>
using namespace std;
void table(int n)
{
if(n==1)
{
cout<<12<<"\n";
return;
}
table(n-1);
cout<<n*12<<"\n";
}
int main(void)
{
table(12);
}
and now here is out put of this program
12
24
36
48
60
72
84
96
108
120
132
144
please help me what I'm missing here I am positive that adding some condition will help I tried one adding if(n==12) { return;} but it prevents does nothing as in the end it is return n*12
Short Version of the Question
If I'm reading in data like so:
while (in >> x) {
hw.push_back(x);
}
// clear the stream so that input will work for the next student
in.clear();
where in is a std::istream, x is a double and hw is a vector<double>. Wouldn't I need to put back whatever read attempt caused me to break out of the while loop? Otherwise, wouldn't my next read from in skip some data?
Full Question
I'm trying to read from a text file that contains a string and a series of numbers. I'm processing this data into a struct which contains member attributes for this data.
The input data looks as follows:
Moore 75 85 77 59 0 85 75 89
This data represents a student's name, their final exam grade, their midterm exam grade, and some homework.
And to read such data in, I have the following:
#include <boost/format.hpp>
#include <iostream>
#include <string>
using std::istream;
using std::vector;
using std::cout;
using std::string;
using std::cin;
struct Student_info {
std::string name;
double midterm, final;
std::vector<double> homework;
};
istream& read(istream&, Student_info&);
istream& read_hw(istream&, vector<double>&);
istream& read(istream& is, Student_info& s) {
// Read and store th studen's name and midterm and final exam grades
is >> s.name >> s.midterm >> s.final;
read_hw(is, s.homework); // read and store all the student's homework grades
return is;
}
istream& read_hw(istream& in, vector<double>& hw)
{
if (in) {
// get rid of previous contents
hw.clear();
// read homework grades
double x;
while (in >> x) {
hw.push_back(x);
}
// clear the stream so that input will work for the next student
in.clear();
}
return in;
}
In short, and if my understanding is correct, I first read the name, then two doubles (final and midterm exam) and then however many homeworks are present.
I know when to stop reading into a vector<double> of homework grades with the following:
while (in >> x) {
hw.push_back(x);
}
// clear the stream so that input will work for the next student
in.clear();
This all looks perfectly sensible to me, but when I read in a series of data lines, the data does not get read in properly.
For example, with the following input:
Moo 100 100 100 100 100 100 100 100
Moore 75 85 77 59 0 85 75 89
Norman 57 78 73 66 78 70 88 89
I get the following output:
Name: Moo, Midterm: 100, Final: 100, Num HW: 6
Name: Moore, Midterm: 75, Final: 85, Num HW: 6
Name: orman, Midterm: 57, Final: 78, Num HW: 6
Notice the name is orman, NOT Norman. The N is missing. That's not a typo, that's the problem I'm trying to understand.
It would seem to me I need to "unget", though when I try to literally call in.unget() it doesn't improve things.
Below is some full input data and the complete source for a driver program if anyone wants to try this out in their hands:
Full Input Data
Moo 100 100 100 100 100 100 100 100
Moore 75 85 77 59 0 85 75 89
Norman 57 78 73 66 78 70 88 89
Olson 89 86 70 90 55 73 80 84
Peerson 47 70 82 73 50 87 73 71
Russel 72 87 88 54 55 82 69 87
Thomas 90 96 99 99 100 81 97 97
Vaughn 81 97 99 67 40 90 70 96
Westerly 43 98 96 79 100 82 97 96
Baker 67 72 73 40 0 78 55 70
Davis 77 70 82 65 70 77 83 81
Edwards 77 72 73 80 90 93 75 90
Franklin 47 70 82 73 50 87 73 71
Jones 77 82 83 50 10 88 65 80
Harris 97 90 92 95 100 87 93 91
Smith 87 92 93 60 0 98 75 90
Carpenter 47 90 92 73 100 87 93 91
Fail1 45 55 65 80 90 70 65 60
Fail2 55 55 65 50 55 60 65 60
Full Source of Driver Program
#include <boost/format.hpp>
#include <iostream>
#include <string>
using std::istream;
using std::vector;
using std::cout;
using std::string;
using std::cin;
struct Student_info {
std::string name;
double midterm, final;
std::vector<double> homework;
};
istream& read(istream&, Student_info&);
istream& read_hw(istream&, vector<double>&);
istream& read(istream& is, Student_info& s) {
// Read and store th studen's name and midterm and final exam grades
is >> s.name >> s.midterm >> s.final;
read_hw(is, s.homework); // read and store all the student's homework grades
return is;
}
istream& read_hw(istream& in, vector<double>& hw)
{
if (in) {
// get rid of previous contents
hw.clear();
// read homework grades
double x;
while (in >> x) {
hw.push_back(x);
}
// clear the stream so that input will work for the next student
in.clear();
}
return in;
}
int main() {
vector<Student_info> students;
Student_info record;
string::size_type maxlen = 0;
while (read(cin, record)) {
// find length of longest name
cout << boost::format("Name: %1%, Midterm: %2%, Final: %3%, Num HW: %4%\n") % record.name % record.midterm % record.final % record.homework.size();
students.push_back(record);
}
return 0;
}
Using the full input data, the output looks like this (notice many names have been incorrectly):
Name: Moo, Midterm: 100, Final: 100, Num HW: 6
Name: Moore, Midterm: 75, Final: 85, Num HW: 6
Name: orman, Midterm: 57, Final: 78, Num HW: 6
Name: Olson, Midterm: 89, Final: 86, Num HW: 6
Name: rson, Midterm: 47, Final: 70, Num HW: 6
Name: Russel, Midterm: 72, Final: 87, Num HW: 6
Name: Thomas, Midterm: 90, Final: 96, Num HW: 6
Name: Vaughn, Midterm: 81, Final: 97, Num HW: 6
Name: Westerly, Midterm: 43, Final: 98, Num HW: 6
Name: ker, Midterm: 67, Final: 72, Num HW: 6
Name: vis, Midterm: 77, Final: 70, Num HW: 6
Name: wards, Midterm: 77, Final: 72, Num HW: 6
Name: ranklin, Midterm: 47, Final: 70, Num HW: 6
Name: Jones, Midterm: 77, Final: 82, Num HW: 6
Name: Harris, Midterm: 97, Final: 90, Num HW: 6
Name: Smith, Midterm: 87, Final: 92, Num HW: 6
Name: rpenter, Midterm: 47, Final: 90, Num HW: 6
Name: l1, Midterm: 45, Final: 55, Num HW: 6
Name: l2, Midterm: 55, Final: 55, Num HW: 6
Update 1
I tried adding in.seekg(-1, in.cur); after breaking out of the following while loop:
double x;
while (in >> x) {
hw.push_back(x);
}
// Going to try and get the istream back to where it was when I broke out of the while loop.
in.seekg(-1, in.cur);
// clear the stream so that input will work for the next student
in.clear();
Thinking this would take me back to whatever caused me to break out of the while loop. But still Student names are still not being read in correctly
Update 2
I see there is a nearly identical question here:
Why is istream.clear() removing part of my strings while reading doubles and strings?
However the accepted solution does not explain why what is being done here is wrong -- it just offers a workaround.
Update 3
I appreciate all the workarounds, but consider this more focused question, why doesn't every subsequent line have a letter missing here or there? Only some lines do.
The reason for the weird extraction is that the letters ABCDEFINP can occur in a double and the others can't. See strtof spec for detail.
This is a fundamental problem with stream I/O without lookahead. The standard specifies (roughly speaking) that extraction continues until finding a character that can't occur in the destination type, and then try to convert what was extracted. There have been various tweaks to the spec (including changing the list of valid characters for a double) over the years but no real solution.
There's no provision to put back characters on conversion failure , you will have to use a different extraction method. As suggested in the other answer: since your input is line-oriented (i.e. newlines are significant) it would be good to use a line-oriented read function to read a line, and then parse a line. Your method of using >> until error has no way of breaking at newlines (that operator treats all whitespace as identical).
There's usually no need to use unget() on standard streams. The problem you have is that you need to know when to stop reading a line. The function std::getline is made for this purpose. You can iterate through each line, store that line in a std::istringstream, and parse out the record from there:
std::istream& read_hw(std::istream& in, std::vector<double>& hw) {
hw.clear();
std::string line;
if (std::getline(in, line)) {
hw.assign(
std::istream_iterator<double>{std::istringstream{line} >> std::skipws}, {}
);
}
return in;
}
I was asked to calculate the average of marks for 10 students.
First, I was able to read and retrieve the data from data.txt file which looks like this:
No. Name Test1 Test2 Test3
1 Ahmad 58 97 83
2 Dollah 78 76 70
3 Ramesh 85 75 84
4 Maimunah 87 45 74
5 Robert 74 68 97
6 Kumar 77 73 45
7 Intan 56 23 27
8 Ping 74 58 18
9 Idayu 47 98 95
10 Roslan 79 98 78
Then I have to calculate the average for each student and determine the grades.
Here are what I've done so far.
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
using namespace std;
int main()
{
ifstream inFile1;
string temp;
int line=0;
inFile1.open("data.txt");
if(inFile1.fail())
{
cout << "File cannot be opened" << endl;
exit(1);
}
while(getline(inFile1, temp))
{
line++;
}
inFile1.close();
return 0;
}
This program should at least consists two prototype function: average() and grade().
This is where I got stuck.
You can check the answers here: find average salaries from file in c++.
Basically when you iterate through the file lines you should split the temp string into tokens you are interested in. How? An option would be to use getline with the delimeter ' ' or look into the std::noskipws stream manipulator or simply use operator>> to read from the file - depends on the details of your requirements.
If I correctly understand your case, I'd go with the operator>> to get the name of the student and then read using getline(inFile, gradesText) to read until end of line to get all grades for the current student.
Then I'd use a separate function to split the strings into a vector of grades. How to do the splitting you can check in Split a string in C++?. This way you could prepare a function like vector<int> split(const string& line, char delim = ' '). Within the implementation you should probably use std::stoi for the string-to-int conversion.
Afterwards, when you already have a proper collection you can calculate the mean from it with:
const double sum = std::accumulate(grades.begin(), grades.end(), 0.0);
const double gradesMean = sum / grades.size();
I've been racking my brain trying to get this information from a text doc into a few different arrays. The number before each name in the txt doc is the identification number, I want to put all these into a single double array. Then put every name into a single string array. Then finally put the numbers after each name into a double 2d array with 50 rows (one for each name) and 7 columns (for the seven scores/numbers for each client). I'm not asking for anyone to do my homework for me, I just need some info on how to get started.
using namespace std;
int main() { ifstream file("client_info.txt");
string txtArray[450];
for (int i = 0; i < 450; ++i)
{
file >> txtArray[i];
}
I thought maybe I'd put all of the text into a string array then split that array into several other arrays, but realized it would be difficult to use strings, since I need the numbers to be doubles for later when I'm finding the average of the clients scores.
Here is the txt doc:
93 SMITH 739.15 634.36 257.02 639.32 376.75 360.56 666.96 81 JOHNSON 888.08 975.86 672.78 176.35 114.58 511.24 502.56 50 WILLIAMS 222.27 171.83 232.83 609.79 726.69 444.89 520.63 32 JONES 343.13 687.73 931.93 72.36 183.93 486.3 90.09 68 BROWN 623.39 968.13 67.59 528.93 703.95 329.02 875.95 24 DAVIS 97.48 296.61 568.49 990.18 448.36 567.52 179.42 21 MILLER 147.68 38.87 64.78 463.19 172.39 914.68 827.42 90 WILSON 687.7 595.19 930.52 77.27 877.45 774.44 599.83 29 MOORE 739.33 402 825.29 859.63 937.14 405.2 89.22 12 TAYLOR 976.11 531.4 731.45 815.16 518.26 858.86 832.34 31 ANDERSON 133.12 355.22 517.53 926.54 552.05 932.52 745.75 89 THOMAS 217.72 266.14 622.99 541.35 618.49 268.9 243.63 87 JACKSON 352.81 772.31 109.43 139.14 430.43 625.92 207.79 46 WHITE 650.79 367.65 915.68 848.85 912.44 603.15 704.01 75 HARRIS 708.38 70.53 34.45 409.82 288.28 735.06 140.9 85 MARTIN 701.73 643.16 766.3 198.92 805.86 802.39 239.76 67 THOMPSON 993.9 274.75 72.87 928.41 208.81 260.42 5.56 52 GARCIA 871.48 646.48 914.77 98.61 724.86 680.7 363.15 60 MARTINEZ 293.38 448.24 985.08 135.2 277.77 705.58 567.81 69 ROBINSON 914.18 688.95 112.81 270.18 950.27 607.49 915.75 76 CLARK 956.12 110.6 820.53 140.97 906.2 529.52 75.24 82 RODRIGUEZ 224.88 324.32 672.74 502.27 768.99 116.42 880.86 39 LEWIS 805.89 274.54 211.14 82.04 804.41 259.69 408.08 48 LEE 80.06 381.7 975.29 448.33 578.49 548.19 818.85 26 WALKER 657.74 0.74 741.06 533.84 887.36 38.35 619.17 55 HALL 266.9 46.42 825.89 986.01 146.96 349.07 386.64 100 ALLEN 293.22 423.57 150.53 519.25 16.96 65.54 688.44 11 YOUNG 870.69 192.46 82.19 92.46 971.38 156.49 16.48 57 HERNANDEZ 145.33 123.45 860.78 521.86 739.9 138.88 169.33 96 KING 411.31 340.93 447.04 14.26 744.1 425.83 57.87 4 WRIGHT 503.48 488.13 603.12 198.14 425.51 216.28 49.75 64 LOPEZ 296.99 744.89 270.49 138.19 897.06 374.89 831.66 62 HILL 910.95 676.68 442.98 961.03 567.6 739.49 225.26 37 SCOTT 970.31 468.48 788.85 903.66 897.93 124.04 983.01 34 GREEN 260.42 714.42 496.13 492.39 170.17 999.36 890.8 51 ADAMS 212.36 115.84 308.57 741.29 780.3 193.71 423.82 40 BAKER 316.91 671.36 398.53 190.99 424.34 457.68 584.16 47 GONZALEZ 947.9 348.88 299.11 71.82 727.49 480.59 891.51 3 NELSON 160.13 962.1 903.76 107.34 127.07 844.07 575.1 36 CARTER 981.92 250.09 5.39 866.43 182.93 135.12 224.91 78 MITCHELL 805.83 181.19 549.25 815.72 776.2 887.33 144.86 28 PEREZ 144.04 616.81 637.07 342.41 818.58 901.72 104.02 8 ROBERTS 880.38 62.34 591.34 721.18 184.64 378.08 439.94 99 TURNER 21.83 227.82 378.42 680.24 336.24 703.13 52.36 2 PHILLIPS 664.1 879.16 811.4 842.3 463.96 446.52 919.31 17 CAMPBELL 392.91 26.12 591.74 766.1 30.91 108.24 863.81 33 PARKER 359.87 606.99 61.67 188.85 474.87 159.02 907.38 30 EVANS 770.78 70.1 724.89 490.02 667.93 116.4 938.55 70 EDWARDS 507.59 698.53 15.5 251.9 340.84 246.6 233.04 44 COLLINS 803.53 580.38 966.57 941.38 249.58 562.3 725.05
To make a multideminsional array use
type arrayName [x][y];
The first number is row, second is column. You can use arrayName[0][x] to set the names you mentioned, assuming you use each row for a single name and whatever properties belong to that name. Hope this helps :)
With error checking omitted:
const int NUM_PERSONS = 50;
const int SCORES_PER_PERSON = 7;
double scores[NUM_PERSONS][SCORES_PER_PERSON];
int ids[NUM_PERSONS];
std::string names[NUM_PERSONS];
for(int i = 0; i < NUM_PERSONS; ++i) {
file >> ids[i] >> names[i];
for(int j = 0; j < SCORES_PER_PERSON; ++j) {
file >> scores[i][j];
}
}
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
I am currently trying to understand how the following code (http://pastebin.com/zTHUrmyx) works, my approach is currently compiling the software in debug and using gdb to step through the code.
However, I'm running into the problem that 'step' does not always tell me what is going on. Particularly unclear to me is the EXECUTE {...} which I cannot step into.
How do I go about learning what the code is doing?
1 /*
2 Copyright 2008 Brain Research Institute, Melbourne, Australia
3
4 Written by J-Donald Tournier, 27/06/08.
5
6 This file is part of MRtrix.
7
8 MRtrix is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 MRtrix is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with MRtrix. If not, see <http://www.gnu.org/licenses/>.
20
21
22 15-10-2008 J-Donald Tournier <d.tournier#brain.org.au>
23 * fix -prs option handling
24 * remove MR::DICOM_DW_gradients_PRS flag
25
26 15-10-2008 J-Donald Tournier <d.tournier#brain.org.au>
27 * add -layout option to manipulate data ordering within the image file
28
29 14-02-2010 J-Donald Tournier <d.tournier#brain.org.au>
30 * fix -coord option so that the "end" keyword can be used
31
32
33 */
34
35 #include "app.h"
36 #include "image/position.h"
37 #include "image/axis.h"
38 #include "math/linalg.h"
39
40 using namespace std;
41 using namespace MR;
42
43 SET_VERSION_DEFAULT;
44
45 DESCRIPTION = {
46 "perform conversion between different file types and optionally extract a subset of the input image.",
47 "If used correctly, this program can be a very useful workhorse. In addition to converting images between different formats, it can be used to extract specific studies from a data set, extract a specific region of interest, flip the images, or to scale the intensity of the images.",
48 NULL
49 };
50
51 ARGUMENTS = {
52 Argument ("input", "input image", "the input image.").type_image_in (),
53 Argument ("ouput", "output image", "the output image.").type_image_out (),
54 Argument::End
55 };
56
57
58 const gchar* type_choices[] = { "REAL", "IMAG", "MAG", "PHASE", "COMPLEX", NULL };
59 const gchar* data_type_choices[] = { "FLOAT32", "FLOAT32LE", "FLOAT32BE", "FLOAT64", "FLOAT64LE", "FLOAT64BE",
60 "INT32", "UINT32", "INT32LE", "UINT32LE", "INT32BE", "UINT32BE",
61 "INT16", "UINT16", "INT16LE", "UINT16LE", "INT16BE", "UINT16BE",
62 "CFLOAT32", "CFLOAT32LE", "CFLOAT32BE", "CFLOAT64", "CFLOAT64LE", "CFLOAT64BE",
63 "INT8", "UINT8", "BIT", NULL };
64
65 OPTIONS = {
66 Option ("coord", "select coordinates", "extract data only at the coordinates specified.", false, true)
67 .append (Argument ("axis", "axis", "the axis of interest").type_integer (0, INT_MAX, 0))
68 .append (Argument ("coord", "coordinates", "the coordinates of interest").type_sequence_int()),
69
70 Option ("vox", "voxel size", "change the voxel dimensions.")
71 .append (Argument ("sizes", "new dimensions", "A comma-separated list of values. Only those values specified will be changed. For example: 1,,3.5 will change the voxel size along the x & z axes, and leave the y-axis voxel size unchanged.")
72 .type_sequence_float ()),
73
74 Option ("datatype", "data type", "specify output image data type.")
75 .append (Argument ("spec", "specifier", "the data type specifier.").type_choice (data_type_choices)),
76
77 Option ("scale", "scaling factor", "apply scaling to the intensity values.")
78 .append (Argument ("factor", "factor", "the factor by which to multiply the intensities.").type_float (NAN, NAN, 1.0)),
79
80 Option ("offset", "offset", "apply offset to the intensity values.")
81 .append (Argument ("bias", "bias", "the value of the offset.").type_float (NAN, NAN, 0.0)),
82
83 Option ("zero", "replace NaN by zero", "replace all NaN values with zero."),
84
85 Option ("output", "output type", "specify type of output")
86 .append (Argument ("type", "type", "type of output.")
87 .type_choice (type_choices)),
88
89 Option ("layout", "data layout", "specify the layout of the data in memory. The actual layout produced will depend on whether the output image format can support it.")
90 .append (Argument ("spec", "specifier", "the data layout specifier.").type_string ()),
91
92 Option ("prs", "DW gradient specified as PRS", "assume that the DW gradients are specified in the PRS frame (Siemens DICOM only)."),
93
94 Option::End
95 };
96
97
98
99 inline bool next (Image::Position& ref, Image::Position& other, const std::vector<int>* pos)
100 {
101 int axis = 0;
102 do {
103 ref.inc (axis);
104 if (ref[axis] < ref.dim(axis)) {
105 other.set (axis, pos[axis][ref[axis]]);
106 return (true);
107 }
108 ref.set (axis, 0);
109 other.set (axis, pos[axis][0]);
110 axis++;
111 } while (axis < ref.ndim());
112 return (false);
113 }
114
115
116
117
118
119 EXECUTE {
120 std::vector<OptBase> opt = get_options (1); // vox
121 std::vector<float> vox;
122 if (opt.size())
123 vox = parse_floats (opt[0][0].get_string());
124
125
126 opt = get_options (3); // scale
127 float scale = 1.0;
128 if (opt.size()) scale = opt[0][0].get_float();
129
130 opt = get_options (4); // offset
131 float offset = 0.0;
132 if (opt.size()) offset = opt[0][0].get_float();
133
134 opt = get_options (5); // zero
135 bool replace_NaN = opt.size();
136
137 opt = get_options (6); // output
138 Image::OutputType output_type = Image::Default;
139 if (opt.size()) {
140 switch (opt[0][0].get_int()) {
141 case 0: output_type = Image::Real; break;
142 case 1: output_type = Image::Imaginary; break;
143 case 2: output_type = Image::Magnitude; break;
144 case 3: output_type = Image::Phase; break;
145 case 4: output_type = Image::RealImag; break;
146 }
147 }
148
149
150
151
152 Image::Object &in_obj (*argument[0].get_image());
153
154 Image::Header header (in_obj);
155
156 if (output_type == 0) {
157 if (in_obj.is_complex()) output_type = Image::RealImag;
158 else output_type = Image::Default;
159 }
160
161 if (output_type == Image::RealImag) header.data_type = DataType::CFloat32;
162 else if (output_type == Image::Phase) header.data_type = DataType::Float32;
163 else header.data_type.unset_flag (DataType::ComplexNumber);
164
165
166 opt = get_options (2); // datatype
167 if (opt.size()) header.data_type.parse (data_type_choices[opt[0][0].get_int()]);
168
169 for (guint n = 0; n < vox.size(); n++)
170 if (isfinite (vox[n])) header.axes.vox[n] = vox[n];
171
172 opt = get_options (7); // layout
173 if (opt.size()) {
174 std::vector<Image::Axis> ax = parse_axes_specifier (header.axes, opt[0][0].get_string());
175 if (ax.size() != (guint) header.axes.ndim())
176 throw Exception (String("specified layout \"") + opt[0][0].get_string() + "\" does not match image dimensions");
177
178 for (guint i = 0; i < ax.size(); i++) {
179 header.axes.axis[i] = ax[i].axis;
180 header.axes.forward[i] = ax[i].forward;
181 }
182 }
183
184
185 opt = get_options (8); // prs
186 if (opt.size() && header.DW_scheme.rows() && header.DW_scheme.columns()) {
187 for (guint row = 0; row < header.DW_scheme.rows(); row++) {
188 double tmp = header.DW_scheme(row, 0);
189 header.DW_scheme(row, 0) = header.DW_scheme(row, 1);
190 header.DW_scheme(row, 1) = tmp;
191 header.DW_scheme(row, 2) = -header.DW_scheme(row, 2);
192 }
193 }
194
195 std::vector<int> pos[in_obj.ndim()];
196
197 opt = get_options (0); // coord
198 for (guint n = 0; n < opt.size(); n++) {
199 int axis = opt[n][0].get_int();
200 if (pos[axis].size()) throw Exception ("\"coord\" option specified twice for axis " + str (axis));
201 pos[axis] = parse_ints (opt[n][1].get_string(), header.dim(axis)-1);
202 header.axes.dim[axis] = pos[axis].size();
203 }
204
205 for (int n = 0; n < in_obj.ndim(); n++) {
206 if (pos[n].empty()) {
207 pos[n].resize (in_obj.dim(n));
208 for (guint i = 0; i < pos[n].size(); i++) pos[n][i] = i;
209 }
210 }
211
212
213 in_obj.apply_scaling (scale, offset);
214
215
216
217
218
219
220 Image::Position in (in_obj);
221 Image::Position out (*argument[1].get_image (header));
222
223 for (int n = 0; n < in.ndim(); n++) in.set (n, pos[n][0]);
224
225 ProgressBar::init (out.voxel_count(), "copying data...");
226
227 do {
228
229 float re, im = 0.0;
230 in.get (output_type, re, im);
231 if (replace_NaN) if (gsl_isnan (re)) re = 0.0;
232 out.re (re);
233
234 if (output_type == Image::RealImag) {
235 if (replace_NaN) if (gsl_isnan (im)) im = 0.0;
236 out.im (im);
237 }
238
239 ProgressBar::inc();
240 } while (next (out, in, pos));
241
242 ProgressBar::done();
243 }
As was noted in the comments, EXECUTE seems to be a macro, apparent from the context a function header (and maybe a bit more, e.g. some global variables and functions), so the part in curly braces is the function body.
To get to the definition of EXECUTE, you will have to examine the headers.
However, if you can reach some part of the code during debugging, you could insert a string or char[] at that point, giving it the stringified version of EXECUTE, so you get whatever the preprocessor will emit for EXECUTE at that position in the code.
#define STR(x) #x
#define STRINGIFY(x) STR(x)
char c[] = STRINGIFY(EXECUTE);
the two macros are a known little macro trick to get the content of any macro as a string literal. Try it out and inspect the char array in your debugger to get the content of execute.
My wild guess here: EXECUTE is the main function or a replacement for it, the OPTIONS and ARGUMENTS describe what arguments the program expects and what command line options you can pass to it. Those macros and some of the used functions and variables (get_options, argument) are part of a little framework that should facilitate the usage, evaluation and user information about command line options.