問題① 配列に文字列を代入するとき、strcpy関数を使わないといけない理由を説明してください。
たとえば、次のように記述すると、コンパイルできません。
char[] str = "abcde";
= "xyz"; str
これは、式の中にあらわれた配列が、ポインタに置き換えられるためです。上の代入式は、結局、次のように解釈されてしまいます。
&str[0] = &"xyz"[0];
左辺側が、値を受け取れる形になっていないため、この代入文は成立しません。 そこで、代わりに strcpy関数を使って、以下のように書かなければなりません。
(str, "xyz"); strcpy
strcpy関数がしていることは、文字を1文字ずつ代入していく作業です。 具体的には、以下のようなことをしていると考えられます。
for (i = 0; i < len; ++i) { // len はコピー元文字列 src の長さ
[i] = src[i];
str}
これなら、ポインタとして扱われることもなく、問題なく代入が行えます。
問題② 次の4つの printf関数の出力結果をそれぞれ答えてください。
char str1[] = "abcd";
char* str2 = "abcd";
("%zu\n", sizeof(str1));
printf("%zu\n", strlen(str1));
printf("%zu\n", sizeof(str2));
printf("%zu\n", strlen(str2)); printf
配列版の文字列に対する sizeof演算子は、配列全体の大きさを返します。 str1 は “abcd” なので、末尾の ‘\0’ を含めて、大きさは 5 です。
一方、ポインタ版の文字列str2 の場合、sizeof演算子が返すのは、ポインタ変数の大きさです。 その大きさは(32ビット環境ならば) 4 になります。
一方、strlen関数の方は、配列版の str1 であっても、ポインタ版の str2 であっても、 4 を返します。 strlen関数の内部では、渡された文字列の中に ‘\0’ が現れるまで、文字数をカウントして、その結果を返します。
問題③ strlen関数と同じことをする処理を書いてください(関数化する必要はありません)。
たとえば、次のように書けます。
#include <stddef.h>
#include <stdio.h>
int main(void)
{
char str[] = "abcd";
size_t i;
for (i = 0; str[i] != '\0'; ++i) {
// 空ループ
}
("%u\n", i);
printf}
実行結果:
4
strlen関数は、‘\0’ までの文字数をカウントし、size_t型で返します。 そこで、for文などで先頭要素から始めて、‘\0’ が現れるまで要素を1つずつ確認していけばいいということになります。
いろいろと書き方は考えられますが、上のプログラム例では、添字i を使って要素を参照しています。 ポインタを前面に出して、以下のように書くこともできます。
#include <stddef.h>
#include <stdio.h>
int main(void)
{
char str[] = "abcd";
size_t len = 0;
for (char* p = str; *p != '\0'; ++p) {
++len;
}
("%u\n", len);
printf}
実行結果:
4
次のようにアドレス計算を使えば、変数len も不要になります。
#include <stdio.h>
int main(void)
{
char str[] = "abcd";
char* p;
for (p = str; *p != '\0'; ++p) {
// 空ループ
}
("%d\n", p - str);
printf}
実行結果:
4
配列の末尾のメモリアドレス( ‘\0’ のところのメモリアドレス)から、先頭要素のメモリアドレスを減算すれば、配列全体の要素数になります。 (ただし、この場合は ptrdiff_t型になります)。
このようにいろいろと方法は考えられますが、どれでも正解です。しかし、これまでにも何度か書いているように、分かりやすさこそ重要視するべきです。3つ目の方法は、アドレス計算まで持ち出しており、格好良く見えるかもしれませんが、これは意味なく技巧的だとも言えます。恐らく、1つ目の方法が一番分かりやすく、効率的でもあります。
問題④ 次のように定義された配列があります。
int table[] = {0, 10, 20, 30, 40, 50, 60, 70};
この配列table のメモリアドレスを printf関数の “%p” 変換指定子を用いて調べたところ、0x0013D684 でした。このとき、配列table の末尾の要素70 のメモリアドレスがいくつであるか答えてください。ただし、sizeof(int) は 4 であるものとします。
配列の各要素は、メモリ上に連続的に並ぶことが保証されています。sizeof(int) == 4 であるという条件から、各要素は 4バイト刻みで並んでいることになります。
配列のメモリアドレスというのは、先頭要素のメモリアドレスを意味しており、これが 0x0013D684 であれば、末尾にある 70 は、そこから 7要素分先にあるので、「0x0013D684 + 4 * 7」が、末尾の要素のメモリアドレスです。
したがって、0x0013D6A0 が正解です。
{
の直後と、}
の直前に空白を入れない)()
の前後の空白の空け方)(
の直後、)
の直前に空白を入れない)return 0;
を削除(C言語編全体でのコードの統一)第38章から練習問題④を移動してきた。
全面的に文章を見直し、修正を行った。
文章中の表記を統一(bit、Byte -> ビット、バイト)
新規作成。
Programming Place Plus のトップページへ
はてなブックマーク に保存 | Pocket に保存 | Facebook でシェア |
X で ポスト/フォロー | LINE で送る | noteで書く |
RSS | 管理者情報 | プライバシーポリシー |