文字列の配列

文字列も配列化することができる。

#include<stdio.h>

int main(void){
        int i;
        char cs[][10] = {"banana","orange","pear"};

        for(i=0;i<3;i++){
                printf("cs[%d] =\"%s\"\n",i,cs[i]);
        }   
        return 0;
}

文字列配列の要素である文字列の読み込み

配列の各要素に、標準入力から文字列を読み込んで表示する。

#include<stdio.h>

int main(void){
        int i;
        char cs[3][128];

        for(i=0;i<3;i++){
                printf("cs[%d]:",i);
                scanf("%s",cs[i]);
        }   
        for(i=0;i<3;i++){
                printf("cs[%d] = \"%s\"\n",i,cs[i]);
        }
        return 0;
}

文字列

文字列リテラルは、整数での50や、浮動小数点数での3.14といった定数のようなもの。
オブジェクトに格納することによって、自由に取り扱うことができる。

文字の配列に文字列を格納・表示してみる

#include<stdio.h>

int main(void){
        char str[4];

        str[0] = 'A';
        str[1] = 'B';
        str[2] = 'C';
        str[3] = '\0';

        printf("文字列strは%sです。\n",str);

        return 0;
}

末尾のナル文字'\0'は、文字列の終端を示す「目印」である。

文字配列の初期化は、以下のいずれかの形式で行う。

char str1[] = {'A','B','C','\0'};
char str2[] = "ABC";

さっき書いたプログラムは以下のように簡略できる。

#include<stdio.h>

int main(void){
    char str[] = "ABC";
    
    printf("文字列strは%sです。\n",str);
    
    return 0;
}

文字列の読み込み

#include<stdio.h>

int main(void){
        char name[40];

        printf("お名前は?");
        scanf("%s",name);

        printf("こんにちは、%sさん。\n",name);

        return 0;
}

復習 〜配列〜

そろそろ夏休みだし、もっと勉強しようと思う。

点数を読み込んで合格者の一覧を表示する

#include<stdio.h>
#define NUMBER 5

int main(void){
        int i;
        int snum = 0;
        int tensu[NUMBER];
        int succs[NUMBER];

        puts("点数を入力してください。");
        for(i=0;i<NUMBER;i++){
                printf("%2d番",i+1);
                scanf("%d",&tensu[i]);
                if(tensu[i] >= 60){
                        succs[snum++] = i;
                }
        }
        puts("合格者一覧");
        puts("---------");
        for(i=0;i<snum;i++){
                printf("%2d番 (%3d点) \n",succs[i] + 1,tensu[succs[i]]);
        }
        return 0;
}

多次元配列

多次元配列の要素とアドレスがどうなるのか確かめてみる

#include <stdio.h>

int main()
{
	int a[3][2] = {10,20,30,40,50,60};
	int i,j;

	for(i=0;i<3;i++){
		for(j=0;j<2;j++){
			printf("a[%d][%d] = %d\n",i,j,a[i][j]);
		}
	}
	printf("\n");
	/*各要素のアドレスを確かめる*/
	for(i=0;i<3;i++){
		for(j=0;j<2;j++){
			printf("&a[%d][%d] = %p (a[%d]+%d) = %p\n",
				i,j,&a[i][j],i,j,(a[i]+j));
		}
	}
	printf("\n" );
	
	/* a[m][n] を *(*(a+m)+n)と書けるのか確かめる */

	for(i=0;i<3;i++){
		for(j=0;j<2;j++){
			printf("*(*(a+%d)+%d) = %d\n",
				i,j,*(*(a+i)+j));
		}
	}
	return 0;
}

実行結果

a[0][0] = 10
a[0][1] = 20
a[0][2] = 30
a[1][0] = 30
a[1][1] = 40
a[1][2] = 50
a[2][0] = 50
a[2][1] = 60

&a[0][0] = 0013F8F8 (a[0]+0) = 0013F8F8
&a[0][1] = 0013F8FC (a[0]+1) = 0013F8FC
&a[1][0] = 0013F900 (a[1]+0) = 0013F900
&a[1][1] = 0013F904 (a[1]+1) = 0013F904
&a[2][0] = 0013F908 (a[2]+0) = 0013F908
&a[2][1] = 0013F90C (a[2]+1) = 0013F90C

*(*(a+0)+0) = 10
*(*(a+0)+1) = 20
*(*(a+1)+0) = 30
*(*(a+1)+1) = 40
*(*(a+2)+0) = 50
*(*(a+2)+1) = 60

一次元配列とさほど変わらないことが分かった。

ちょっと実用的な例

テストの平均点と、個人別総合得点を求めるプログラム。

define NO 3

int main()
{
	int point[][2] = {
		80,80,
		100,98,
		60,80,
	};

	int i,j,sum = 0,p_sum[NO];
	double ave;

	for(i=0;i<NO;i++){
		sum += point[i][0];
	}
	ave = (double)sum/NO;

	printf("英語の平均点は%5.2fです。\n",ave);
	
	sum=0;
	for(i=0;i<NO;i++){
		sum += point[i][1];
	}
	ave = (double)sum/NO;
	

	printf("数学の平均点は%5.1fです。\n",ave);

	for(i=0;i<NO;i++){
		p_sum[i] = 0;
	}

	for(i=0;i<NO;i++){
		for(j=0;j<2;j++){
			p_sum[i] += point[i][j];
		}
		printf("出席番号%dの総得点%d\n",i+1,p_sum[i]);
	}
	return 0;
}

配列とアドレス

配列の要素は原則として、順番にメモリ上に並んでいる。

配列の各要素のアドレスを調べてみよう

#include <stdio.h>

int main()
{
        int a[4] = {1,2,3,4},i;
        
        for(i=0;i<4;i++){
                printf("&a[%d] = %p\n",i,&a[i]);
                
        }
        printf("\na = %p\n",a);
        return 0;
} 

実行結果

&a[0] = 0xbf8c0de0
&a[1] = 0xbf8c0de4
&a[2] = 0xbf8c0de8
&a[3] = 0xbf8c0dec

a = 0xbf8c0de0

確かに4バイトずつつながっている。

&a[0] = 0xbf8c0de0
a = 0xbf8c0de0

配列の名前は、その配列の先頭要素のアドレスを表している。
もしそうなら、aというアドレスより4バイト進めたらa[1]のアドレスになるのではないか、

確かめてみる

#include <stdio.h>

int main()
{
        int a[] = {10,20,30,40,},i,*p;

        p = a;
        for(i=0;i<4;i++){
                printf("&a[%d] = %p, a[%d] = %d, *(p+%d) = %d\n",
                i,&a[i],i,a[i],i,*(p+i));
        }
        return 0;
}

実行結果

&a[0] = 0xbfd9e2a8, a[0] = 10, *(p+0) = 10
&a[1] = 0xbfd9e2ac, a[1] = 20, *(p+1) = 20
&a[2] = 0xbfd9e2b0, a[2] = 30, *(p+2) = 30
&a[3] = 0xbfd9e2b4, a[3] = 40, *(p+3) = 40

a[1]のアドレスは(p+4)ではなくて(p+1)なのかな、実行結果を見ると1加えると4バイト進んでいる。

確かめてみる

#include <stdio.h>

int main()
{
	int *p,i,a[] = {20,40,80,10};

	p = a;

	for(i=0;i<4;i++){
		printf("&a[%d] = %p, (p+%d) = %p, (a+%d) = %p\n",
			i,&a[i],i,p+i,i,a+i);
	}
	return 0;
}

実行結果

&a[0] = 001BFD18, (p+0) = 001BFD18, (a+0) = 001BFD18
&a[1] = 001BFD1C, (p+1) = 001BFD1C, (a+1) = 001BFD1C
&a[2] = 001BFD20, (p+2) = 001BFD20, (a+2) = 001BFD20
&a[3] = 001BFD24, (p+3) = 001BFD24, (a+3) = 001BFD24

このことからa[n]は*(a+n)と同じということが分かる。

C言語ポインタ

ポインタ

ポインタをつかって変数の値を入れ替える。

#include <stdio.h>

void swap(int *,int *);

int main(void)
{
        int a,b;
        a  = 10;
        b = 20; 
    
        swap(&a,&b);

        printf("a = %d , b = %d\n",a,b);

        return 0;
}

void swap(int *x,int *y)
{
        int z;

        z = *x;
        *x = *y;
        *y = z;

        return;
}

  • ポインタは変数のアドレスを格納する。

  • 関数において、引数に変数のアドレスを渡すことにより、参照呼び出しと同じことができる。

オセロつくる

C言語でオセロつくろう。
でも石を置くところまで書いて躓き中。

#include <stdio.h>

int main(void){

	int circle[8][8];
	int i,j,x,y;
	int  flag = 1;
	int ans;
	int player = 1;

	for(i=0;i<8;i++){
		for(j=0;j<8;j++){
			circle[i][j] = 0;
		}
	}
	
	for(;;){
		if(flag == 1){
			printf("Do you play Osero? (Yes:1,No:0) ");
			scanf("%d",&ans);
			if(ans == 1){
				printf("Let's start Osero!!\n");
				circle[3][3] = 1;
				circle[3][4] = 2;
				circle[4][3] = 2;
				circle[4][4] = 1;
				flag = 0;
			}else{
				break;
			}
		}
		for(i=0;i<8;i++){
			for(j=0;j<8;j++){
				if(circle[i][j]==0){
					printf("□ ");
				}else if(circle[i][j] == 1){
					printf("● ");
				}else if(circle[i][j] == 2){
					printf("× ");
				}
			}
			printf("\n");
		}
		printf("Player%d\n",player);
		printf("Please input x and y.\n");
		printf("x:");
		scanf("%d",&x);
		printf("y:");
		scanf("%d",&y);
		
		
		if(x >=0 && x < 8 && y >=0 && y < 8){
			if (player == 1){
				if(circle[y][x] == 0){
					circle[y][x] = 1;
					
				}else{
					printf("すでに置かれています。\n");
				}
			}else if(player == 2){
				if(circle[y][x] ==0){
					circle[y][x] = 2;
				}else{
					printf("すでに置かれています。\n");
				}
			}
		}
		if(player == 1){
			player = 2;
		}else{
			player = 1;
		}
	}
	return 0;
}

結構条件分岐つかいそうだな。