コンピュータやソフトウェアのあれこれ@道民(&元道民)
C
OpenMPはじめました
8月 2nd
#include <stdio.h>
#include <omp.h>
int main(void)
{
#pragma omp parallel
{
printf( "hello world.\n" );
}
return 0;
}
って書いたCソースを”test.c”ってファイル名で保存して、
$ gcc -fopenmp test.c
$ ./a.out
ってやれば、コア(スレッド)の数だけ、”hello world.”が出力されるよ!
(Xcodeが入ってないとか、gccのバージョンが古いとダメかも・・・。)
実はこのプログラム、
すべてのコア(スレッド)をフルに使って”hello world.”を出力してるんだよ!
もう、並列プログラミングに片足突っ込んだも同然だね!!
ちなみに、手元のMacBookAirに入ってるgccのバージョンは、
gcc version 4.2.1 (Apple Inc. build 5666) (dot 3)
でした。
おしまい。
C/C++プログラミングの迷信と誤解
3月 22nd
読書感想文を書きます。
今日買って来て、今日読みました。
技術評論社 高木信尚著「C/C++プログラミングの迷信と誤解」
とっても良い本だと思います。
どんなヒトに読んで欲しいかと言うと、
一通りC/C++の入門書を読み終えて、実践に入る前に目を通して欲しいです。
組み込み系のように標準ライブラリに縁遠いヒトにも、
アプリ屋さんのように標準ライブラリを使うヒトにも、
なんとなくC++を使ってるヒトにも、
今まで何気なく使ってたキーワードや手法を、
掘り下げてしっかり解説してくれる1冊だと思います。
とは言う物の、私自身ただの物好きかも知れないので、
一度、目次に目を通すくらいはした方が良いと思います。
おしまい。
25個目!
12月 25th
一人Advent Calendarも今日でおわり!
終了間際には、1日空いちゃったけど、
C言語について25個書きました。
途中で思わず書いちゃったけど、
こんなの読んでないで、良書探して、
習うより慣れた方が良いと思います。
後で読んだヒトが困らないコードを目指すと、
長く険しい道のりが待っているので、
飽きずに続けられると思います。
めでたし、めでたし。
もっと知ろう!
12月 25th
12/24の分だよ。
きっと、いくつかの本を読み終えた頃には、
一通りの知識が身に付いて、それなりにコードを書けるんだけど、
たまに、コンパイラの警告が消えないとか、
文章にできるほど理解していない場合は、
こういうのも見たら良いと思うよ。
初級C言語Q&A
最初は、これを読んで理解出来なくても、
コードを書いて、慣れた頃にもう一度読むと、いろいろ発見があって、
ちょっとしたことで時間を使いすぎちゃうのを防げるかもしれないから、
こうした先人の知恵を探して、正しい知識を身につけてね!
良いコードとは?
12月 23rd
ポインタのポインタまで理解したなら、
あとは良書を読んで知識を深めてね。
今日、紹介するのは、このサイトだよ。
Cプログラミング診断室
どういうコードが良いコードかは、
そのコードを読むヒトの知識や経験によっても違うけど、
悪いコードっていうのは共通項があって、
このサイトは、悪い見本が何故悪いのか?も含めて紹介してあるよ。
もしも、お仕事でC言語を扱う場合は、
後で読むヒトの工数を増やすような
悪いコードを書かないように気を付けてね!
ポインタのポインタ – その2
12月 22nd
今日はアドレスを見るよ!
#include <stdio.h>
void showMessage(const char * const *pp)
{
printf( "in func, *pp = %s\n", *pp );
printf( "pp = 0x%016lX\n", (unsigned long)pp );
printf( "*pp = 0x%016lX\n", (unsigned long)(*pp) );
}
int main(int argc, char *argv[])
{
const char message[] = "hello.";
const char *p = message;
printf( "message = 0x%016lX\n", (unsigned long)message );
printf( "&p = 0x%016lX\n", (unsigned long)(&p) );
showMessage( &p );
return 0;
}
実行結果
message = 0x00007FFF5FBFF900
&p = 0x00007FFF5FBFF8F8
in func, *pp = hello.
pp = 0x00007FFF5FBFF8F8
*pp = 0x00007FFF5FBFF900
今日はポインタのポインタのアドレスを見るよ。
配列の先頭アドレスをポインタに入れてるよ。
そのポインタのアドレス、つまりポインタのポインタが&pだね。
そのアドレスを関数の引数に渡してるよ。
だから、&pとppが一致してるよ。
そして、*ppでmessageの先頭アドレスが取得できるよ。
ここまで理解出来れば、あとは習うより慣れろだから、
いっぱいコードを書いて覚えてね!
constとポインタのポインタ
12月 21st
constが2つ???
#include <stdio.h>
void printStrings(const char * const *p)
{
// p[0][0] = 'c'; error: assignment of read-only location
// p[0] = p[1]; error: assignment of read-only location
printf( "p = %s\n", *p );
p++;
printf( "p = %s\n", *p );
p++;
printf( "p = %s\n", *p );
}
int main(int argc, char *argv[])
{
const char str1[] = "a";
const char str2[] = "bc";
const char str3[] = "def";
const char *pStrArray[] = { str1, str2, str3 };
printStrings( pStrArray );
return 0;
}
実行結果
p = a
p = bc
p = def
今日は、constが2つだよ。
これは、str1の最初の文字を書き換えるコードだけど、
p[0][0] = 'c';
1つ目の const char * でエラーになるよ。
これは、pStrArray[0]の値(アドレス)を、
p[0] = p[1];
pStrArray[1]の値(アドレス)で書き換えるコードだけど、
2つ目の const * でエラーになるよ。
書き換えてはいけない変数や配列も、
こうやってCコンパイラさんに監視して貰えば、
後々のメンテナンスもきっと楽になるからちゃんと理解してね!
ポインタの配列
12月 20th
今日もポインタのポインタだよ。
#include <stdio.h>
void swapMessage(const char **ppA, const char **ppB)
{
const char *p;
p = (*ppA);
(*ppA) = (*ppB);
(*ppB) = p;
}
int main(int argc, char *argv[])
{
const char messageHello[] = "hello.";
const char messageBye[] = "bye.";
const char *p[] = { messageHello, messageBye };
printf( "p[0] = %s, p[1] = %s\n", p[0], p[1] );
swapMessage( &(p[0]), &(p[1]) );
printf( "p[0] = %s, p[1] = %s\n", p[0], p[1] );
return 0;
}
ポインタも配列にできるよ。
配列の使い方は大丈夫だよね。
そして、今日もポインタのポインタだよ。
今日は、ポインタの中身を交換するよ。
そのためには、変数を書き換えてもらうためのアドレスである、
ポインタのポインタを渡して、変数の中身を交換してるよ。
交換するには、一時的にアドレスを入れる変数を用意するよ。
2つの皿に乗ったケーキを交換する場合、もう1枚お皿を用意するよね。
考え方はこれと同じで、一時的に使用するポインタを使って、
アドレスを書き換えてるよ。
メモリをイメージすることが大事だから、
分からないときは絵を描いてがんばってね。
ポインタのポインタ
12月 19th
みなさん、お待ちかね!
#include <stdio.h>
void setMessage(const char **ppDst, const char *pMessage)
{
*ppDst = pMessage;
}
int main(int argc, char *argv[])
{
const char messageHello[] = "hello.";
const char messageBye[] = "bye.";
const char *p = messageHello;
printf( "p = %s\n", p );
setMessage( &p, messageBye );
printf( "p = %s\n", p );
return 0;
}
実行結果
p = hello.
p = bye.
今日は、ポインタのポインタだよ。
&pは、アドレスが格納された変数のアドレスを表してるよ。
setMessageの中では、最初の引数に*を付けると、
引数に格納されているアドレスをたどってポインタを書き換えることが出来るよ。
もう1つの引数で、そのポインタを書き換えているね。
少しややっこしいかもしれないけど、
ポインタっていうのは、アドレスが格納された変数ということを思い出せば、
きっと理解できるから、ゆっくり考えてね。
2次元配列とポインタ
12月 18th
今日は息抜きだよ!
#include <stdio.h>
int main(int argc, char *argv[])
{
char strings[3][4] = {
{ 'a', 'b', 'c', '\0' },
{ 'd', 'e', 'f', '\0' },
{ 'g', 'h', 'i', '\0' }
};
printf( "strings[0] = %s\n", strings[0] );
printf( "strings[1] = %s\n", strings[1] );
printf( "strings[2] = %s\n", strings[2] );
return 0;
}
実行結果
strings[0] = abc
strings[1] = def
strings[2] = ghi
こうすれば、文字列の配列を表現できるよ。
今日は簡単だったね。