반응형

(컴퓨터 프로그래밍2 수업에서 배운 내용 일부를 정리한 포스팅입니다...)

 

 

핵심포인트

[ ]연산자

다음 두 연산은 완전히 동일한(indentical to)연산

"B-th element of A"를 의미하고 A는 "pointer to boject" type이다.

B[A] 연산도 당연히 성립하지만, 정상적으로 A[B]으로 사용합시다.

 

배열(Array)

배열은 연속된 메모리 공간에 동일한 자료형을 가진 원소들이 존재한다. 배열의 원소는 배열이름과 인덱스를 통하여 쉽게 접근이 가능하다.

그리고 배열을 선언할 때는 그 크기가 확정되어야 한다.(배열의 원소의 개수는 변수로 지정이 불가하다.)

 

★배열명의 사용

배열명은 3가지 의미로 사용될 수 있다.

  1. 배열명은 다음 두 경우를 제외하고는 첫번째 원소의 포인터로 쓰인다.
  2. sizeof 연산과 사용될 때
  3. & 연산과 사용될 때

 

EX.1

[코드]

#include<stdio.h>

int main() 
{
	char* s = "JANE";
	printf("%p %p\n", s, &s);
	printf("%s %c\n", s, s[2]);

	return 0;

}

[실행결과]

[설명]

schar형 포인터변수이며 ‘J’의 주소를 담고 있다. 프로그램 실행에서 보이는 바와 같이 s가 담고있는 값은 00637B30이며 s의 주소는 0073FA68이다.

그리고 s가 가리키는 주소에 해당하는 값은 JANE이며 s[2]*(s+2)와 같은 표현이므로 00637B30 +2 = 00637B32 이므로 이 주소에 해당하는 값은 ‘N’ 이다.

 

EX. 2

[코드]

#include<stdio.h>

int main() 
{
	char a[] = "JANE";
	printf("%p %d\n", a, sizeof(a));
	printf("%s %c\n", a, a[2]);

	return 0;

}

[실행결과]

[설명]

a는 문자열을 저장하는 배열명이며 배열명만 쓰이는 경우는 배열의 첫 번째 원소의 포인터를 가리킨다. 따라서 a[0]의 포인터 즉, 주소는 0090FD7C이고 sizeof 연산자의 경우 메모리공간에서 사용하는 메모리 크기를 바이트 단위로 계산해주는 연산자인데 char형 의 경우 1byte씩 차지하며 배열a에서 a[0]부터 a[3] 까지 각각 ‘J’,‘A’,‘N’,‘E’ 이 저장되어 있으며 a[4]에는 ‘\0’ 이 저장되어 있으므로 총 5byte를 차지한다. a%s로 출력하면 “JANE”이 출력되고 a[2]의 값은 ‘N’이다.

 

EX. 3

[코드]

#include<stdio.h>

unsigned int factorial(unsigned int n)
{
	if (n == 0) return 1;
	else return n * factorial(n - 1);
}

int main() 
{
	const unsigned int n = 4;
	int r;
	r = factorial(n);
	printf("%d! is %d\n", n, r);
	return 0;
}

[실행결과]

[설명]

기초적인 재귀를 이용하여 구현한 팩토리얼 함수이다. 초기의 n 값을 4로 지정하고 factorial 함수에 n값을 전달한다. factorial 함수 내부에서는 전달받은 인자가 0이 아니므로 n*factorial(n-1)을 반환하고 여기서 factorial(n-1)n-1값이 0이 아닐 경우 다시 (n-1)*factorial(n-2)를 반환한다. 이런식으로 전달받는 인자 값이 0이 될 때까지 진행하면 factorial(n)d으로부터 전달받는 값은 n*(n-1)*(n-2)*...*2*1 = n! 이 된다.

 

EX. 4

[코드]

// <main.c>

#include<stdio.h>
int a = 1; // 전역변수
int b = 2;
int c = 3;
void func(int c);

int main() 
{
	printf("전역변수\n");
	printf("global a = %d\n", a); // 전역변수
	printf("global b = %d\n", b); // 지역변수 b
	printf("global c = %d\n", c); // 전역변수
	
	printf("함수호출\n");
	func(a); // 전역변수 값 전달
	
	printf("전역변수\n");
	printf("global a = %d\n", a); // 전역변수
	printf("global b = %d\n", b); // 지역변수 b
	printf("global c = %d\n", c); // 전역변수
	
	return 0;
}
// <extern.c>

#include<stdio.h>
extern int a, b, c;

void func(int a)
{
	a++;
	b++;
	c++;

	printf("local a = %d\n", a); // 지역변수 a
	printf("global b = %d\n", b); // 전역변수
	printf("global c = %d\n", c); // 전역변수

}

[실행결과]

[설명]

main.c에서 만약 static 함수를 만들었다면 외부가 아닌 main.c의 안에 있어야 하는 함수여야 할 것이다. 먼저 전역변수 a,b,c를 각각 1,2,3으로 선언하고 출력한 뒤 func()라는 함수에 전역변수 값 a를 전달 한다. 외부에 있는 func함수에서 요소는 int a 이기 때문에 func함수 안에서는 a값이 지역변수 값이 되고 bc는 전역변수이다. 모든 값을 +1해주고 출력하면 순서대로 2,3,4가 나오지만 func() 함수가 끝나는 순간 지역변수 a값은 소멸된다. 따라서 다시 출력을 해보면 a,b,c 순서대로 1,3,4 값이 출력됩니다. 왜냐하면 a값은 func()함수에 값만 전달하고 실질적으로 func()함수 안에서는 이름만 같을 뿐인 a값이 사용되었기 때문이다.

 

 

EX. 5

[코드]

#include<stdio.h>

int main() 
{
	char* s = "string";
	char s1[6] = { 'h','e','l','l','o','\0' };
	char s2[] = { 'w','o','r','l','d','\0' };
	char s3[] = "compiler"; // 'compiler';로 적으면 x
	char* ap[] = { "park","kim","choi" };
	char aa[][10] = { "Android","IOS", "Linux" };

	printf("%s %p\n", s, s);
	printf("%c %c %c\n", s1[0], s2[0], s3[0]);
	
	printf("%s %s %s\n", ap[0], ap[1], ap[2]);
	printf("%p %p %p\n", ap[0], ap[1], ap[2]);

	printf("%c %c %c\n", aa[0][0], aa[0][1], aa[0][2]);
	printf("%c %c %c\n", aa[1][0], aa[1][1], aa[1][2]);
	printf("%c %c %c\n", aa[2][0], aa[2][1], aa[2][2]);
}

[실행결과]

[설명]

  • schar형 포인터 변수이고 “String”이라는 문자열이 담긴 주소를 저장한다.
  • s1,s2,s3모두 문자를 저장하는 배열들이고 각각의 앞글자 h, w, c 만 출력해보았다.
  • apchar형 배열의 포인터 변수이며 ap[0], ap[1], ap[2]는 각각 문자열 “park”, “kim”, “choi”를 가리키는 주소를 저장한다.
  • 이차원 배열 aa[][10]에서 문자들이 저장되는 구조를 살펴보면 아래와 같다.

 

EX. 6

[코드]

#include<stdio.h>

int main() 
{
	char a[] = "JANE"; // 자동으로 []에는 5가 채워진다.
	printf("%p %p %p\n", a, &a[0], &a);
	printf("%p %p %p\n", a+1, &a[0]+1, &a+1);
	printf("%d %d %d\n", sizeof(a),sizeof(a[0]), sizeof(&a));

	return 0;
}

[실행결과]

[설명]

 

printf(“%p”, a)

>> 배열명만 쓰인 경우는 첫 번째 원소의 포인터로 쓰이기 때문에 a[0]의 주소인 00B8FD10 이 출력된다.
printf(“%p”, &a[0])

>> a[0]의 포인터 값 00B8FD10 이 출력된다.
printf(“%p”, &a)

>> 배열자체의 포인터 이므로 위와 마찬가지로 00B8FD10 이 출력된다.
printf(“%p”, a+1)

>> a의 경우 첫 번째 원소의 포인터로 쓰이고 여기에 +1을 하는 경우이므로 00B8FD10 + 1 =00B8FD11 이 출력된다.
printf(“%p”, &a[0]+1)

>> a[0]의 포인터 값에 + 1한 값이므로 00B8FD10 + 1 = 00B8FD11 이 출력된다.
printf(“%p”, &a+1)

>> 배열자체의 포인터에 + 1 한 값이므로 00B8FD10 +1 = 00B8FD11 이 출력된다.
printf(“%p”, sizeof(a))

>> a라는 배열의 메모리 크기는 ‘J’,‘A’,‘N’,‘E’,‘\0’ 이고 char형 이므로 각각 1byte씩 차지한다. 
>> 따라서 5가 출력된다.
printf(“%p”, sizeof(a[0]))

>> a[0]의 값은 ‘J’이며 char형 데이터이므로 1byte
printf(“%p”, sizeof(&a))

>> &a 는 포인터이므로 포인터 타입의 size는 4byte 이다.

 

 

EX. 7

[코드]

#include<stdio.h>

int main() 
{
	short int a[2][3] = { 11,12,13,14,15,16 };
	printf("%p %p %p\n", a, a + 1, a[0] + 1);
	printf("%p %p\n", &a[0][1], &a[1][0]);

	return 0;
}

[실행결과]

[설명]

 

printf(“%p”, a)

>> 배열명이 첫 번째 원소의 포인터로 쓰이기 때문에 003FFA70이 출력된다.
printf(“%p”, a+1)

>> *(a+1) 은 a[1]과 같으므로 a[1]의 포인터 값은 003FFA70 + 6 = 003FFA76이 출력된다. 
>> (a[]배열은 3개의 short int형 데이터를 저장하고 있기 때문에 6byte를 차지한다.)
printf(“%p”, a[0]+1)

>> a[0]의 포인터는 a[0][0]의 주소이므로 003FFA70이고 short int형은 2byte씩 차지하므로 
>> a[0] + 1 의 포인터 값은 003FFA70 + 2 = 003FFA72 이다.
printf(“%p”, &a[0][1])

>> 위의 그림에서 알 수 있듯이 003FFA72이다.
printf(“%p”, &a[1][0])

>> 위의 그림에서 알 수 있듯이 003FFA76이다.

추가적으로 sizeof(a[0])의 경우 short int형 데이터가 3(11,12,13) 있으므로 6byte를 차지하기 때문에 6이 출력된다.

반응형

+ Recent posts