리스트 10.2 no_data.c 프로그램
/* day_mon1 -- 각 달의 날짜 수를 출력한다.*/
#include<stdio.h>
#define MONTHS 12
int main(void)
{
int days[MONTHS] = {31,28,31,30,31,30,31,31,30,31,30,31};
int index;
for (index = 0; index < MONTHS; index++)
printf("%2d월: 날짜 수 %2d\n",index+1,days[index]);
return 0;
}
<출력>
1월: 날짜 수 31
2월: 날짜 수 28
3월: 날짜 수 31
4월: 날짜 수 30
5월: 날짜 수 31
6월: 날짜 수 30
7월: 날짜 수 31
8월: 날짜 수 31
9월: 날짜 수 30
10월: 날짜 수 31
11월: 날짜 수 30
12월: 날짜 수 31
<코드분석>
1년이 12개월이기 때문에 #define MONTHS 12 로 상수로 나타낼 수 있다.
그리고 index 변수로 각 달의 일 수를 리스트로 12개 나열하고
for문을 사용해 12월 달까지 리스트를 불러오고
printf를 사용해 %2d월 = index+1을 한 이유는 index는 값을 저장할 때 0~11까지의 값을 저장하기 때문이다.
리스트 10.2 no_data.c 프로그램
/*no data.c -- 초기화시키지 않은 배열*/
#include<stdio.h>
#define SIZE 4
int main(void)
{
int no_data[SIZE]; // 초기화시키지 않은 배열
int i;
printf("%2s%14s\n","i","no_data[i]");
for(i = 0; i <SIZE; i++)
printf("%2d%14d\n",i,no_data[i]);
return 0;
}
<출력>
i no_data[i]
0 -299606951
1 32766
2 100
3 0
<코드분석>
리스트를 초기화 시키지않았기 때문에 컴파일러는 우연히 그 메모리 위치에 놓여 있는 값을 사용한다.
리스트 10.3 some_data.c 프로그램
/*some_data.c -- 일부분만 초기화된 배열*/
#include<stdio.h>
#define SIZE 4
int main(void)
{
int some_data[SIZE] = {1492,1066};
int i;
printf("%2s%14s\n","i","some_data[i]");
for(i = 0; i < SIZE; i++)
printf("%2d%14d\n",i,some_data[i]);
return 0;
}
<출력>
i some_data[i]
0 1492
1 1066
2 0
3 0
<코드분석>
만약에 배열을 전부 초기화 시키지않는다면 내가 원하지않는 값이 나온다.
리스트 10.4 day_mon2/c 프로그램
/*day_mon2.c -- 컴파일러가 원소 개수를 카운트한다*/
#include<stdio.h>
int main(void)
{
const int days[] = {31,28,31,30,31,30,31,31,30,31};
int index;
for(index = 0; index < sizeof days / sizeof days[0]; index++)
printf("%2d월: 날짜수 %2d\n",index+1,days[index]);
return 0;
}
<출력>
1월: 날짜수 31
2월: 날짜수 28
3월: 날짜수 31
4월: 날짜수 30
5월: 날짜수 31
6월: 날짜수 30
7월: 날짜수 31
8월: 날짜수 31
9월: 날짜수 30
10월: 날짜수 31
<코드분석>
정확하게 카운트하는 능력이 부족하기 때문에 컴퓨터가 배열 크기를 계산해서 우리에게 알려주도록 부탁해야한다.
sizeof days는 바이트 수로 배열 전체의 크기고 sizeof days[0]는 배열 원소 하나의 크기다.
배열 전체 크기를 배열 원소 하나의 크기로 나누면 그 배열에 몇 개의 원소가 있는지 알 수 있다.
리스트 10.5 designate.c 프로그램
// designate.c -- 지정 초기화자를 사용한다.
#include<stdio.h>
#define MONTHS 12
int main(void)
{
int days[MONTHS] = {31,28, [4] = 31,30,31,[1] = 29};
int i;
for (i = 0; i < MONTHS; i++)
printf("%2d %d\n",i + 1,days[i]);
return 0;
}
<출력>
x
<코드분석>
컴파일러가 C99 기능을 지원하지않음.
리스트 10.6 bounds.c 프로그램
// bounds.c -- 배열의 범위를 벗어난다.
#include<stdio.h>
#define SIZE 4
int main(void)
{
int value1 = 44;
int arr[SIZE];
int value2 = 88;
int i;
printf("value1 = %d, value2 = %d\n",value1,value2);
for(i = -1; i <= SIZE; i++)
arr[i] = 2 * i + 1;
for(i = -1; i < 7; i++)
printf("%2d %d\n",i,arr[i]);
printf("value1 = %d, value2 = %d\n",value1,value2);
printf("arr[-1]의 주소 : %p\n",&arr[-1]);
printf("arr[4]의 주소 : %p\n",&arr[4]);
printf("value1의 주소 : %p\n",&value1);
printf("value2의 주소 : %p\n",&value2);
return 0;
}
<출력>
value1 = 44, value2 = 88
-1 -1
0 1
1 3
2 5
3 7
4 9
5 0
6 -556608256
value1 = 44, value2 = 88
arr[-1]의 주소 : 0x7ffeb51fb53c
arr[4]의 주소 : 0x7ffeb51fb550
value1의 주소 : 0x7ffeb51fb534
value2의 주소 : 0x7ffeb51fb538
<코드분석>
유효한 범위 내에 있는 배열 인덱스를 사용해야하는 이유를 보여준다.
컴파일러는 인덱스안에 어떤 값이 들어있는지 검사를 대신 해주지않기 때문에 사용자가 꼭 확인해야한다.
(4개의 원소를 가지는 배열을 만들고 나서 부주의 하게 -1부터 6까지 인덱스 값으로 사용했을 때 벌어지는 코드)
리스트 10.8 pnt_add.c 프로그램
// pnt_add.c -- 포인터 덧셈
#include<stdio.h>
#define SIZE 4
int main(void)
{
short dates[SIZE];
short * pti;
short index;
double bills[SIZE];
double * ptf;
pti = dates; // 배열의 주소를 포인터에 대입한다.
ptf = bills;
printf("%23s %15s\n","short","double");
for(index = 0; index < SIZE; index++)
printf("포인터 + %d: %10p %10p\n",index, pti + index, ptf + index);
return 0;
}
<출력>
short double
포인터 + 0: 0x7fffc00be948 0x7fffc00be950
포인터 + 1: 0x7fffc00be94a 0x7fffc00be958
포인터 + 2: 0x7fffc00be94c 0x7fffc00be960
포인터 + 3: 0x7fffc00be94e 0x7fffc00be968
<코드분석>
short형은 2바이트, double형은 8바이트 이기 때문에 주소에 + 1을 더할 때 short형은 2 double형은 8씩 증가한다.
우리가 포인트에 + 1 을 더한다는 의미는 하나의 기억단위를 객체의 단위만큼 더한다는 의미.
리스트 10.9 day_mon3.c 프로그램
/*day_mon3.c -- 포인터 표기를 사용한다*/
#include<stdio.h>
#define MONTHS 12
int main(void)
{
int days[MONTHS]={31,29,31,30,31,30,31,31,30,31,30,31};
int index;
for(index = 0; index < MONTHS; index++)
printf("%2d월: 날짜 수 %2d\n",index+1, *(days + index)); //*(days + index) 는 days[index]와 같다
return 0;
}
<출력>
1월: 날짜 수 31
2월: 날짜 수 29
3월: 날짜 수 31
4월: 날짜 수 30
5월: 날짜 수 31
6월: 날짜 수 30
7월: 날짜 수 31
8월: 날짜 수 31
9월: 날짜 수 30
10월: 날짜 수 31
11월: 날짜 수 30
12월: 날짜 수 31
<코드분석>
배열과 포인트는 밀접한 관련이 있음을 알려주는 예시
배열에서 *(days + index) 는 days[index]와 같다.
days는 그 배열의 첫 번째 원소의 주소다. days + index는 원소 days[index]의 주소다.
루프는 배열의 각 원소에 차례로 접근하여 그것의 내용을 출력한다.
리스트 10.10 sum-arr1.c 프로그램
// sum_arr1.c -- 배열의 원소들의 합을 구한다.
// %zd가 동작하지 않는다면 %u 또는 %lu를 사용하라.
#include<stdio.h>
#define SIZE 10
int sum(int ar[], int n);
int main(void)
{
int marbless[SIZE] = {20,10,5,39,4,16,19,26,31,20};
long answer;
answer = sum(marbless,SIZE);
printf("구슬의 전체 개수는 %ld개 입니다.\n",answer);
printf("marbles의 크기는 %zd바이트입니다.\n",sizeof marbless);
return 0;
}
int sum(int ar[],int n)
{
int i;
int total = 0;
for(i = 0; i < n; i++)
total += ar[i];
printf("ar의 크기는 %zd바이트 입니다.\n",sizeof ar);
return total;
}
<출력>
ar의 크기는 8바이트 입니다.
구슬의 전체 개수는 190개 입니다.
marbles의 크기는 40바이트입니다.
<코드분석>
marbles의 크기가 40바이트인 이유는 int형 원소를 10개 가지기 때문에 총 40바이트라는걸 알 수있다.
리스트10.11 sum_arr2.c 프로그램
/*sum_arr2.c -- 배열의 원소들의 합을 구한다.*/
#include<stdio.h>
#define SIZE 10
int sump(int * start, int * end);
int main(void)
{
int marbles[SIZE] = {20,10,5,39,4,16,19,26,31,20};
long answer;
answer = sump(marbles,marbles + SIZE);
printf("구슬의 전체 개수는 %ld개입니다.\n",answer);
return 0;
}
/*포인터 계산을 사용한다. */
int sump(int * start,int * end)
{
int total = 0;
while(start < end)
{
total += *start; // total에 값을 더한다
start++; // 포인트를 증가시켜 다음 원소를 가리킨다.
}
return total;
}
<출력>
구슬의 전체 개수는 190개입니다.
<코드분석>
포인터 start는 marbles의 첫 번째 원소를 가리키면서 시작한다
그래서 total += *start는 첫 번째 원소의 값(20)을 total에 더한다. 그리고 start++;는 포인터 변수 start를 증가시켜 배열에 있는 다음원소를 가르킨다. start가 int형을 가리키기 떄문에 C는 start의 값을 int형의 크기만큼 증가시킨다.
리스트 10.12 order.c 프로그램
// order.c -- 포인터 연산에서의 우선순위
#include <stdio.h>
int data[2] = {100, 200};
int moredata[2] = {300, 400};
int main(void)
{
int * p1, * p2, * p3;
p1 = p2 = data;
p3 = moredata;
printf(" *p1 = %d, *p2 = %d, *p3 = %d\n",
*p1 , *p2 , *p3);
printf("*p1++ = %d, *++p2 = %d, (*p3)++ = %d\n",
*p1++ , *++p2 , (*p3)++);
printf(" *p1 = %d, *p2 = %d, *p3 = %d\n",
*p1 , *p2 , *p3);
return 0;
}
<출력>
*p1 = 100, *p2 = 100, *p3 = 300
*p1++ = 100, *++p2 = 200, (*p3)++ = 300
*p1 = 200, *p2 = 200, *p3 = 301
<코드분석>
여기서 (*p3)++ 연산만이 배열의 값을 유일하게 변경시켰고 다른 두 연산은 p1과 p2를 배열의 다음 원소를 가리키도록 전진시켰다.
'스터디 > C언어' 카테고리의 다른 글
챕터 14 구조체와 그 밖의 데이터형 (0) | 2024.08.13 |
---|---|
챕터 11 문자열과 문자열 함수 (0) | 2024.08.13 |
챕터 9 함수 (0) | 2024.08.10 |
챕터 7 C의 제어문: 분기와 점프 (0) | 2024.08.09 |
챕터 6 C의 제어문: 루프 (0) | 2024.08.09 |