C++編【標準ライブラリ】 第2章 string 解答ページ

先頭へ戻る

このエントリーをはてなブックマークに追加

問題@

問題@ std::string型の変数を 'X' という1文字で初期化するには、どうすればいいですか?


1文字で初期化するには 'X' ではなく、"X" のように文字列として指定する必要があります。

#include <iostream>
#include <string>

int main()
{
	std::string str("X");

	std::cout << str << std::endl;
}

実行結果

X


問題A

問題A あなたの使っているコンパイラにおいて、空の std::string はどれだけのサイズと容量を持つか調べてみて下さい。


サイズは size関数、容量は capacity関数で取得できます。 また、std::string型の変数を宣言する際、初期値を与えなければ、空の文字列になります。

#include <iostream>
#include <string>

int main()
{
	std::string str;

	std::cout << "size: " << str.size() << std::endl;
	std::cout << "capa: " << str.capacity() << std::endl;
}

実行結果

size: 0
capa: 15

環境によって、容量は変わり得ますが、サイズの方は必ず 0 のはずです。 容量が変わるのは、std::string の具体的な実装方法がライブラリ製作者の裁量にある程度任されているためです。

上記の実行結果は、VisualC++ 2013/2015/2017 でのものです。 この環境では、容量は 15 になっています。
これは、多くの場合、std::string に与えられる文字列は短いものであり(世界中のプログラムの経験則から来ている判断です)、 そういった「よくある状況」では、時間のかかる動的なメモリ割り当てをできるだけ避けようとしているからです。


問題B

問題B 文字列の途中に '\0' を挿入することによって、std::string のサイズは変化するでしょうか?


#include <iostream>
#include <string>

int main()
{
	std::string str("abcde");
	std::cout << "size: " << str.size() << std::endl;

	str[2] = '\0';
	std::cout << "size: " << str.size() << std::endl;
}

実行結果

size: 5
size: 5

最初、"abcde" という文字列を格納してあり、このときのサイズは 5 です。 その後、str[2] に '\0' を代入してからサイズを調べてみると、やはり 5 のままです。

C言語でも C++ でも、生の文字列の終端は '\0' です。 strlen関数(⇒リファレンス)が返す長さは、'\0' までの長さですが、 std::string の「サイズ」の意味は違っています。 途中に '\0' があるとしても、std::string にとっては "ab\0de" であって、これは全体として「サイズ=5」なのです。


問題C

問題C std::string を渡すと、その中に含まれる小文字のアルファベットを大文字化するような関数を作成して下さい。 (ちなみに、std::string にそのような機能はありません)。


ここでは、C言語の toupper関数(⇒リファレンス)を利用します。 C++ なので、標準ヘッダの名前は cctype、関数は正確には std::toupper になります。

#include <iostream>
#include <string>
#include <cctype>

void to_upper(std::string* s);

int main()
{
	std::string str("abcABC012");

	to_upper(&str);
	std::cout << str << std::endl;
}

void to_upper(std::string* s)
{
	for (std::string::size_type i = 0; i < s->size(); ++i) {
		(*s)[i] = std::toupper((*s)[i]);
	}
}

実行結果

ABCABC012

添字を使って、先頭から末尾までループさせています。 末尾の添字は、サイズの値に一致しますから、size関数で取得した値で判定すればいいです。
また、size関数の戻り値は std::string::size_type型であり、これは符号無し整数ですから、 ループ制御変数もそれに合わせておいた方が安全です。


to_upper関数に、std::string型のポインタを渡していますが、C++ では、参照を使った方がいいかも知れません(【言語解説】第16章)。

#include <iostream>
#include <string>
#include <cctype>

void to_upper(std::string& s);

int main()
{
	std::string str("abcABC012");

	to_upper(str);
	std::cout << str << std::endl;
}

void to_upper(std::string& s)
{
	for (std::string::size_type i = 0; i < s.size(); ++i) {
		s[i] = std::toupper(s[i]);
	}
}

実行結果

ABCABC012


問題D

問題D 問題Cの関数を、イテレータによる範囲指定に対応させて下さい。


2つのイテレータを渡して、それが範囲を示すものとします。

#include <iostream>
#include <string>
#include <cctype>

void to_upper(std::string::iterator begin, std::string::iterator end);

int main()
{
	std::string str("abcABCabc");

	to_upper(str.begin(), str.begin() + 7);
	std::cout << str << std::endl;
}

void to_upper(std::string::iterator begin, std::string::iterator end)
{
	for (std::string::iterator it = begin;
	     it != end;
	     ++it
	) {
		*it = std::toupper(*it);
	}
}

実行結果

ABCABCAbc

STL での共通ルールとして、範囲の終わりを表すイテレータは、有効な末尾の要素の「1つ先」を参照するものとします。


参考リンク

更新履歴

'2017/3/25 VisualC++ 2017 に対応。

'2015/9/5 VisualC++ 2012 の対応終了。

'2015/8/18 VisualC++ 2010 の対応終了。

'2015/8/15 VisualC++ 2015 に対応。

'2014/3/30 問題@の解説内の誤った記述を削除。

'2014/2/1 VisualC++ 2013 に対応。

'2014/1/14 VisualC++2008 の対応終了。

'2013/7/13 新規作成。



第2章のメインページへ

C++編のトップページへ

Programming Place Plus のトップページへ