#c #makefile
#c #makefile
Вопрос:
Я работаю с ускоренным C Эндрю Кенига и Барбары Му (2000) и застрял на коде из главы 4. Я думаю, что этот код считывает внешний файл данных, содержащий оценки за экзамен, итоговую и домашнюю работу для нескольких студентов, и возвращает оценку за курс для каждого студента.
Я загрузил решения для упражнений от Эндрю Кенига с GitHub:
https://github.com/bitsai/book-exercises/tree/master/Accelerated C++
Я могу запустить первый пример из главы 4 ( main1.cc
), который возвращает оценку курса для одного студента, когда промежуточные, итоговые оценки и домашние задания вводятся с клавиатуры. Вот пример:
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
Но я не могу запустить второй пример ( main2.cc
), в котором данные считываются для нескольких учащихся из внешнего файла. При создании или запуске main2.exe
файла сообщения об ошибках не появляются. Курсор в окне командной строки Windows 10 просто перемещается на следующую строку, когда я пытаюсь запустить main2.exe
и ничего не отображается, даже каталог. Вот строки, возвращаемые при создании исполняемых файлов:
c:Usersmark_myCppprogramsmychapter04>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
Код в main2.cc
длинный. Третий пример в главе 4 ( main3.cc
) разбивает этот код на несколько C
и header
файлов, но я также не могу заставить main3.exe
файл возвращать что-либо.
Вот код для main2.cc
. Я изменил #include "../minmax.h"
на #include "minmax.h"
и поместил файл "minmax.h"
в ту же папку, что и main2.cc
. Файл "minmax.h"
был получен не с вышеупомянутого сайта GitHub, и я вставляю его содержимое ниже.
#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>amp; hw) {
if (hw.size() == 0)
throw domain_error("student has done no homework");
return grade(midterm, final, median(hw));
}
double grade(const Student_infoamp; s) {
return grade(s.midterm, s.final, s.homework);
}
// read homework grades from an input stream into a `vector<double>'
istreamamp; read_hw(istreamamp; in, vector<double>amp; 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;
}
istreamamp; read(istreamamp; is, Student_infoamp; 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_infoamp; x, const Student_infoamp; 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
Вот содержимое single_grade
:
harriet 85 95 88 87 93 45 76 99
Единственное место, где я нахожу эти два файла данных, упомянутых в любом из приведенных выше кодов, находится в makefile
, что меня смущает, но я предполагаю, что makefile
ассоциаты main2.cc
и два файла данных.
Вот содержимое "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
Вот что возвращается c -v
на моем Windows 10
ноутбуке:
c:Usersmark_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:Usersmark_myCppprograms>
Я знаю, что другие люди загрузили решения для ускоренных упражнений на C . Я просмотрел несколько. Но я не смог заставить ни один из них работать с main2.cc
или main3.cc
и возвращать ожидаемые результаты.
Комментарии:
1. «Я работаю с ускоренным C Эндрю Кенига и Барбары Му (2000)» — я бы настоятельно не советовал изучать C по книге 20-летней давности. Язык значительно эволюционировал, и с появлением C 11 он сильно отличается от того, что было раньше, а C 14, 17 и 20 только увеличили разрыв между современным C и C двадцатилетней давности. Не учитесь на устаревшем материале.
2. Если вы самостоятельно изучаете C , то одна из вещей, которую вы должны в конечном итоге усвоить, — это как использовать ваш отладчик. Ваш отладчик позволяет запускать вашу программу по одной строке за раз, проверяя значения всех переменных, и отслеживать их по мере их изменения, а также наблюдать за логическим ходом выполнения вашей программы. Знание того, как использовать отладчик, является обязательным навыком для каждого разработчика C , без исключений, и, похоже, это отличная возможность для вас узнать, как это сделать, не так ли?
3. Книга Кенига и Му была действительно замечательной в те времена. Раньше я рекомендовал его каждому новому разработчику C . К сожалению, сегодня этого недостаточно. Хотелось бы, чтобы была обновленная версия.
Ответ №1:
Я не уверен, как вы на самом деле это запускаете, но в моем случае это работает отлично. Если вы внимательнее посмотрите на main
в main2.cc
, вы заметите, что есть блокирующий read
вызов, который заставляет программу ждать ввода пользователя. Взгляните на test
цель из makefile:
test: all
./main1 <../data/single_grade
./main2 <../data/single_grade
./main2 <../data/grades
./main3 <../data/grades
<
означает, что мы будем перенаправлять содержимое single_grade
в выполняемый процесс. Неявно предполагается, что в папке выше исполняемого двоичного файла будет data
каталог с single_grade
файлом данных. Итак, при запуске $ make test
вы заметите, что все работает так, как ожидалось (при условии, что структура каталогов не изменилась). Если вы просто запустите $ ./main2
, ничего не произойдет, поскольку программа ожидает ввода. Или, предполагая, что ваш файл данных находится рядом с main2
двоичным файлом, вы могли бы выполнить $ main2 < single_grade
. Или, в качестве альтернативы, вы могли бы вообще не использовать файлы:
$ ./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)
Что дает:
Moo 100
Moore 79.4