Accelerated C++ Chapter 04

どうもです。


Chapter04です。振り返ると,だんだんとテストが欲しくなってきていた頃だった気が。

Memo

  • C++ では,構造体は型として扱う
struct Foo { ... };
Foo foovar; // C の場合は,struct Foo foovar;
  • 参照は何かしらを指している。
    • どっかのなんかの`別名'なので。
  • domain_error
    • stdexcept
    • 引数がおかしい時などに使用するみたい。
    • Java と違って,どっかで例外が throw されていて catch してなくてもコンパイラさんは
    • それについて文句を言ってくれないのが怖いと思った。
    • どの関数がどの例外を投げるのかを判断する方法がないのかなぁ?
      • Java の throws みたいなん。
      • そすれば関数の宣言みればわかるのに。
    • というかC++では例外は使わない方がいいのか?

Exercise 4-1

型が違うから怒られる。

Exercise 4-2

#include <iostream>
#include <cmath>
#include <iomanip>

using std::cout;
using std::endl;
using std::setw;

int main()
{
  for (int i = 0; i <= 100; ++i) {
    cout << setw(5) << i << " " << setw(5) << i * i << endl;
  }
  return 0;
}

Exercise 4-3

#include <iostream>
#include <cmath>
#include <iomanip>

using std::cout;
using std::endl;
using std::setw;

int main()
{
  const int upper = 10000;

  int w = 1;
  for (int i = upper - 1; i / 10 != 0; i /= 10) {
    ++w;
  }

  for (int i = 0; i < upper; ++i) {
    cout << setw(w) << i << " " << setw(w * 2) << i * i << endl;
  }

  return 0;
}

Exercise 4-4

最初,square を square root と勘違いしてた。

#include <iostream>
#include <cmath>
#include <iomanip>

using std::cout;
using std::endl;
using std::setw;
using std::streamsize;
using std::setprecision;
using std::setiosflags;
using std::ios_base;

int main()
{
  const double upper = 100;
  int intpart_width = 1;
  for (int i = (upper + 1) - 1; i / 10 > 0; i /= 10) {
    ++intpart_width;
  }

  const streamsize prec = 3;  
  // + 1 for a floating point
  const int left_width = intpart_width + prec + 1;
  const int right_width = intpart_width * 2 + 1 + prec;

  streamsize prec_org = cout.precision();
  for (double d = 0; d < upper; d += 0.1) {
    // We need fixed notaion rather than scientific notation.
    cout << setiosflags(ios_base::fixed);
    cout << setw(left_width) << setprecision(prec) << d << " "
         << setw(right_width) << setprecision(prec) << d * d << endl;
    cout << setprecision(prec_org);
  }

  return 0;
}
  • 実行結果

長いので一部省略。

% ./ex4-4
  0.000      0.000
  0.100      0.010
  0.200      0.040
  0.300      0.090
  0.400      0.160
  0.500      0.250
  0.600      0.360
  0.700      0.490
  0.800      0.640
  0.900      0.810
  1.000      1.000
  1.100      1.210
  1.200      1.440
  1.300      1.690
  1.400      1.960
  1.500      2.250
  1.600      2.560
  1.700      2.890
  1.800      3.240
  1.900      3.610
  2.000      4.000
  2.100      4.410
  2.200      4.840
  2.300      5.290
  2.400      5.760
  2.500      6.250
  2.600      6.760
  2.700      7.290
  2.800      7.840
  2.900      8.410
  3.000      9.000
  3.100      9.610
  3.200     10.240
  3.300     10.890
## ... omitted
 98.100   9623.610
 98.200   9643.240
 98.300   9662.890
 98.400   9682.560
 98.500   9702.250
 98.600   9721.960
 98.700   9741.690
 98.800   9761.440
 98.900   9781.210
 99.000   9801.000
 99.100   9820.810
 99.200   9840.640
 99.300   9860.490
 99.400   9880.360
 99.500   9900.250
 99.600   9920.160
 99.700   9940.090
 99.800   9960.040
 99.900   9980.010
100.000  10000.000

Exercise 4-5

構造体を使ったが,(ん? C++では構造体って言わない? 言うよね。)
テキスト中でも登場しているから使ってもいい武器なはず。

#include <iostream>
#include <vector>
#include <string>
#include <stdexcept>
#include <algorithm>

using namespace std;

istream& read_words(istream& in, vector<string>& words)
{
  string word;

  while (in >> word) {
    words.push_back(word);
  }
  in.clear();

  return in;
}

struct Word {
  string word_;
  int occurrence_;
};

void push_word_in_vec(const string& word, vector<Word>& words)
{
  // Search for w in words
  typedef vector<Word>::size_type wvec_sz;
  for (wvec_sz i = 0; i != words.size(); ++i) {
    if (word == words[i].word_) {
      // If found, increment its occurrence
      ++words[i].occurrence_;
      return;
    }
  }

  // Push new Word into words
  Word w;
  w.word_ = word;
  w.occurrence_ = 1;
  words.push_back(w);
}

void count_occurrences(const vector<string>& words_vec, vector<Word>& words_counter)
{
  for (vector<string>::size_type i = 0; i != words_vec.size(); ++i) {
    push_word_in_vec(words_vec[i], words_counter);
  }
}

bool cmp(const Word& w1, const Word& w2)
{
  return w1.word_ < w2.word_;
}

int main()
{
  vector<string> words_vec;
  vector<Word> words_counter;
  string word;

  cout << "Enter as many words as you want: ";
  read_words(cin, words_vec);

  // count occurrences of each word in words_vec
  count_occurrences(words_vec, words_counter);

  // determine the max length
  string::size_type maxlen = 0;
  for (vector<string>::size_type i = 0; i != words_vec.size(); ++i) {
    maxlen = max(maxlen, words_vec[i].size());
  }

  // Sort alphabetically
  sort(words_counter.begin(), words_counter.end(), cmp);

  // Display the result
  cout << endl << "Reoprt: " << endl;
  cout << "The number of words: " << words_vec.size() << endl;
  cout << "The occurrences of each word are as follows: " << endl;
  for (vector<Word>::size_type i = 0; i != words_counter.size(); ++i) {
    cout << words_counter[i].word_ << string(maxlen - words_counter[i].word_.size() + 3, ' ')
         << words_counter[i].occurrence_ << endl;
  }
  
  return 0;
}
  • 実行結果

出力がたくさんなので,一部省略。

% ./ex4-5 < ./ex4-5.cc
Enter as many words as you want: 
Reoprt: 
The number of words: 257
The occurrences of each word are as follows: 
!=                               4
"                                3
";                               1
"Enter                           1
"Reoprt:                         1
"The                             2
#include                         5
words_vec.size()                 1
words_vec.size();                2
words_vec;                       1
words_vec[i].size());            1
wvec_sz;                         1
you                              1
{                                12
}                                11
};                               1

Exercise 4-6

Student_info::read() だけを修正。
たしかこれだけだったはず。

istream& read(istream& is, Student_info& s)
{
  is >> s.name >> s.midterm >> s.final;
  read_hw(is, s.homework);
  s.final_grade = grade(s);
  return is;
}

Exercise 4-7

入力がでかかったり,たくさんだったら,あふれると思う。

#include <iostream>
#include <vector>

using namespace std;

double average(const vector<double>& vec)
{
  if (vec.size() == 0) {
    return 0.0;
  }

  double total = 0;
  for (vector<double>::size_type i = 0; i < vec.size(); i++) {
    total += vec[i];
  }

  return total / vec.size();
}

int main()
{
  double x;
  vector<double> dvec;

  while (cin >> x) {
    dvec.push_back(x);
  }

  double avg = average(dvec);
  cout << "Average = " << avg << endl;
  for (vector<double>::size_type i = 0; i != dvec.size(); ++i) {
    cout << dvec[i] << ", ";
  }
  cout << endl;

  return 0;
}

Exercise 4-8

f() が返す型は,operator[] をサポートしている型。
ポインタとか vector とかそんなん。
あ,ポインタだと SEGVる可能性もあるのか。でも,vector だってそだよね。