情報処理演習
第7回
2010年11月18日
2 変数に値を代入=記憶 プログラムの記憶領域として使用されるものがメモリ (パソコンの仕様書における512 MB RAM などの記述はこのメモリの量) #include <stdio.h> main() { int a,b; a=25; b=12; } 25 12 メモリの内容 0 1 2 3 アドレス RAMは多数のコンデンサの集合体: 電荷がたまっている(1)/ いない(0)で0か1を表現 → 計算機は2進法(10進法でプログラムが書けるのはCコンパイラなどのおかげ) つまり,変数を使用するためには, ・その変数が何番目のコンデンサを使うか → アドレス ・そのコンデンサの状態 → メモリの内容(変数の値) を把握しておく必要がある.ポインタとはアドレスを扱うためのしくみ a → b → 変数 【変数とメモリとの関係を模式的に示したもの】
今回のテーマ1: ポインタ
3 #include <stdio.h> main() { int a,b; a=25; b=12;
printf(”a: naiyou, address = %d, %lu¥n”,
a,&a);
printf(”b: naiyou, address = %d, %lu¥n”,
b,&b); } 25 12 .... 内容 C言語の表記 0 1 2 3 .... アドレス C言語の表記 a → b → 変数 【変数とメモリとの関係およびC言語における表記法】 a b &b &a
プログラムh07-1.c
内容aとアドレス&aを表示 bについても同様アドレスを扱うためには?
[xxx]% gcc h05-1.c [xxx]% a.out a: naiyou, address = 25, 3221221876 b: naiyou, address = 15, 3221221872 アドレスは自動的に 割り当てられた値
printf文中の%lu: unsigned long型を表示するための書式
変数のアドレスは,unsigned long型で表されるため,アドレス&a,&bの表示に必要. ※unsignedとは“符号なし”の意味.アドレスは正の整数であるため,符号±は不要.
unsigned long 型などの変数型については本資料の付録を参照.
これまでにない事項
scanf(”%d”,&a); キーボード入力した整数値(%dで指定)を,アドレス&aのメモリに格納 → scanfでは,データを格納する場所(アドレス)を指定している printf(”%d”,a); 変数aの内容を整数型としてコンソールに表示 → printfは内容の表示を行うので&aではなくa
プログラムh07-1.cから分かること
ポインタ変数: 変数のアドレスを扱うための変数 【定義方法】 (アドレスを記憶する変数の)データ型 *ポインタ変数名) 例: 整数型変数aのアドレスをポインタ変数pに記憶させる場合 #include <stdio.h> main() { int a; int *p; }
ポインタ変数
#include <stdio.h> main() { int a; int *p; a=51; p=&a;
printf(”a: naiyou, address = %d, %lu¥n”,a,&a); printf(”p: naiyou, address = %d, %lu¥n”,*p,p); }
プログラムh07-2.c
ポインタ変数(ここではp)を定義すると, ・pはアドレス格納用の変数(したがってpの型はunsigned longである) ・*pはアドレスpのメモリの内容 (例ではアドレスpを使っている変数がint型なので*pはint型である) として扱える. ポインタ変数pを定義 pに変数iのアドレスを代入 アドレスpのメモリの内容*p を表示(p=&aでアドレスpは aのアドレスになっているた め結局は変数aの内容と同じ) p=&a,*p=aとなっているはずです. 実行して確認してみよう.ポインタ変数を用いたプログラム例
・・・・・・・・・・ アドレス 0 1 2 3 4 内容 ・・・・・・・・・・ 1. 変数aを定義(int a;) &a= 2. 変数aに51を代入(a=51;) ・・・・・・・・・・ アドレス 0 1 2 3 4 内容 ・・・・・・・・・・ &a= 51 3. ポインタ変数pに整数型変数aのアドレス&aを代入(p=&a;) ・・・・・・・・・・ アドレス 0 1 2 3 4 内容 ・・・・・・・・・・ p ,&a= 51
プログラムh07-2.cの模式的な説明
ファイルの読み込み/書き込みの際に, FILE *fout; という定義を行った.この場合のfoutはファイルポインタと呼ばれます. fout=fopen(”test.txt”,”r”); などの処理を行ったことを憶えていると思います.fopenを実行すると,開いた ファイルtest.txtの状態を示すファイル変数が設定されます.ファイルポイ ンタfoutはそのファイル変数のアドレスを格納しておくためのものです.
int *p; の定義方法で思い出すこと
#include <stdio.h> main() { float i; float *p; i=10.5; p=&i;
printf(”i: naiyou, address = %f, %lu¥n”,i,&i); printf(”p: naiyou, address = %f, %lu¥n”,*p,p); }
#include <stdio.h> main() { char s[]=”the”; char *p; p=s+1; printf(”%c¥n”,*p); }
プログラムh07-3.c
配列の場合,各要素に対応するアドレスが存在 【表記】 【意味】 s[0] s[0]の値(この例では’t’) s[1] s[1]の値(この例では’h’) s[2] s[2]の値(この例では’e’) s[3] s[3]の値(この例ではヌル文字) &s[0] s[0]のアドレス &s[1] s[1]のアドレス(&s[0]+1) &s[2] s[2]のアドレス(&s[0]+2) &s[3] s[3]のアドレス(&s[0]+3) s 配列sの先頭アドレス(=&s[0]) p=s+1 (=&s[0]+1)によりpは配列sの2番目の要素s[1]のアドレス&s[1]となる. → アドレスpのメモリの内容*pは,s[1]=’h’ 文字列からある1文字を抜き出す配列とポインタ
・・・・・・・・・・ アドレス 0 1 2 3 4 内容 ・・・・・・・・・・ 1. 文字型配列sを定義,文字列theを代入(char s[]=”the”;) &s[0]=s= 2. ポインタ変数pの値を,配列sの先頭アドレス+1に設定(p=s+1;)
&s[1]= &s[2]= &s[3]=
t h e ヌル ・・・・・・・・・・ アドレス 0 1 2 3 4 内容 ・・・・・・・・・・ &s[0]=s= p ,&s[1]= &s[2]= &s[3]= t h e ヌル
プログラム(h05-3.c)の模式的な説明
今回のテーマ2: ファイル入出力(テキストファイル)
まず,音声データを http://www.ecei.tohoku.ac.jp/~hasegawa/ からダウンロード
今回のテーマ2: ファイル入出力(テキストファイル)
自分の学籍番号をクリックしてデータが表示されたら「名前を付けて保存」を選択
保 存 先 は 必 ず 自 分 の ホ ーム ディレ クトリ (フォルダ)にして下さい.自分の学籍番号 のディレクトリ(フォルダ)があるはずです.
ダウンロードしたデータの構造
保存したファイルをemacsで開いてみて下さい. 保存先されているデータの個数N ・・・・・ 1番目のデータ 2番目のデータ ・・・・・・・・・・・・・・・・ N番目のデータ#include <stdio.h> main() { int i,N; float sound[90000]; FILE *fp; fp=fopen(”b0tb0000.txt”,”r”); fscanf(fp,”%d”,&N); for(i=0;i<N;++i) fscanf(fp,"%f",&sound[i]); fclose(fp); printf(”N = %d¥n”,N); for(i=0;i<10;++i) fopenは今までと同じ使い方.読み込み なので,書き込みモードwではなく読み 込みモードrで開く ファイルからの読み込みは,fscanf.基本的に scanfと同じ使い方.違いは,読込先fpの指定. まず,第1行のデータの個数Nを読み込む. fclose忘れずに N個のデータをfor文を用いて 繰り返し読み込み.
テキストファイルのデータを読み込み配列に格納
配列を宣言.要素の数はemacsでファイルを開いた ときに1行目に書いてあったデータの個数より多く しておく. 全部表示するのは大変なので,最初の10個の データをコンソールに表示.表示された値と, emacsでファイルを開いたときの値が一致し16ページのプログラムを改良し,gnuplotで横軸時間,縦軸音声データ
の値,としてグラフ表示できるよう読み込んだデータをファイルに出力
するように改造して下さい.
データの標本化周波数 f
sは22,050 Hzです.つまり,データとデータ
の間隔が 1/22,050 秒,ということです.
課題Q7-20101118a
※【gnuplotで表示するためのファイルの構造】 1番目のデータの時刻(= 0秒) 1番目のデータ 2番目のデータの時刻 2番目のデータ 3番目のデータの時刻 3番目のデータ ・ ・ ・ ・ ・ ・ N番目のデータの時刻 N番目のデータ16ページのプログラムを改良する.
1. 音声データを格納した配列sound[i] (i=0, 1, 2, ..., N-1)と
別に配列ei[i] (i=0, 1,2,..., N-1)を定義し,音声データと同
じ 標 本 化 周 波 数 f
s= 2 2 0 5 0 H z で サ ン プ ル さ れ た 周 波 数 f =
(100×22050/N) Hzの正弦波sin(2π f i/22050)をei[i]に格納する.
2. 音声データと正弦波sin(2π f i/22050)の積sound[i]*ei[i]を全ての
i (i=0, 1, 2, ..., N-1)について計算し,さらに別の配列
eip[i]に格納して下さい.
※周波数 f の正弦波sin(2π f t)について,i番目の点の時刻はi/22050なの
でsin(2π f i/22050)と表現しています.
※eip[i]をグラフで確認するなど,適宜処理を各自の興味で加えて下さ
い.この処理を何に使うかは次回講義でお知らせします.
課題Q7-20101118b
音声データの拡大図 正弦波データの拡大図各変数は,型により扱えるデータなどが異なる. 【文字】 char unsigned char 【整数】 short int long unsigned short unsigned int unsigned long 【実数】 float double 8 bit 8 bit,符号なし 16 bit 32 bit 32 bit 16 bit,符号なし 32 bit,符号なし 32 bit,符号なし 32 bit 64 bit ※bit長は,2進数における桁数に対応する.