C h a p t e r 01 C 언어의 개요 ㉣ 동적메모리 관리에 의한 H/W제어가 용이하다. ⑥ 구조적 프로그램이 가능하다. ㉠ 아무리 복잡한 논리구조도 「goto」 명령을 사용하지 않고 처리할 수 있다. ㉡ 구조적 프로그래밍 언어로 모듈식 구현이 용이하다. 1. C 언어 개요 (3) C 프로그램의 일반적인 구조 (1) C 언어의 역사 1) C 프로그램은 함수의 집합체로 구성되며, 그 일반적인 구조는 헤드, 몸체, 사용 ALGOL60 - 1960년 국제위원회 ò CPL(Combined Programming Language) - 1963년 Univ of Cambridge & London ò BCPL(Basic CPL) - 1967년 Martin Richards, Cambridge Univ. ò B 언어 - 1970년 Ken Thompson ò C 언어 - 1972년 Dennis Ritchie ò 1989년 ANSI(America National Standard Institute) 에서 C의 표준을 결정 표 7.1 C 언어의 역사 (2) C 언어의 특징 (가) C 프로그램은 함수의 집합으로 구성된다. ① 각 루틴의 특성에 맞추어 각각의 함수를 만들어 두면 다른 응용프로그램을 작성할 때 도 그대로 이용할 수 있다. ② 함수의 집합으로 구성된 함수형 언어이다. ③ 이식성(Portable)이 좋다.(시스템 간 호환 및 이식성이 좋음) ④ 예약어(Reserved Word)가 간편하다. 자 정의 함수 부분으로 구분된다. 2) 헤드 부분 ① #include문(외부파일 정의 구문) ② #define문(매크로 정의 구문) ③ 전역변수 및 사용자 정의함수 선언 3) 몸체 부분 ① 함수 main()은 C 프로그램에서 예약된 유일한 함수로 프로그램 실행시 가장 먼저 수 행되는 함수이다. ② main() 함수의 위치는 프로그램 내의 어디에나 위치할 수 있고 반드시 한 번 기술되 어야 한다. 4) 사용자 정의 함수 ① 처리할 내용에 맞게 함수를 정의하고 경우에 따라서는 또 다른 함수를 호출할 수 있 다. ② 실제 프로그램에서는 사용자 정의 함수가 여러 개 나열되어 완전한 하나의 프로그램이 된다. ③ 함수 내부에서는 또 다른 함수를 정의할 수 없다. ㉠ 기본적인 몇 가지의 예약어로 다양한 종류의 작업을 처리할 수 있는 프로그램 개발 을 할 수 있다. ㉡ 비트 및 증감연산자 등 풍부한 연산자를 지원한다. ㉢ 배열과 포인터를 이용한 주소지정 및 연산의 용이함을 제공한다. ⑤ 융통성과 강력한 기능을 갖고 있다. ☑ 표준함수 C 컴파일러 자체에서 제공되는 함수인 printf(), scanf(), puts(), gets() 등을 표준함수라 고 하며 이들은 사용자가 직접 정의하지 않고 사용할 수 있을 뿐이고, 사용자 정의함수 와 모든 면에서 똑같이 취급된다. ㉠ 과학 기술 및 업무용 프로그램뿐만 아니라 오락, 문서작성기, 데이터베이스 등을 만드는데 사용될 수 있고, 심지어는 운영체제와 또 다른 언어의 컴파일러를 개발 하는데도 사용될 수 있는 언어이다. ㉡ 고급 및 저급 언어 간 인터페이스가 용이하다. ㉢ UNIX 운영체제의 기본이 된다. (4) 전처리문 구조 10 국가직 7급 1) 전처리문(Preprocessor Statement) ① 컴파일하기 전에 원시프로그램에 사용된 전처리문을 전처리기가 확장시킨다. PART 07 C 언어 2) 전처리문의 종류 ⑤ #ifndef ~ #endif - 다음에 오는 명칭이 전처리문에 의해 정의되어 있지 않으면 그 지 ① #include - 헤더파일 지정 시 사용, 외부파일을 원시프로그램에 편입시킨다. 점 다음에 오는 문장을 처리한다. #ifdef ~ #endif와 반대이다. #if !defined와 동일하 다. #include <stdio.h> → 표준 헤더파일 지정한다. #include "sort.h" → 사용자 헤더파일 지정한다. #include "c:sort.h" → c: 드라이브의 헤더파일 지정한다. ② #define - 매크로 지정 시 사용한다. #define MAX 5 → MAX 에 5 값으로 지정한다. #define SUM MAX * MAX → 매크로로 선언된 MAX를 곱한 값을 SUM으로 지정한다. #define PRN printf("최종값은 %d∖n", SUM) → SUM값을 출력한다. ③ #undef - 가장 최근에 #define으로 선언된 것을 해제한다. #define MAX 5 → MAX 에 5 값으로 지정한다. #define MAX 15 → MAX 에 15 값으로 재지정한다. #undef MAX → MAX가 다시 5로 값이 바뀐다. ④ #ifdef ~ #endif - 다음에 오는 명칭이 전처리문에 의해 정의되어 있으면 그 지점 다 음에 오는 문장을 처리한다. #define MAX 5 main(){ #ifdef MAX printf("출력한다."); #endif } → MAX가 매크로(#define 으로 선언)로 정의되어 있는지 검사하여 정의되어 있으면 printf문을 실행한다. #ifdef와 #if defined는 같은 뜻이다. 단 #if defined를 사용 시에는 조건을 여러 개를 걸 수 있다. 예를 들어 #if defined(MAX) || defined(MIN)와 같이 표현한다. main(){ #ifndef MAX printf("출력한다."); #endif } → MAX가 매크로(#define 으로 선언)로 정의되어 있는지 검사하여 정의되어 있지 않으면 printf문을 실행한다. ⑥ #ifdef ~ #else ~ #endif - 제어문의 if~else문과 같은 기능을 한다. #define MAX 5 main(){ #ifdef MAX printf("MAX가 선언되어 있다."); #else printf("MAX가 선언되어 있지 않다."); #endif } → MAX가 매크로(#define 으로 선언)로 정의되어 있는지 검사하여 정의되어 있으면 printf("MAX가 선언되어 있다.");문을 실행하고, 그렇지 않으면 printf("MAX가 선언되어 있지 않다.");문을 실행한다. 3) 전처리문의 사용 형식 및 구동방법 2006 군무원 ① 매크로 정의는 전처리문 #define을 사용한다. #define PI 3.14 main(){ int val; val = PI * 100; printf("%d", val); } 전처리 [원시프로그램] [확장된 원시프로그램] 그림 7.1 Chapter 01 C 언어의 개요 PART 07 C 언어 main() { int val; val = 3.14 * 100; printf("%d",val); } 매크로 과정 2009 군무원 2011 국가직 9급 ㉠ 위와 같이 매크로를 정의한 후 상수명 PI를 원시프로그램 내에 사용하면 전처리기 에 의해 모든 PI 위치에 3.14로 치환되고 나서 컴파일된다. Q. 다음은 C++ 프로그램의 일부이다. 실행 결과는? ② 매크로는 중첩되어 사용할 수 있다. 이때 전처리 과정을 선행한 후 컴파일이 된다는 #define POWER(x) x*x ... printf("%d\n", POWER(1+2+3)); 사실을 기억해야 한다. 매크로 중첩 예제 #define VAT 5 로 매크로 정의한 후 수식을 『y = VAT * SUM』로 #define SUM VAT + 3 기술했을 때 y의 값은? ① 6 ② 11 ③ 12 ④ 36 A. 4) 선행처리기 사용 시 제약사항 y = VAT * SUM = VAT * VAT + 3 ① 반드시 #으로 시작한다. = 5 * 5 + 3 ② 문장 끝에 세미콜론(;)을 붙이지 않는다. = 28 ─────────→ y의 값이 40이 아님을 주의해야 한다. ※ 만약, #define ② SUM ③ 한 줄에 하나의 명령만 쓴다. ( VAT + 3 ) 로 매크로 정의를 하면 y는 40이 된다. 즉, 매크로는 있는 모습 그대로 치환된다. 수식 등에 매크로가 사용될 때는 주의할 필요 가 있으며, 특히 매크로 정의시 매크로 명을 괄호로 묶으면 혼선을 피할 수 있다. 5) 조건부 컴파일 ① 정의 ③ 매크로 사용 시 주의할 점 ㉠ 해당 조건에 따라 컴파일 여부를 결정하는 명령이다. ㉠ 매크로명은 일반 변수와 구별하기 위해 대문자를 사용한다. ㉡ 매크로 정의문 끝에는 세미콜론(;)을 사용하지 않는다. ㉢ 문자열이 한 줄을 넘어서면 \를 사용한다. ㉡ 최적의 코드로 프로그램을 작성할 수 있기 때문에 시스템의 성능향상에 기여한다. ② 형식 #if 조건문 #define STATEMENT "동해물과 백두산이 마르고 닳도록 하느님이\보우하사 명령문 1 #else 우리나라만세!" ㉣ 매크로명과 인수 사이에는 공백이 있어서는 안 된다. 명령문2 #endif #define SUM ( a, b ) (a+b) ⇒ (X) ㉤ 매크로 정의를 해제할 때는 매크로명만 기입한다. Chapter 01 C 언어의 개요 ③ 종류∶#if, #elif, #else, #ifdef, #ifndef, #endif PART 07 C 언어 C h a p t e r 02 C 언어의 구성 및 문법 1. C ④ 기타 예약어 : main, sizeof, include,… (4) Escape 문자 ① Escape 문자는 문자를 표현하는 또 다른 방법으로, 역 슬래쉬(\) 다음에 특정 기호를 언어의 구성 요소 붙여 사용한다. 하단의 표와 같은 문자로는 표현할 수 없는 기호나 문자를 표현할 때 사용한다. (1) 주석문 종류 ① C언어에서 주석은 '/*' 와 '*/'사이, '//'뒤에 기술하며, 컴파일 대상에서 제외된다. 의 미 \a 삑하는 벨소리 출력 \b 현재 커서의 위치를 앞으로 한칸 이동 \f 인쇄용지를 1쪽 이동(Page skip) /* 한 줄짜리 주석 */ \n 현재 커서의 위치를 다음 행으로 이동 /* \r 현재 커서의 위치를 현재 행의 첫 번째 위치로 이동 여러 줄에 \t 현재 커서의 위치를 다음 탭 위치로 이동 걸친 주석 \0 NULL 문자 */ \\ 역슬래쉬(\) 기호 출력 // 한 줄짜리 주석 \' 단일 따옴표(’) 기호 출력 \? 물음표 기호 출력 \" 이중 따옴표(”) 기호 출력 주석을 작성하는 방법 (2) 명칭(Identifier) (가) 변수, 배열, 포인터, 함수 등의 이름으로 다음과 같은 규칙을 따라야 한다. ① 예약어만을 명칭으로 사용할 수 없다. ② 영문자, 숫자, 밑줄( _ )을 사용하여 명칭을 구성할 수 있다. ③ 첫글자는 반드시 영문자이어야 하며 underscore(_)도 영문자로 취급하며 숫자로 시작 해서는 안 된다. 2. C 언어의 자료형(Data Type) (1) 자료 표현 1) 자료 표현의 특징 ① C언어에서는 문자열형을 제공하지 않는다. 따라서 문자열을 사용하기 위해서는 배열 ④ 대문자와 소문자는 구별된다. 또는 포인터를 사용해야 한다. 즉 C에서 문자열은 문자 배열이다. ② C언어 표준에서는 기본적으로 정수형 상수는 int형으로 실수형 상수는 double형으로 (3) 예약어(Reserved Word) 표현한다. (가) 예약어는 언어 자체에서 미리 정해진 기능을 갖는 것으로 변수명, 함수명 등으로 사용할 수 없다. ① 자료형 관련 예약어 : char, int, float, short, long, double, unsigned, union, struct, signed, const, typedef, enum, void, auto, static, extern, register ③ 문자형, 정수형, 열거형의 경우, 자료형 앞에 수식어 unsigned가 없으면 signed가 생략 된 것으로 처리된다. 즉 「char」는 「signed char」와 같다. ④ 컴퓨터는 내부적으로 int형 데이터를 가장 빠르게 연산(처리)한다. ⑤ int형은 기종에 따라 처리하는 비트수가 다르게 잡힌다. 즉 「컴퓨터가 한꺼번에 처리 할 수 있는 비트수 크기(word)」로 기억공간이 확보된다. ② 제어 관련 예약어 : if ~ else, for, while, do ~ while, switch ~ case, break, continue, return, default, goto ③ 기억장소 관련 예약어 : auto. register, static, extern, volatile Chapter 02 C 언어의 구성 및 문법 PART 07 C 언어 (2) 자료형의 종류 2) 자료 표현 방식 (가) 숫자 표현 방법 구분 1) 기본형 종류 8진수 16진수 int unsigned int long unsigned long float double long double 정수 숫자 실수 표현방법 숫자 앞에 0을 붙인다. 숫자 앞에 0x를 붙인다. 일반적인 정수형을 표현한다. 접미사 u 또는 U를 붙인다. 접미사 l 또는 L을 붙인다. 접미사 ul 또는 UL을 붙인다. 접미사 f 또는 F를 붙인다. 일반적인 소수점으로 표현한다. 접미사 l 또는 L을 붙인다. 예 012, 034 0x12, 0x34 123, -45 123u, 123U 123l, 123L 123ul, 123UL 1.23f, 1.23F 1.23 1.23l, 1.23L 구 분 문자형 자료형 char unsigned char short unsigned short int 정수형 unsigned int ※ 접미사는 대소문자를 구분하지 않으며 대소문자를 섞어서 사용 가능. 구분 종류 문자 문자열 문자 표현방법 출력 문자를 단일 따옴표로 묶는다. 출력 문자열을 이중 따옴표로 묶는다. 예 'O', 'K', '\t' "TOPSPOT", "T" 허용 범위 -128 ~ 127 0 ~ 255 -32,768 ~ 32,767 2 byte 2 byte 가변적 2 byte 4 byte 2 byte 4 byte 0 ~ 65535 (16비트 OS) (32비트 OS) (16비트 OS) (32비트 OS) -32,768 ~ 32,767 -2,147,483,648~2,147,483,647 0 ~ 65,535 0 ~ 4,294,967,295 4 byte 4 byte -2,147,483,648~2,147,483,647 unsigned long bool 1byte true or false float 3.4*10-38~3.4*1038 double 4 byte 8 byte long (나) 문자 표현 방법 바이트 수 1 byte 1 byte 논리형 실수형 0 ~ 4,294,967,295 1.7*10-308~1.7*10308 (다) 실수 자료형의 정밀도 열거형 enum 2byte 자료형 float 정밀도 소수점 이하 6자리까지 표현 가능하다. 무치형 void 실제 자료가 없음을 명시적으로 선언 double 소수점 이하 15자리까지 표현 가능하다. long double double의 정밀도와 같거나 크다. 정수를 대신하여 사용하는 별명 2) 유도형 ① 유도형은 기본형의 조합에 의해 만들어지는 타입들로 기본형 변수 여러 개를 모아서 또는 기본형을 약간 변형하여 만들어지는 타입들이다. ② 유도형에는 배열, 함수, 포인터, 구조체, 공용체가 있다. (3) 자료형 변환 ☑ 출력문 실행시 지정 문자열 표 정수형 변수의 선언 형식 지정 문자열 int var1, var2, …; unsigned int var1, var2, …; long var1, var2, …; unsigned long var1, var2, …; short var1, var2, …; unsigned short var1, var2, …; %d %u %ld %lu 또는%ld %d %u Chapter 02 C 언어의 구성 및 문법 2007 서울시 2007 국가직 09 국가직 7급 2010 서울시 2010 국가직 1) 자동 형 변환(묵시적 형 변환) (가) 대입 연산 과정에서의 자동 형 변환 ① 대입 연산자의 오른쪽에 존재하는 데이터가 왼쪽에 존재하는 데이터의 자료형으로 자 동 형 변환된다. PART 07 C 언어 int main(void) int main(void) { int a = 1; int b = 2; float f1 = a/b; float f2 = (float)a/b; printf("%f, %f \n", f1, f2); } [실행결과] 0.000000, 0.500000 { int inum = 6.25; // ‘소수부의 손실’이 발생하면서 int형으로 자동 변환됨 double dnum = 5; // 값의 표현 범위가 더 넓은 double형으로 자동 변환됨 char cnum = 129; /* 129는 int형 데이터이므로 4바이트이다. 따라서 ‘상위 비트의 손실’이 발생하면서 1바이트로 자동 변환됨 */ printf("%d, %f, %d \n", inum, dnum, cnum); } [실행결과] 2010 서울시 9급 6, 5.000000, -127 Q. 다음의 C언어 수식이 실행될 때 그 연산 방식이 가장 가까운 수식은? (단, x는 정수형 변수이다.) (나) 산술 연산 과정에서의 자동 형 변환 ① +, -, *, /와 같은 산술 연산자의 경우, 피연산자의 자료형이 일치하지 않으면 자료 x + 2.0 * 3 형의 크기가 작은 것에서 큰 자료형으로 자동 형 변환이 발생한다. (char → short → int → long → float → double) ② 수식 내에 int형보다 작은 자료형은 무조건 int형으로 변환된다. ① × + (int)2.0 * 3 ② × + (int)2.0 * (float)3 ③ (int) (x + (int)2.0 * 3) ④ (float)x + (int)2.0 * 3 ⑤ (float)x + (float)2.0 * (float)3 (char, short, enum이 혼합된 수식은 int로 변환된다.) A. ⑤ A. ① ③ 실수 연산 시 float형은 무조건 double형으로 변환되어 연산에 첨가된다. 예시 자동 형 변환 double e1 = 6.5 + 3; int형 → double형 double e2 = 3.14f + 4.5; float형 → double형 2009 국가직 7급 형 변환 결과 Q. e1 = 6.5 + 3.0 = 9.5 e2 = 3.14 + 4.5 = 7.64 C함수 매개변수로 5를 주어 호출했을 때 변환되는 값은? #include <stdio.h> void main(){ float a = 3/2; float b = 3.0/2; int c = (int)b; printf("%7.3f %7.3f %3d\ n", a, b, c);} ④ 만약 int, long, double형을 갖는 3개의 자료가 수식 내에 포함되어 있으면 연산결과 는 double형이 된다. 2) 강제 형 변환(명시적 형 변환) ① 아래와 같이 명시적인 선언에 의해서 발생하는 형 변환이다. 3. C ① 1.000 1.500 1 ➁ 1.000 1.000 1 ➂ 1.500 1.500 1 ➃ 1.500 1.500 2 언어의 연산자(Operator) (1) 연산자 Chapter 02 C 언어의 구성 및 문법 PART 07 C 언어 2007 경상남도 2007 국가직 1) 산술 연산자(Arithmetic Operator) 2009 서울시 2010 국가직 연산자 예시 기능 = i = 10 i 에 10을 대입 += i += 10 i 값을 10만큼 증가시켜 i 에 대입 -= i -= 10 i 값을 10만큼 감소시켜 i 에 대입 *= i *= 10 i 값에 10을 곱한 후 결과값을 i 에 대입 /= i /= 10 i 값을 10으로 나눈 후 결과값을 i 에 대입 ① 2개의 항을 대상으로 연산을 수행한다. %= i %= 10 i 값을 10으로 나눈 후 나머지를 i 에 대입 ② % 연산자는 정수형 자료에만 사용할 수 있다. &= i &= 10 i 값과 10을 비트단위 AND 연산한 후 결과값을 i 에 대입 |= i |= 10 i 값과 10을 비트단위 OR 연산한 후 결과값을 i 에 대입 (가) 이항 연산자(Binary Operator) + 연산자 * % / 기능 더하기, 빼기, 곱하기, 나누기 계산 예시 i + 1 나머지 계산 i % 2 (나) 단항 연산자(Unary Operator) 연산자 - 2006 경상남도 2006 부산교육 기능 2006 군무원 예시 -i 부호의 반전 ++ 1 증가 i++ -- 1 감소 --i ① 1개의 자료를 대상으로 산술적인 처리를 수행하는 연산자로 정수형 변수에만 사용한 ^= i ^= 10 i 값과 10을 비트단위 XOR 연산한 후 결과값을 i 에 대입 <<= i <<= 2 i 값을 2비트 좌로 shift 연산한 후 결과값을 i 에 대입 >>= i >>= 2 i 값을 2비트 우로 shift 연산한 후 결과값을 i 에 대입 ① '=' 연산자를 사용하여 오른쪽 피연산자의 값을 왼쪽 피연산자에 대입하는 데 사용한 다. ② 프로그램의 길이가 짧아지고 실행속도를 증가시킨다. 다. 대입 연산자 사용 예제 ② 전치연산과 후치연산이 가능하다. #include <stdio.h> void main(){ int i, j, k; i = j = k = 5; i += j *= k -= 4; printf("i=%d, j=%d, k=%d", i, j, k);} [출력결과] i=10, j=5, k=1 ㉠ 전치연산 : 변수값을 먼저 증가시킨 후 사용한다. ㉡ 후치연산 : 변수값을 먼저 사용 후 증가시킨다. 단항 연산자 사용 예제 #include <stdio.h> void main() { int i=10; printf("%d\n",i); printf("%d\n",i++); printf("%d\n",i); printf("%d\n",++i); } [출력결과] 10 10 11 12 2) 관계 및 논리 연산자 06 대구교육 06 서울시 07 부산시 07 경상북도 07 국가직 7급 09 군무원 (가) 관계 연산자(Relational Operator) 연산자 == > 기능 != >= < <= 예시 값의 동일 여부를 비교 i == j 값의 대∙소 관계를 비교 i <= j ① 피연산자에 대한 값의 동일여부와 대∙소 관계를 비교하는 연산자 ② 연산 결과값으로 참(true) / 거짓(false) 을 가진다. int b = a > 10; 에서 a > 10이 참이면 b는 1이 되고, 거짓이면 0이 된다. (다) 대입 연산자 Chapter 02 C 언어의 구성 및 문법 PART 07 C 언어 #include<stdio.h> void main(){ int a, b, c; 2011 지방직 9급 Q. 다음 C 프로그램의 실행 결과는? a = b = c = 1; ++a && ++b || ++c; printf("a=%d, b=%d, c=%d \n", a, b, c); #include<stdio.h> void main(){ int a = 3 + 5, b = 1, c; int ap, bp; ap = a++; bp = ++b; b = 3 * (ap == 8); c = 5 * (ap != 8); printf("%d %d %d %d %d", a, b, c, ap, bp);} ① 8 2 5 9 2 ② 8 3 0 8 1 ③ 9 2 5 9 1 ④ 9 3 0 8 2 a = b = c = 1; ++a || ++b && ++c; printf("a=%d, b=%d, c=%d \n", a, b, c); a = b = c = -1; ++a && ++b || ++c; printf("a=%d, b=%d, c=%d \n", a, b, c); A. a = b = c = -1; ++a || ++b && ++c; printf("a=%d, b=%d, c=%d \n", a, b, c); ④ } [출력결과] a=2, b=2, c=1 a=2, b=1, c=1 a=0, b=-1, c=0 a=0, b=0, c=-1 (나) 논리 연산자(Logical Operator) 연산자 &&(AND) 기능 예시 i&&j 양쪽 모두 참일 때만 참 ||(OR) 양쪽 중 한쪽만 참이면 참 !(NOT) 참 / 거짓값의 반전 i||j !i ① 피연산자에 대한 논리연산(AND, OR, NOT)을 수행하는 연산자 2007 국가직 7급 ② 연산 결과값으로 참(true) / 거짓(false) 을 가진다. Q. C 언어는 논리곱(logical AND;&&) 과 논리합(logical OR;||) 연산자(operator) 에 대해 '단락- 회로 평가(short - circuit evaluation)' 를 하도록 되어 있다. 논리 연산자 사용 예제 아래 C 프로그램의 수행 결과는? int main(){ int a=1, b=2, c=3, d=4; if((a==b)&&(c++==d)) c++; printf("%d",c); } ① 3 ② 4 ③ 5 ④ 6 A. 3) 비트 연산자(Bitwise Operator) Chapter 02 C 언어의 구성 및 문법 PART 07 C 언어 ① 2006 부산시 연산자 2006 경상남도 2007 군무원 2007 경상남도 &(AND) 예시 i&j 대응되는 두 비트가 모두 1일때만 결과값이 1 |(OR) i|j 대응되는 두 비트중 하나만 1이면 결과값이 1 2010 국가직 기능 ☑ 시프트 연산 모든 시프트 연산은 0으로 채우는 것은 아니며, 시프트 연산은 데이터의 직렬 전송을 위해 사용된다. 종류로는 논리, 순환, 산술 시프트 연산이 있다. ^(XOR) i^j 대응되는 두 비트가 서로 다를 때 결과값이 1 ~(NOT) ~i 1은 0으로, 0은 1로 변환시키는 보수연산자 << i<<2 i 값을 2비트 왼쪽으로 shift 연산 - 부호 없는 이진수에 대한 연산. 부호를 고려하지 않으므로 0으로 채움 >> i>>2 i 값을 2비트 오른쪽으로 shift 연산 - 직렬입력으로 0이 전송되는 것 ① 논리 시프트(logical shift) - 기호로는 shl(<<), shr(>>) (가) 이동 연산자(shift operator) ② 산술 시프트(arithmetic shift) - 부호가 있는 이진수를 시프트하는 것 ① << : 이진수에 2를 곱한 것과 결과 값이 같다.(비트 단위로 왼쪽으로 이동한다.) a. 오른쪽 산술 시프트에서는 최상위 비트를 유지하며 연산을 수행 ② >> : 이진수를 2로 나눈 것과 결과 값이 같다.(비트 단위로 오른쪽으로 이동한다.) (부호비트는 이동되지 않음) b. 왼쪽 산술 시프트에서는 마지막 비트에 0을 삽입하고, 나머지 상위비트를 왼쪽으로 시프트 (따라서 오버플로가 발생할 가능성이 생김) 이동 연산자 예제 X∶ 1 0 0 1 0 0 1 1 X<<2∶ 0 1 0 0 1 1 0 0 X>>2∶ 0 0 1 0 0 1 0 0 ③ 순환 시프트(circular shift or rotate shift) - 시프트 레지스터의 직렬 출력을 직렬 입력에 연결함으로써 원래 저장되어 있던 정보의 손실 없이 비트들을 순환시키는 연산 int a = 8; int r_shift = a >> 3; int l_shift = a << 3; 2010 국가직 9급 Q. printf("shr of %d = %d\n", r_shift, a ); printf("shl of %d = %d\n", l_shift, a ); #include <stdio.h> void main(){ int x = 0x11; int y, z; y = x & 0x0f; z = x ∣ 0x0f; printf("x=%d, y=%d, z=%d", x, y, z); } <출력결과> shr of 1 = 8 shl of 64 = 8 [풀이] ↓ → 3칸 0 0 0 0 1 0 0 0 => 0 0 0 0 0 0 0 1 ← 3칸 ↓ 0 0 0 0 다음 C 프로그램의 실행 결과는? ① x=11, y=1, z=31 ② x=11, y=31, z=1 ③ x=17, y=1, z=31 ④ x=17, y=31, z=1 1 0 0 0 => 0 1 0 0 0 0 0 0 Chapter 02 C 언어의 구성 및 문법 A. PART 07 C 언어 ③ 일반적인 C에서의 우측 시프트 규칙 출력 결과 1. 부호 없는 타입일 경우에는 논리 시프트를 한다. 2. 부호 있는 타입일 경우에는 산술 시프트를 한다. a shr of -1 = -8 a shl of -64 = -8 일반적이라고 말하는 이유는 이것을 보장할 수 없기 때문이다. 이 문제가 명백하게 정의되어 있지 않기 때문에 구현에 따라 달라질 수 있다. 다만 Intel CPU 기반의 윈도 우에서 동작하는 Visual C++의 경우에는 이 규칙을 따른다. 그러나 어떤 경우에도 부호 없는 타입에 대해 부호비트를 유지해주는 일은 하지 않는다. 따라서 "unsigned의 경우 부호를 유지한다."는 내용이 있다면, 이는 수정하고 보는 게 좋을 듯하다. 부호를 유지한다면 이는 signed 타입일 경우이다. java에서는 >>> 연산자가 논리시프트, >> 연산자가 산술시프트이므로 c/c++에서 일어나는 모호한 상황을 없앴다. b shr of 1 = 8 b shl of 64 = 8 #include <stdio.h> void main () { int a = -8; int a_r_shift = a >> 3; int a_l_shift = a << 3; c shr of 3 = -8 c shl of -64 = -8 d shr of 1 = 8 d shl of 64 = 8 int c_r_shift = c >> 30; (32비트일 경우) c 는 1111 1111 1111 1111 1111 1111 1111 1000 c >> 30 연산을 수행하면 0000 0000 0000 0000 0000 0000 0000 0011 이므로 3이 된다. int b = 8; int b_r_shift = b >> 3; int b_l_shift = b << 3; 2011 국가직 7급 unsigned int c = -8; int c_r_shift = c >> 30; int c_l_shift = c << 3; Q. 다음 C 프로그램의 실행 결과로 옳은 것은? #include <stdio.h> void main() { int a, b, c, r; a = 4; b = 2; c = 3; r = a++ - ++b * (c << 2); printf("%d\n", r); } unsigned int d = 8; int d_r_shift = d >> 3; int d_l_shift = d << 3; printf("a shr of %d = %d\n", a_r_shift, a ); printf("a shl of %d = %d\n", a_l_shift, a ); printf("b shr of %d = %d\n", b_r_shift, b ); printf("b shl of %d = %d\n", b_l_shift, b ); printf("c shr of %d = %d\n", c_r_shift, c ); printf("c shl of %d = %d\n", c_l_shift, c ); ① -32 ② -24 ③ -20 ④ 12 A. printf("d shr of %d = %d\n", d_r_shift, d ); printf("d shl of %d = %d\n", d_l_shift, d ); } (나) 논리 연산자 ① 비트별 논리곱 Chapter 02 C 언어의 구성 및 문법 PART 07 C 언어 ① 2009 대전교육 &는 비트 단위로 AND연산을 수행하며, 연산하려는 두 개의 비트가 모두 1일 때만 결 개의 비트가 서로 다른 값을 가지고 있을 때 1을 반환한다는 의미로 해석되기도 한다. 과가 1이 되고 하나라도 0이면 결과는 0이 된다. 표로 정리하면 다음과 같다. 표로 정리하면 다음과 같다. 0&0 0&1 1 &0 1 &1 0^ 0 0^ 1 1 ^ 0 1 ^ 1 0 0 0 1 0 1 1 0 0x0F ^ 0xFF = ? (결과는 0xF0) 0x0F & 0xFF = ? (결과는 0x0F) 다음과 같은 연산을 하게 된다. 그럼 이번엔 0x0F와 0xFF를 XOR연산하면 아래 0x0F는 이진수로 00001111이고, 0xFF는 11111111이다. 그런데 &연산자는 모두 1 와 같이 계산된다. 일 때만 1을 돌려주므로, 00001111과 11111111에서 모두 1인 부분은 뒤쪽 4개의 0x0F = 00001111 비트이다. 그러므로 결과는 00001111 이다. ( ^ 연산) 0xFF = 11111111 0xF0 = 11110000 이것을 16진수로 고치면 0x0F가 된다. 다시 표로 정리하면 아래와 같다. ④ 1의 보수 0x0F = 00001111 ( & 연산) 0xFF = 11111111 0x0F = 00001111 ~는 1의 보수를 구하는 연산자로 그냥 쉽게 비트들을 반대로 즉, 0이면 1로 1이면 0 으로 바꿔버린다고 알고 있으면 된다. ~0 ~1 1 0 ② 비트별 논리합 |는 OR연산을 하는 것으로 &와는 달리 두개의 비트 중 1개라도 1이면 1을 돌려주는 2007 경상남도 연산자이다. Q. 표로 정리하면 다음과 같다. 0| 0 0| 1 1 | 0 1 |1 0 1 1 1 0x0F | 0xFF = ? (결과는 0xFF) 이유는 하나라도 1이면 1을 돌려주므로 아래와 같이 연산된다. 0x0F = 00001111 ( | 연산) 0xFF = 11111111 0xFF = 11111111 다음 보기의 연산을 참고하여 출력 값으로 적당한 것을 고르면? int a=2, b=3; int d=a&b; int e=a|b; int f=b<<3; int g=a--; printf("%d %d %d %d",d,e,f,g); ① 2 3 24 2 ② 1 3 12 2 ③ 2 3 48 1 ④ 2 3 24 3 A. ① ③ 비트별 배타 논리합 ^는 비트단위 배타 OR연산 즉, 비트단위 XOR연산을 하는 연산자이다. 이 연산자는 OR와 비슷하지만, 다른 점은 OR에서는 어느 하나가 1의 값을 가지면 1을 돌려주지만 XOR연산인 경우에는 두개의 비트가 모두 동일하면 0을 돌려준다는 것이다. 또는 두 4) 조건 연산자〔 ? : 〕 2002 경기도 2006 충청남도 2007 인천시 2009 국가직 ① 주어진 조건의 만족 여부에 따라 지정된 수식을 수행하는 연산자로, 수식으로 명령이 Chapter 02 C 언어의 구성 및 문법 PART 07 C 언어 나 연산식을 사용할 수 있다. 2010 국가직 7급 [형식] (조건)? 수식1 : 수식2 └──→ 조건이 참이면 수식1을 수행하고 조건이 거짓이면 수식2를 수행한 Q. 다음 C 프로그램의 실행 결과는? 다. #include <stdio.h> int main(int argc, char* argv[]) { int a = 1, b, c, d; d = (b= a++, c =b+2); printf( ″a=%d, b=%d, c=%d, d=%d\ n″, a, b, c, d); return 0; } 조건 연산자 예제 #include <stdio.h> void main() { int i=10, j; j = (i!=10)? (i+5) : (i-5); printf("j = %d",j); } [출력결과] j = 5 ① a=2, b=1, c=3, d=3 ② a=2, b=1, c=4, d=4 ③ a=2, b=2, c=3, d=3 ④ a=2, b=2, c=4, d=4 A. 5) 콤마(,) 연산자 또는 나열 연산자 ① 10 국가직 7급 ① 콤마가 분리시키는 수식이 좌변에서 우변으로 평가되는 것을 보장해 준다. 즉, 콤마 (,) 가 사용되었을 경우 우변을 평가하기 전에 좌변을 평가한다. ② 콤마(,)가 들어 있는 수식이 갖게 되는 값은 콤마의 오른쪽에 있는 수식의 값을 갖는 다. 즉, 전체 수식의 값은 우변 수식의 값이 된다. 나열 연산자 예제 int a, b; a = b = 15, b = 28; → a는 15, b는 28을 할당받는다. a =(b = 15, b + 28); → a는 43, b는 15를 할당받는다. 6) Cast 연산자 또는 형 변환 연산자 ① 할당된 자료의 값은 그대로 두고 지정된 자료의 자료형을 강제적으로 다른 자료형으 로 변환한다. ,(콤마) 연산자를 ++연산자와 결합하여 사용 int a=1, b=2, c=0; c=(a++, ++a, a++, a + b++); printf("%d, %d, %d", a, b, c); → a는 4, b는 3, c는 6을 할당받는다. 시에는 ,(콤마)연산자를 ;과 동일하게 취급하여 계산을 수행한다. 그러므로 첫 번째 항목인 a++를 수행 후 ++a 연산하기 전에 1을 증가시 킨 후 ++a연산을 수행한다. 그러므로 a는 3번 ② 예를 들면, 정수형을 실수형으로 자료형을 명시적(Explicit)으로 바꿀 때 사용한다. 형 변환 연산자 예제 을 1씩 증가하여 4가 할당된다. Chapter 02 C 언어의 구성 및 문법 PART 07 C 언어 7) sizeof 연산자 #include <stdio.h> void main() { float pi = 3.14; int i = (int)pi; printf("i = %d",i); } [출력결과] i = 3 2003 서울시 2007 군무원 ① 지정한 자료(자료형, 상수, 변수, 수식) 에 대한 기억장소의 크기를 구한다. ② 인자가 수식일 때에는 괄호를 붙이지 않아도 되지만 데이터 유형의 이름일 때에는 반 드시 괄호를 붙여야 한다. sizeof()연산의 예제 /* 32bit 기준 */ void main(){ char ch = 5; long a; a = sizeof(ch) + sizeof(long); //→ a의 값은 1 + 4 = 5이다. printf("%d\n",a); int i, j = 3; char c; printf( "%d\n", sizeof(i) + j );// sizeof(i) + j = 4 + 3 = 7 printf( "%d\n", sizeof(i + j) );// i + j 가 int 형이므로 4 printf( "%d\n", sizeof(i) + sizeof(j) );// 4 + 4 = 8 printf( "%d\n", sizeof(sizeof(c)) );// sizeof(c)는 1이 되고 int 형이므로 4 } /*각 자료형의 sizeof 연산 결과*/ main() { printf("The size of data types is computed\n\n"); printf("char = %2d byte\n",sizeof(char)); printf("short int = %2d bytes\n",sizeof(short int)); printf("int = %2d bytes\n",sizeof(int)); printf("long int = %2d bytes\n",sizeof(long int)); printf("float = %2d bytes\n",sizeof(float)); printf("double = %2d bytes\n",sizeof(double)); } [실행결과] The size of data types is computed char = 1 byte short int = 2 bytes int = 2 or 4 bytes (16비트에서는 2, 32비트에서는 4가 반환된다.) long int = 4 bytes float = 4 bytes double = 8 bytes Chapter 02 C 언어의 구성 및 문법 PART 07 C 언어 8) 주소 연산자〔&〕 2007 군무원 ① 주소 연산자(Address Operator)는 기억장소의 주소 값을 반환한다. 즉 &a는 변수 a 가 할당받은 기억장소의 시작주소 값을 반환한다. ② 포인터 유형의 변수는 주소를 값으로 가지기 때문에 이를 사용하려면 주소를 할당하 여야 하는데 C에서는 이를 위해 '&' 연산자를 제공하고 있다. 이는 “&변수이름”과 같은 형태로 사용한다. int *val; int add; // 변수 add가 위치하는 기억장소의 시작 주소가 val에 대입된다. val = &add; // (이때 변수 val는 포인터 변수이어야 한다.) 9) 포인터 연산자 또는 역참조 연산자〔*〕 2007 부산시 ① 포인터 변수를 사용하는 목적은 그 변수가 값으로 갖고 있는 주소의 데이터를 사용하 기 위해서이다. 포인터 변수가 값으로 갖고 있는 주소의 데이터를 사용하고자 할 때 사용 한다. ② 또 다음의 경우를 보면 int i = 10, j; int *ip = &i, *jp; jp = ip; j = *jp + *ip; ip가 i의 주소를 갖고 있는데 ip의 값을 jp에 할당했으므로 jp도 i의 주소를 갖고 있게 된다. 따라서 *ip와 *jp는 모두 i가 되며 따라서 위의 j = *jp + *ip는 j = i + i가 ☑ 포인터 변수에 주소를 할당할 때 '&' 연산자 사용 되어 j의 값은 20이 된다. ③ 위에서는 ip와 jp 둘 다 int 유형의 데이터의 주소를 갖는 포인터였기 때문에 jp = ip int i = 10; int *ip; ip = &i; 와 같이 값을 그대로 할당할 수 있었지만 만일 서로 다른 데이터 유형의 주소를 값으 로 갖는 포인터라면 이와 같이 할당할 수는 없고 다음과 같이 형 변환 연산자를 사용 ⦁포인터 변수 ip가 int 유형의 주소를 값으로 갖는 변수이기 때문에 같은 int 유형의 변수 인 i의 주소를 할당받고 있다. 그러나 다음과 같이 할당 할 수는 없다. 해야만 한다. int i = 10, *ip = &i; char c = 'A', *cp = &c; cp = (char *)ip; char c; int *ip; ip = &c; ⦁c가 int 유형이 아닌 char 유형의 변수이기 때문이다. 포인터의 경우에 같은 유형의 포인 터 값이 아니면 컴파일시에 바로 에러가 나게 된다. 그러나 다음과 같이 형 변환을 사용 하면 다른 데이터 유형의 주소를 포인터 변수에 할당할 수 있다. ④ 그러나 위와 같이 한다고 해서 cp의 값과 ip의 값이 다른 것은 아니다. 둘 다 변수 i 의 주소를 값으로 갖게 되는데 '*' 연산자를 사용할 때 차이가 발생한다. 즉, *ip의 경 우에는 주소에 int 유형의 데이터가 있다고 간주하여 그 주소로부터 2바이트의 값을 char c; int *ip; ip = (int *)&c; 가져오는 반면 *cp의 경우에는 주소에 char 유형의 데이터가 있다고 간주하여 그 주 소로부터 1바이트의 값만 갖고 오게 된다. ⦁또 '&' 연산자를 사용하면 포인터 유형의 변수들에게 다음과 같이 초기값을 줄 수 있다. int i = 10; int *ip = &i; char c = 'A'; char *cp = &c; ⦁'&' 연산자는 변수 이외의 것에는 사용할 수 없으며, 따라서 다음과 같이 사용할 수 없다. ⑴ ⑵ ⑶ ⑷ &3 // 3은 변수가 아니라 상수이다. &(x+y) // x+y는 변수가 아니라 수식이다. &&x // &(&x)가 되어 &(주소)가 되는데, 주소는 변수가 아니다. register int x; // register 유형의 변수는 주기억 장치가 아닌 레지스터에 &x; // 할당되기 때문에 주소라는 것이 없다. Chapter 02 C 언어의 구성 및 문법 PART 07 C 언어 포인터의 자료형과 할당받은 주소값의 자료형이 다를 경우. main() { int i = 256; /* 256 == 0x100 */ int *iptr; iptr = &i; printf("%d\n",*iptr); } /* *iptr은 iptr이 가리키고 있는 메모리의 내용 */ [실행결과] 256 main() { int i = 256; char *iptr; iptr = (char *)&i; // 형 변환 연산자가 없으면 경고 메시지가 출력됨 printf("%d\n",*iptr); } // iptr이 char형이기 때문에 1바이트만을 참조함 [실행결과] 0 ☑ NULL 포인터 ⦁포인터가 가질 수 있는 값 중에 NULL이란 것이 있는데, 먼저 #include <stdio.h>를 선언해야만 사용할 수 있다. 이는 실제로 0의 값인데 포인터 변수가 이 값을 갖게 되면 0번지를 값으로 갖는 것이 아니라 아직 값이 없는 것이 된다. 따라서 포인터 변수에 초기 값을 주고 싶을 때에는 이 NULL을 다음과 같이 주면 된다. #include <stdio.h> char *cp = NULL; ☑ 포인터 변수에 바로 주소를 할당 주소는 양의 정수이기 때문에 다음과 같이 직접 주소를 할당하는 것이 실제로 가능하다. int *ip = (int *) 2000; /* 반드시 형 변환 연산자를 사용하여야 한다. */ ⦁위와 같이 직접 주소를 할당하였을 때에는 당연히 그 주소에 해당 데이터 유형의 데 이터가 있어야 한다. 예를 들어 위의 경우에 2000번지에 int 유형의 데이터가 있어 야 한다. 그렇지 않은 경우에는 위의 포인터를 사용할 때 에러가 발생하게 된다. ⦁PC의 경우에는 주소가 고정되어 있는 경우가 많기 때문에 위와 같이 주소를 직접 지정해 주는 것이 의미가 있는데, 특히 비디오 메모리를 액세스할 때에는 직접 주소 를 할당하는 것이 더 효율적인 경우가 많다. Chapter 02 C 언어의 구성 및 문법 PART 07 C 언어 4. 제어 (2) 연산자의 결합방향과 우선순위 2006 전라남도 2006 군무원 2006 인천시 06 국가직 7급 08 경기도 7급 종류 괄호, 구조체, 공용체 연산자 단항 연산자 연산자 2008 경기도 2008 서울시 결합방법 우선순위 ( ) [ ] -> 좌⇒우 높다 ! ~ ++ -- & * sizeof() 우⇒좌 구조 (1) 조건문 1) if 문 (가) 단순 if 문 05 국가직 7급 * / % ① 주어진 조건의 만족 여부에 따라 특정 명령문을 수행한다. 더하기/빼기 + - ② 조건을 만족하면 주어진 명령문을 수행하고, 그렇지 않으면 다음 명령문을 수행한다. shift 연산 << >> 크기 비교 < <= > >= 곱하기/나누기 이항 동일값 판정 연산자 비트연산 AND & 비트연산 XOR ^ 비트 OR | if(조건) 명령문; if(조건) { 명령문 1; … 명령문 2; } == != 논리연산 AND && 논리연산 OR || 좌⇒우 (나) if ~ else 문 ① 주어진 조건의 참∙거짓 결과에 따라 참일때에는 if이하 명령문을 수행하고, 거짓일 경 조건 연산자 ?: 대입 연산자 += -= *= /= %= &= |= <<= >>= 우⇒좌 콤마 연산자 , 좌⇒우 우에는 else이하 명령문을 수행한다. 낮다 if(조건) 명령문 1; else 명령문 2; 2008 서울시 Q. 2005 국가직 다음 C언어의 수식에서 연산되는 순서를 ( )로 바르게 나타낸 것은? a =b =c‖ a > b ?a: b (다) 다중 if ~ else 문 ① 주어진 조건의 참∙거짓 결과에 따라 지정된 명령문을 수행한다. ① a = ( b = ( c ‖ (( a > b ) ? a : b ))) ② else 는 가장 가까운 if 문과 대응되어 하나의 if ~ else 문을 형성한다. ② a = ( b =((( c ‖ a ) > b ) ? a : b )) ③ ( a = b ) =((( c ‖ a ) > b ) ? a : b ) ④ a = ( b = (( c ‖ ( a > b )) ? a : b )) ⑤ a = ((( b = c ) ‖ ( a > b )) ? a : b ) A. ④ Chapter 02 C 언어의 구성 및 문법 if(조건 1) if(조건 2) 명령문 1; else 명령문 2; else 명령문 3; PART 07 C 언어 2) switch~case 문 2006 전라남도 06 국가직 7급 2007 경기교육 2008 광주시 ① 주어진 값에 따라 지정된 명령문을 수행한다. ② 수식의 값과 일치하는 경우의 값이 있는 명령문을 수행하고, 수식의 값과 일치하는 2006 국가직 7급 Q. 값이 없으면 default의 명령문 n을 수행한다. int sum = 10; switch(1){ case 1: case 1: case 2: case 2: default: } printf("value of ③ break를 만나면 switch 블록을 탈출하나, break가 없으면 수식의 값에 해당하는 경 우부터 break가 있는 곳까지 수행한 후 switch 블록을 탈출한다. switch(수식) { case 1 : case 2 : case 3 : ⋮ default : } 다음은 C언어 프로그램이다. 출력값으로 옳은 것은? 명령문 1; break; 명령문 2; break; 명령문 3; break; 명령문 n; break; sum += 1; sum += 1; sum += 2; { sum += 2; break; } sum =0; sum is %d", sum); ① value of sum is 10 ② value of sum is 16 ③ value of sum is 12 ④ value of sum is 0 A. ② break문이 없을 경우의 switch~case문 예제 char ch; ch = getchar(); switch(ch){ case ('A') : putchar('a'); case ('B') : putchar('b'); case ('C') : putchar('c'); case ('D') : putchar('d'); case ('E') : putchar('e'); default : putchar('f'); } [실행결과] A 입력 시 abcdef, C 입력 시 cdef, X 입력 시 f (2) 반복문 1) for 문 2006 울산교육 2006 충청남도 2006 경기교육 2007 경기도 08 국가직 7급 (가) 단순 for 문 for (int i =0 ; i<5; i++){ 처리 } ① 조건식이 거짓이면 블록을 탈출한다. ② for 블록의 실행순서는 조건식(i<5)이 참(True)일 동안 처리구문을 반복 실행한다. (나) 중첩된 for문 ① for문 안에 또 다른 for문이 내포되어 수행할 수 있다. int n = 0 ; for(i = 0 ; i < 5 ; i++){ for( j = 0 ; j < 5 ; j++){ n++; } } [실행결과] 25 Chapter 02 C 언어의 구성 및 문법 2008 국가직 PART 07 C 언어 (다) for문 사용의 여러 가지 형태 ① for( ; 2009 국가직 7급 ; ) → 세미콜론만 있으면 무한루프가 된다. ② for( ; 1 ; ) → 조건식만 있다. 상수 1이므로 항상 참이 된다. 역시 「무한루프」 Q. ① int sum(int a[], int n){ int i, s=0; for (i=0; i<n; i++) s += a[i]; return s; } ③ int sum(int a[], int n){ int i, s=0; for (i=0; i<n; i++) s += *a++; return s; } ③ for( i=5 ; i<9 ; ) → 증감식이 생략되어 있다. ④ for 문에 사용되는 초기식, 조건식, 증감식은 선택적으로 기술할 수 있다. 즉, 필요없는 식은 생략할 수 있다. 그러나 ;은 생략할 수 없다. 2011 국가직 7급 Q. 다음의 4가지 C 함수들 가운데 그 의미가 나머지와 다른 것은? 다음 C 프로그램의 실행 결과로 옳은 것은? #include <stdio.h> int getnext(int a) { return (a * 2 + 1); } void main() { int i, j, k = 0; for (i = 1; i < 10; i++) for (j = 1; j < getnext(i); j++) k++; printf("k = %d\n", k); } ② int sum(int *a, int n){ int i=0, s=0; while (i<n) s += a[i++]; return s; } ④ int sum(int *a, int n){ int i=0, s=0; while (i<n) s += a[i]++; return s; } A. 3) do~while 문 05 국가직 7급 2006 국회사무 ④ 2007 군무원 2007 경기도 do { ① k = 90 ② k = 99 ③ k = 110 ④ k = 120 반복 실행될 문장; } while(조건식); A. ① ① 반복문 내의 명령식들을 먼저 실행한 후, 주어진 조건을 검사하여 반복 수행여부를 결정한다. 2) while 문 2006 전라남도 2009 지방직 ② 조건 검사를 나중에 하기 때문에 적어도 한번은 수행된다. while(조건식) { 반복 실행될 문장; } ① 주어진 조건이 만족되는 동안 루프문을 반복 수행한다. ② 먼저 조건식을 판단한 후 참이면 블록 내부를 실행하며, 조건식이 거짓이면 블록을 탈출한다. Chapter 02 C 언어의 구성 및 문법 PART 07 C 언어 2011 서울시 Q. 2008 국가직 7급 Q. 다음 C언어로 작성된 반복문 중 실행 결과 r의 값이 다른 하나는? ① for(x=1; x<99; x++) r=r+x; ② x=1; while(x<99) {x++; r=r+x;} ③ x=1; do {r=r+x; x++;} while (x<99); ④ for(x=1; x<99; x=x+2) {r=r+x+x+1;} ⑤ x=1; while(x<99) {r=r+x; x++;} A. 4) break / continue 문 ② 2007 경기교육 2007 경상남도 2009 지방직 while(조건식){ ⋮ continue ;//블록의 조건식으로 복귀 ⋮ break ;//블록을 탈출 ⋮ } 다음 C 프로그램 코드가 실행된 후, 변수 n의 값으로 옳은 것은? #include <stdio.h> void main() { int i, j, sum = 0; for (i = 1; i < 10; i ) { for (j = 1; j < 10; j ) { if (j%3 == 0) continue; if (i%4 == 0) break; sum ; } } printf("%d\n", sum); } ① 42 ② 81 ③ 27 ④ 12 A. ① continue∶for, while, do~while에서 블록의 조건식으로 복귀하고자 할 때 사용한다. ② break∶for, while, do while, switch에 블록을 강제적으로 벗어나고자 할 때 사용한다. 5) goto 문 Label : 처리 ⋮ goto Label; ① 프로그램의 실행을 특정 위치로 이동시킬 때 사용한다. ② goto 문을 사용할 수 없는 경우 ㉠ 반복문이나 if 조건문 범위 밖에서 안으로 이동한 경우 ㉡ for 문의 범위 안으로 이동한 경우 Chapter 02 C 언어의 구성 및 문법 PART 07 C 언어 ① 5. 배열과 포인터 2002 경기도 2007 경남 (1) 배열(Array) 2009 국가직 7급 Q. 1) 특징 C 언어에서 int a[10];과 같이 선언하는 경우에 대한 설명으로 옳은 것은? ① a배열이 필요로 하는 기억장소의 용량이 번역시간에 확정된다. ① 같은 이름을 갖는 하나 이상의 변수 리스트들이다. ② a = 10;과 같은 동작이 허용된다. ② 동일한 자료형으로 이루어진 자료들을 처리할 때 효율적인 자료처리를 가능하게 한다. ③ 프로그램 실행 중에 a배열의 크기가 변한다. ③ 모든 배열은 자료형과 기억클래스를 가진다. ④ a 배열이 저장되는 기억장소 내 주소는 컴파일러가 결정한다. ④ 배열의 크기를 나타내는 수인 첨자는 정수만 사용할 수 있다. A. ① ⑤ 배열의 각 요소들은 메모리영역에 연속적으로 할당되며 배열명은 배열의 시작주소가 기억된 포인터 상수이다. ⑥ 배열의 첨자가 할당된 영역의 범위를 벗어나면 런타임 에러가 발생한다. 3) 배열의 초기화 ① 일차원 배열 2) 배열 선언 ㉠ int array[5] = { 1, 2, 3, 4, 5 } ; ① 대괄호[ ]에 생성하고자 하는 개수만큼 정수를 넣어 배열을 선언한다. char array 1 array[0] 2 array[1] 3 array[2] 4 array[3] 5 array[4] [5] ; 그림 7.3 배열의 개수(반드시 인덱스는 0부터 시작하여야만 한다.) 일차원 배열 ㉡ int array[5] = {1, 2, } ; 배열 명 선언된 배열의 요소를 초기화하지 않은 경우, 배열요소 중 array[0]=1, array[1]=2 배열의 데이터타입 로 초기화되고, 나머지 선언되지 않은 배열요소 값은 모두 0으로 초기화 된다. 단, 마지막에 콤마는 없어도 된다. 위와 같이 선언하면 다음과 같이 char형의 5개 배열 요소가 지정된다. array[0] array[1] array[2] array[3] array[4] ㉢ int array[5] = { } ; 선언된 배열의 요소를 {}으로 할당한 경우에는 모든 배열요소가 0으로 초기화되어 할당된다. 1차원 배열의 초기화 예제 C에서는 배열의 첨자는 0부터 시작되고, [ ]가 사용된 개수에 의해 다차원 배열로 선언한다. int a = 3, ave[10]; ave[a] = 100; ave[9] = 200; ave[10] = 400; → 오류가 발생한다. 정의할 때 '10'이라고 크기를 정했기 때문에 첨자가 쓰일 때는 '0 ~ 9'까지 쓸 수 있다. ⑴ int ave[10] = { 10, 30, 50, 70, 100, 40, 30, 55, 223, 765 }; 모든 배열의 원소를 초기화한 것이다. ⑵ int ia[] = { 10, 30, 50, 70, 100, 40, 30, 55, 223, 765 }; 첨자를 생략한 경우이다. 첨자를 생략했다는 것은 배열의 크기를 생략했다는 뜻이 된다. 이러한 경우는 배열의 모든 데이터를 초기화할 때만 가능한 것이며, 첨자를 생략하면 컴파일러는 초기화한 데이터의 개수만큼의 배열을 자동으로 잡게 되어 있 다. 즉, 초기화한 데이터가 10개 이므로 배열은 10개가 잡히게 된다. ⑶ int ja[10] = { 10, 30, 50, 70, 100, 40, 30, }; // 숫자 뒤에 콤마가 있다. 데이터의 개수가 7개 밖에 없으며 마지막 데이터 뒤에는 콤마가 찍혀있는데, 이것은 10개의 배열 중에서 ja[0]부터 ja[6]까지만 초기화하고 나머지는 모두 0으로 초기화 하라는 뜻이다. (실수 데이터 유형의 경우에는 당연히 0.0이 되며 char 유형의 경우 Chapter 02 C 언어의 구성 및 문법 PART 07 C 언어 에는 널 문자('\0')가 되고 포인터 데이터 유형의 경우에는 널 포인터(NULL)가 된 다.) ⑷ int ka[3] = { 1, 10, 5, 7, 8 }; 지정한 원소의 개수보다 더 많은 초기값을 주었을 때에는 컴파일 에러가 발생하기 때문에 주의하여야 한다. ⑸ char ca[5] = { "Test" }; char 유형의 배열에 스트링 형태로 초기값을 준 것인데, 스트링은 여러 개의 문자 들이 모인 것으로 맨 끝에 널 문자('\0')가 있는 것이 다르다. 따라서 위의 정의는 다음과 같은 의미를 갖는다. char ca[5] = { 'T','e','s','t','\0' }; 또한 초기값을 스트링 형태로 준 경우에는 다음과 같이 중괄호를 생략할 수 있다. char c3[] = "Computer"; char c4[10] = "string"; ② 이차원 배열 array[3][3] ⇒ 1 2 3 array[0][0] array[0][1] array[0][2] 2byte 할당 4 2byte 할당 5 2byte 할당 6 array[1][0] array[1][1] array[1][2] 2byte 할당 7 2byte 할당 8 2byte 할당 9 array[2][0] array[2[1] array[2][2] 2byte 할당 2byte 할당 2byte 할당 그림 7.4 이차원 배열 (16bit 기준) ㉠ int array[3][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9} ; → 이차원 배열을 1차원처럼 선언하면 행 우선으로 순차적으로 배치된다. ㉡ int array[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}} ; array[0][0] array[0][1] array[0][2] array[1][0] array[1][1] array[1][2] array[2][0] array[2][1] array[2][2] ⑵ int ia[][3] = { 1, 2, 3, 4, 5, 6 }; 아예 중괄호 구분을 없애고 하나로 초기값을 주고 있다. 이 경우 메모리에 위치하는 순서대로 차례로 초기값이 할당된다. 그리고 맨 처음 첨자를 생략했는데, 모두 생략 할 수는 없고 맨 처음 첨자만 생략이 가능하다. 그러나 ⑶과 같이 모두 생략할 경우 컴파일 에러가 발생한다. ⑶ int ia[][] = { 1, 2, 3, 4, 5, 6 }; 이와 같이 첨자를 모두 생략하면 에러가 발생한다. ⑷ int ja[2][3][2] = { { {1,2},{3,4},{5,6} }, { {7,8},{9,10},{11,12} } }; 3차원 배열과 같은 경우는 배열의 첨자에 맞추어 블록으로 묶어서 초기화할 수 있 다. ⑸ int ja[][3][2] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; 3차원 배열도 마찬가지로 맨 처음 첨자는 생략할 수 있으나, 그 외 첨자는 생략할 수 없 다. int array[3][3] array[0][2] array[1][2] array[2][2] ⇓열 - 물리적 표현 Chapter 02 C 언어의 구성 및 문법 array[2] : 부분배열 a[2]의 시작주소 ⑴ int ia[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } }; 첫 번째 중괄호는 초기값 전체를 의미한다. 그 안에 다시 두 개의 중괄호가 있는데, 이는 각각 ia[0]으로 시작하는 행과 ia[1]로 시작하는 행에 대한 초기값을 의미한다. 즉, 초기값도 각 행별로 주게 되며 각 행은 중괄호로 구분하게 된다. - 논리적 표현 array[0][1] array[1][1] array[2][1] array[1] : 부분배열 a[1]의 시작주소 다차원 배열의 초기화 예제 ㉢ 이차원배열의 논리적, 물리적 표현 ⇒행 array[0][0] array[1][0] array[2][0] array : 배열 전체의 시작주소 / array[0] : 부분배열 a[0]의 시작주소 PART 07 C 언어 4) 배열과 문자열 2011 국가직 7급 Q. 2007 경기교육 ① 문자열(String) 다음 C 프로그램은 2차원 배열 x의 각 원소 값을 두배로 만들기 위한 것이다. ㉠과 ㉡에 들어갈 내용으로 옳지 않은 것은? (Character)가 연결된 구조인 배열로 선언 할 수 있으며, 반드시 '\0'으로 끝나야 한다. '\0'은 Null문자로 칭하고, 입출력 시 문자열의 끝을 판단하는데 이용한다. #include <stdio.h> ㉠ ㉡ 아래와 같이 문자열 "TOPSPOT"은 다음과 같이 메모리에 할당하는 방법이 존재한 // 배열의 원소 값을 두배로 하는 함수 정의 다. '\0'(Null문자)는 프로그래머가 지정하지 않아도 마지막이 '\0'로 끝나야 하 void main() { int x[2][3] = {{1, 2, 3}, {4, 5, 6}}; ㉡ ㉠ C 언어에서는 문자열 자료형이 별도로 지원되지 않기 때문에 여러 개의 문자 므로 컴파일러가 자동으로 기억시켜 주게 된다. char str[8]="TOPSPOT"; 또는 char str[]="TOPSPOT"; // 함수 ㉠ 호출 char str[8]={ 'T','O','P','S','P','O','T' }; 또는 char str[]={'T','O','P','S','P','O','T' } }; ① ㉠ ㉡ ② ㉠ ㉡ ③ ㉠ ㉡ ④ ㉠ ㉡ 'T' void dubl(int ary[][], int row, int col) { int i, j; for (i = 0; i < row; i++) for (j = 0; j < col; j++) ary[i][j] *= 2; } dubl(x, 2, 3); 'O' 'P' 'S' 'P' 'O' 'T' '\0' 따라서 문자열을 처리할 때 문자열의 길이에 대한 정보는 필요 없다. printf 구문 의 %s 기호를 통해 출력 시 문자열이 시작하는 메모리의 주소값을 시작으로 하나 씩 꺼내어 출력하다가 '\0'를 만나면 출력을 종료한다. void main() { char str[] = "TOPSPOT"; printf("%c, ", str[0]); /* str[0]의 값을 문자로 출력 */ printf("%s", str); } /* str배열의 문자열 출력 */ [실행결과] T, TOPSPOT void dubl(int ary[], int size) { int i; for (i = 0; i < size; i++) ary[i] *= 2; } int i; for (i = 0; i < 2; i++) dubl(x[i], 3); ② 다차원 문자 배열 ㉠ 여러 개의 문자열을 한꺼번에 배열에 기억시키려면 다차원 배열을 이용해야 한다. ㉡ 문자열의 끝을 의미하는 '\0'가 수록되어야 하므로 열의 크기는 「가장 긴 문자열 길 이 + 1」 이어야 한다.(문자열의 길이가 다를 경우 메모리의 낭비가 발생될 수 있 void dubl(int ary[], int size) { int i; for (i = 0; i < size; i++) ary[i] *= 2; } dubl(x[0], 6); 다.) ㉢ 문자열 "LOW", "MIDDLE", "HIGH"를 배열에 기억시키는 방법을 살펴보자. 'L' 'M' 'H' 'O' 'I' 'I' 'W' 'D' 'G' 그림 7.5 void dubl(int *ary, int size) { int i; for (i = 0; i < size; i++) *(ary + i) *= 2; } dubl(x[0], 6); A. ① Chapter 02 C 언어의 구성 및 문법 PART 07 C 언어 '\0' 'D' 'H' '\0' 'L' '\0' 다차원 문자 배열 '\0' 'E' '\0' '\0' '\0' '\0' ☑ 2차원 배열에 문자열을 기억시킬 때 주의점 ☑ '\0'의 개념 a. 「0, '\0', '0'」 로 표현되는 이들 3가지의 값들이 기억장소 1byte에 2진수로 어떻 게 표현되는지 알아보면 모든 것은 해결될 것이다. a. 첫 번째 첨자는 생략할 수 있으나 두 번째는 생략할 수 없다. b. 배열의 열 크기는 「가장 긴 문자열 길이 + 1」 이어야 한다. c. NULL 문자('\0')를 기억시킬 배열요소가 없으면 '\0'가 문자열 끝에 들어가지 않 는다. → 문자열이 될 수 없음 0 00000000 → 수치 0 ‘\0’ 00000000 → ASCⅡ 코드 0번 ‘0’ 001 1 0000 → 문자 ‘0’은 ASCⅡ 코드값 48이므로 d. 배열의 자료형은 char형으로 하여야 한다. void main() { char array[][7] = {"LOW", "MIDDLE", "HIGH"}; printf("%c, ", array[0][0]); /* a[0][0]의 값을 문자로 출력 */ printf("%s, ", array[0]); printf("%s, ", array[1]); printf("%s", array[2]);} /* 문자열 출력 */ [실행결과] L, LOW, MIDDLE, HIGH b. 수치 0과 문자 ‘0’은 엄연히 다르다. Escape sequence방식으로 표현된 '\0'은 ASC Ⅱ 코드 0번을 의미하는 것으로 수치 0과 같은 개념이다. 즉, '\0'은 논리값을 판 단할 때 'false'로 계산된다. (2) 포인터(Pointer) 2003 국가직 1) 포인터의 개요 2007 경기도 교육청 Q. ① 포인터는 주소를 나타내는 데이터 유형이다. 다시 말해서 포인터 데이터 유형의 값은 <보기> 프로그램의 [가]에서 출력된 값이 “12345036” 이라고 가정할 때 [나]에서 출력되는 값은? 주소라는 얘기가 되며, 이 주소로 역시 숫자를 사용하고 있다. 단지 주소에는 음수가 있을 수 없기 때문에 포인터 데이터 유형의 주소는 양의 정수가 되며 외관상으로 unsigned 데이터 유형과 같게 된다. #include<stdio.h> void main(){ float a[5]; printf("%u",a); //[가] printf("\n"); printf("%u",&a[1]); //[나] } ② 기억공간의 주소를 갖는 변수를 포인터 변수 또는 포인터라고 하며 *를 사용하여 포 인터를 선언한다. [형식] 자료형 *포인터 변수명; 예제) int *ptr; 2) 포인터의 구조 ① 12345036 ② 12345040 ③ 12345048 ④ 12345052 ① 포인터 : 다른 변수(대상체)의 주소를 갖는 자료. A. ② C의 변수 종류 일반 변수 포인터 변수 ② 포인터의 선언과 초기화 Chapter 02 C 언어의 구성 및 문법 PART 07 C 언어 내용 값(Value) 주소(address) type <변수형지정자 > int * pvar; * pointer-variable; * <변수명>; 3) 포인터를 이용한 참조에 의한 호출 ① C에서는 모든 것을 값에 의한 호출 형태로 인자를 전달하고 있다. 값만 넘어가기 때문 에 받은 쪽에서는 부른 쪽의 데이터를 변경할 수 없게 된다. 반면에 참조에 의한 호출 비교) pvar : 포인터변수 (정수형 변수의 주소를 취할 수 있음) *pvar : 포인터 변수가 가리키는 주소의 메모리 참조 &pvar : 포인터 변수 자체의 주소값. ㉠ 포인터 변수의 크기는 참조할 대상체의 크기와 무관하게 항상 일정하다. (해당 컴파일러의 int형 크기와 같다 : 2 byte or 4 byte) ㉡ 포인터 변수의 초기화는 동일한 형의 포인터이어야 한다. ㉢ 포인터 변수는 역참조 연산자(*)를 사용하여 해당 대상체를 참조할 수 있다. ㉣ 포인터 변수는 초기화 된 후에만 역참조 연산자(*)를 사용할 수 있다. ③ 지금까지의 변수 정의와 다른 것은 변수 앞에 '*'가 있는 것인데, '*'는 뒤의 변수가 포인 터 유형의 변수임을 나타내는 역할을 한다. 다음은 포인터 변수를 정의한 몇 가지 예 이다. a. int *ip; -> int 유형의 데이터가 기억되어 있는 주기억 장치의 주소를 값으로 갖는 포 인터 변수 ip를 정의한 것이다. b. char *cp; -> 포인터 변수 cp를 정의한 것으로 이 주소에는 char 유형의 데이터가 있음 을 의미한다. c. int *ip, *jp; -> 같은 데이터 유형의 포인터 변수들을 한 번에 같이 정의한 것으로, 이때 각 포인터 변수 앞에 '*'를 붙여야 한다. d. int *ip, jp; -> ip는 포인터 변수이지만 jp는 그냥 int 유형의 변수가 되므로 주의해야 한 다. 실제로 위의 변수들은 주소를 값으로 갖는다는 점에서는 같다. 그러나 그 주소에 어떤 데이터가 있느냐가 다르기 때문에 ip의 값을 cp에 할당할 수 없으며, 마찬가지로 cp의 값을 ip에 할당할 수 없다. 의 경우에는 변수 자체가 넘어가기 때문에 받은 쪽에서 부른 쪽의 데이터를 변경할 수 있게 되는데 C에서는 참조에 의한 호출을 전혀 지원하지 않기 때문에 이를 기본적으로 는 할 수 없지만 포인터를 사용하면 이와 같은 효과를 낼 수 있다. ② 실인자에 값을 주는 것이 아니라 변수가 할당되어 있는 번지를 건네줌으로써 간접적 인 참조에 의한 호출을 행한다. 다음은 그 프로그램의 예이다. void swap(int *, int *); main() { int i = 10, j = 20; printf("i = %d, j = %d\n",i,j); swap(&i,&j); /* '&'연산자를 사용하여 주소를 넘겨주고 있다 */ printf("i = %d, j = %d\n",i,j); } /*받는 쪽은 주소를 받아야 하므로 포인터가 된다 */ void swap(int *ip, int *jp) { int t; t = *ip; *ip = *jp; *jp = t; } [실행결과] i = 10, j = 20 i = 20, j = 10 ③ 결과적으로 변수 i와 j를 넘겨준 참조에 의한 호출과 같은 결과를 낳게 되었다. 그러 나 실제로 참조에 의한 호출로 인자가 전달된 것은 아니다. 역시 값만 넘어 갔는데 그 값이 바로 주소였기 때문에 swap에서 main의 변수를 사용할 수 있었던 것이다. ④ 어떤 변수를 참조에 의한 호출로 전달하고자 할 때에는 부르는 쪽에서는 그 변수의 주소를 넘겨주고, 받는 쪽에서는 이에 대한 포인터 변수로 받으면 된다. 그러면 받는 쪽에서 부르는 쪽의 변수를 마음대로 사용할 수가 있게 된다. ④ 포인터 변수는 선언된 포인터 자료형과 일치되는 자료형 변수의 주소를 할당 받을 수 있다. 다음은 포인터 변수에 값을 할당하는 몇 가지 예이다. int var , *pvar = &var; int var1, *pvar1, *pvar2; pvar1 = &var1; *pvar = *pvar1 = 10; //(O) *pvar2 = 10; //(X) Chapter 02 C 언어의 구성 및 문법 PART 07 C 언어 2011 국가직 7급 Q. 2008 국가직 9급 Q. 다음 C 프로그램의 실행 결과로 옳은 것은? 다음 C프로그램의 실행 결과는? #include <stdio.h> #include <stdio.h> void swap(int i, int *j) { int tmp; tmp = i; i = *j; *j = tmp; } void main() { int i, j; i = 10; j = 9; swap(i, &j); printf("%d\n", i - 1); } int main() { static char *c[]={aaa,bbb,ccc}; printf("%s",*(c+1)); } ① aaa ② bbb ③ ccc ④ aaabbbccc A. 5) 포인터 연산 ① 8 ③ 10 ② 2008 국가직 ① 포인터는 주소연산을 할 수 있다. 포인터를 1 증가시키면 포인터가 가리키는 주소값이 ② 9 ④ 11 증가하는데, 실제 주소의 증가량은 포인터가 가리키는 자료형의 크기만큼 증가된다. A. ② 포인터 변수는 int형일 수도 있고, char형일 수도 있고 float형 일수도 있다. 하지만 그것에 무관하게 메모리에서 차지하는 양은 단지 2바이트(16비트 기준) 또는 4바이트 4) 포인터와 문자열 2008 경기도 2008 국가직 ① char *p = "TOPSPOT" ; 라고 선언하면 아래와 같이 메모리에 할당된다. (32비트 기준)만을 차지한다. ② 포인터 변수의 주소연산 시 증가량 'T' 'O' 'P' 'S' 'P' 'O' 'T' '\0' 선언된 포린터 변수의 자료형에 따라 주소연산 시 증가량이 다르다. 즉, char형은 포 *p *(p+1) *(p+2) *(p+3) *(p+4) *(p+5) *(p+6) *(p+7) 인터 변수에 1을 더할 때 마다 1바이트를 차지하므로 1바이트씩 이동하고, short형은 여기서 ‘\0’은 널 종료문자(Null Terminator)로 C에서는 문자열의 끝을 표시하기 위해 사 용하며 위의 그림을 기준으로 하면, 문자열의 시작 주소인 포인터 변수 p를 기준으로 ‘+’ 2바이트를 차지하므로 2바이트씩 이동한다. 즉 자료형에 할당된 바이트 수만큼 증가 한다. 연산자를 이용하여 문자를 출력하거나 문자열을 출력할 수 있다. Chapter 02 C 언어의 구성 및 문법 PART 07 C 언어 2008 국가직 7급 ☑ 포인터와 기억공간의 대응관계 ( 32비트 기준 => int 4바이트 ) 주소 <int *p> 메모리 1000 ⇒ 포인터 ←p 주소 1000 ⇒ *p 1004 ⇒ ← p+1 포인터 ←p 1001 ⇒ ← p+1 *(p+1) ← p+2 1002 ⇒ *(p+2) 10012 ⇒ Q. *p *(p+1) 1008 ⇒ <char *p> 메모리 ← p+2 *(p+2) ← p+3 1003 ⇒ ← p+3 *(p+3) *(p+3) ⋮ ⋮ 다음 C 프로그램 코드에서 정수형 변수 a가 저장되어 있는 메모리 주 소는 1000번지, 문자형 변수 b가 저장되어 있는 주소는 2000번지라고 가정하였을 때, 프로그램 코드가 실행된 후 i_ptr과 c_ptr에 저장되어 있는 값은? (단, 정수형 변수는 4바이트가 할당된다고 가정한다.) int a, *i_ptr; /* a 변수의 저장 주소는 1000번지 */ char b, *c_ptr; /* b 변수의 저장 주소는 2000번지 */ i_ptr = &a; c_ptr = &b; i_ptr = i_ptr + 2; c_ptr = c_ptr + 2; ① i_ptr : 1002, c_ptr : 2002 ② i_ptr : 1008, c_ptr : 2008 ☑ 포인터 연산 예제 ③ i_ptr : 1004, c_ptr : 2004 #include<stdio.h> void main(){ char *p, i='a'; p=&i; printf("p = %x\n",p); printf("p+1 = %x\n",p+1); printf("p+2 = %x\n",p+2); ④ i_ptr : 1008, c_ptr : 2002 A. ④ ③ *p++와 ++*p의 계산의 차이점 ㉠ int *result = *p++; -> p++를 먼저 계산 후, result 변수에 p번지의 값을 할당 printf("*p = %c\n",*p); printf("*(p+1) = %x\n",*(p+1)); printf("*p+1 = %c\n",*p+1); ㉡ int result = ++*p; -> p가 가르키는 번지에 들어있는 값을 꺼낸 후, 1을 더해서 result 변수에 할당 ※ 단항연산자는 연산자 방면이 우 ⇒ 좌이므로 포인터 변수를 기준으로 오른쪽 연산자 } [출력결과] p = 1000 p+1 = 1001 p+2 = 1002 부터 순차적으로 계산한다. 이때 *연산자 이전의 ++ 연산자는 주소이동을 말하며, 이후의 연산자는 산술 연산을 의미한다. ④ 다음은 포인터 연산에서 사용할 수 없는 것들이다. int *ip, *jp; *p = a *(p+1) = ffcc *p+1 = b char *cp; // 쓰레기값 a. ip + jp /* 두 포인터 간에 덧셈은 할 수 없다.*/ b. ip * 2 /* 포인터 변수에 곱셈을 하게 되면 컴파일 시 에러가 발생한다.*/ c. jp / 3 /* 사용할 수 없는 연산자를 사용했다.*/ d. ip + 3.2 /* 정수값만 더해야 하는데 실수값(3.2)을 더했다.*/ e. ip - cp /* 같은 데이터 유형의 포인터들 사이에서만 뺄셈을 할 수 있다.*/ f. ip - 1 /* 포인터 변수에 -연산을 하면 자료형 크기만큼 앞쪽으로 이동한다.*/ Chapter 02 C 언어의 구성 및 문법 PART 07 C 언어 g. ip = jp /* 같은 데이터 유형의 포인터들 사이에서만 주소를 할당할 수 있다.*/ ※ 배열의 경우에도 첨자에 음수가 올 수 있다. 물론 알 수 없는 값을 출력한다. ② 포인터끼리 뺄 수는 있다. 2011 경기 교육청 Q. 포인터끼리 더한 값은 아무런 의미가 없지만 뺀 값은 두 요소간의 상대적인 거리라 는 의미가 있다. 그래서 포인터끼리의 뺄셈은 원칙적으로 허용되며 실제로 많이 사 용된다. 다음 예제를 실행해 보자. void main() { char ar[]="Pointer"; char *pi1, *pi2; pi1=&ar[0]; pi2=&ar[5]; printf("%c와 %c의 거리는 %d\n",*pi1,*pi2,pi2-pi1); } 타입이 같은 임의의 두 포인터에 대해 뺄셈이 가능하다. 하지만 일반적으로 두 포 인터가 같은 배열내의 다른 요소에 가리키고 있을 때만 실질적인 의미가 있다. 문 자형의 ar배열은 "Pointer"라는 문자열을 저장하고 있으며 pi1은 첫 번째 요소인 'P'자 위치를 가키고 있고 pi2는 여섯 번째 요소인 'e' 문자를 가리키고 있다. 이 상 태에서 pi2-pi1연산문은 두 배열 요소의 거리를 구한다. 다음 프로그램에서 (가)와 (나)의 출력 결과로 옳은 것은? #include<stido.h> void main(){ int *p; // 32bit int 형 int array[]={10, 20, 30, 35, 45, 55}; p=array; // p에 저장된 값: 12ff64 printf(″%x ″, ++p); // (가) printf(″%d ″, (*p)++); printf(″%d ″, (*p)++); printf(″%d \n″, *++p); // (나) } (가) (나) (가) (나) ① 12ff65 20 ② 12ff65 21 ③ 12ff68 30 ④ 12ff68 35 A. ③ ☑ 포인터사이의 연산 ① 포인터끼리 더할 수 없다. 번지값끼리 더한다는 것은 아무런 의미가 없기 때문이다. 변수 x, y를 포인터 변수 px, py가 각각 가리키고 있다고 하자. 설명의 편의상 x는 1000번지에 있고 y는 1500번지에 있다고 가정한다. 이때 포인터끼리 더하는 px+py 연산은 허용되지 않 는다. 번지라는 타입은 부호없는 정수형이며 따라서 px와 py를 굳이 더하고자 한 다면 2500으로 연산할 수도 있다. 그러나 이런 연산을 허용하지 않는 이유는 2500 이라는 결과값이나 또는 2500번지에 들어있는 값이 x나 y 모두에게 어떠한 의미도 없기 때문이다. Chapter 02 C 언어의 구성 및 문법 실행해 보면 "P와 e의 거리는 5"라는 결과가 출력되는데 pi2-pi1 연산에 의해 문자 'P'와 'e'가 5만큼 떨어져 있다는 것을 알 수 있다. 포인터끼리 뺄셈을 한 연산 결 과는 더 이상 포인터가 아니며 단순한 정수값이다. ptr1=ptr2-ptr3; ptr2-ptr3은 적법한 연산이지만 이 연산의 결과인 정수를 ptr1이라는 포인터 변수 에 대입할 수는 없다. 그래서 앞의 예제에서도 pi2-pi1에 대응되는 printf의 서식 은 정수형인 %d였다. ③ 포인터끼리 대입할 수 있다. 정수형 포인터 p1, p2가 있을 때 p1=p2 대입식으로 p2가 기억하고 있는 번지를 p1 에 대입할 수 있다. 다만 대입식의 좌변과 우변의 포인터 타입이 일치해야 한다는 것만 주의하자. 만약 두 포인터의 타입이 틀릴 경우는 캐스트 연산자로 타입을 강 제로 맞추어야 한다. int *pi,i=1234; unsigned *pu; pi=&i; pu=(unsigned *)pi; pi는 부호있는 정수형 포인터이고 pu는 부호없는 정수형 포인터인데 pu=pi로 바로 대입하면 타입이 맞지 않으므로 에러(터보 C는 경고)로 처리된다. 꼭 대입하려면 캐스트 연산자를 사용할 수 있되 대입 후의 결과에 대해서는 개발자가 책임져야 한 다. PART 07 C 언어 2007 국가직 7급 ④ 포인터끼리 비교는 가능하다. 두 포인터가 같은 번지를 가리키고 있는지를 조사하기 위해 ==, != 상등 비교 연 산자를 사용할 수 있으며 산술 연산과 동일한 의미를 가진다. 물론 이때 양쪽의 데 이터 타입은 일치해야 한다. 포인터끼리 값을 비교하는 일은 그리 흔한 일은 아니 지만 포인터값의 유효성을 점검하기 위해 NULL값과 비교하는 연산은 자주 이용된 다. 포인터형을 리턴하는 함수들은 에러가 발생했다는 표시로 NULL을 리턴하므로 이 함수들의 실행 결과를 점검하기 위해 포인터와 NULL을 비교한다. if (ptr == NULL) if (ptr != NULL) 이런 비교 연산문은 거의 대부분 "에러가 발생했으면~"이라는 조건식이다. 상등 비 교 연산자뿐만 아니라 <, >, <=, >= 등의 크기를 비교하는 연산자도 사용할 수 있 다. 이때 양쪽은 데이터 타입이 일치해야 하는 것은 물론이고 의미있는 비교가 되 려면 같은 배열내의 포인터여야 한다. 다음 조건문은 "ptr1이 ptr2보다 더 뒤쪽의 요소를 가리키고 있으면" 이라는 뜻이다. 6) void형 포인터 2006 아산시 2007 서울시 2007 국가7급 ① void * 타입의 포인터는 데이터 형이 정해지지 않아 어떠한 타입의 값도 가리킬 수 있 으며, 역참조될 수 없으므로 타입검사에서 자유롭다. 포괄형 포인터(generic pointer)라 고도 한다. 즉, 주소값을 저장하는 것 이외에는 아무것도 할 수 없다. ② 함수와 포인터 변수에게만 적용되는 타입이므로 일반 변수에는 쓸 수 없다. ③ void 포인터는 타입캐스팅이 없이는 참조할 수가 없다. 그 이유는 포인터가 가리키는 객체의 크기를 컴파일러가 결정할 수 없기 때문이다. Q. C 와 C++ 언어의 포인터형(pointer type) 에 대한 설명으로 옳지 않은 것은? ① 포인터 변수는 힙-동적(heap-dynamic) 변수에 대한 접근을 제 공할 수 있다. ② 허상 포인터(dangling pointer) 는 할당된 기억장소가 이미 회수 된 힙-동적(heap-dynamic) 변수에 대한 참조를 포함한다. ③ ‘*’ 연산자는 역참조 연산을 의미하며, ‘&’ 연산자는 변수의 주소 를 반환한다. ④ void * 타입으로 정의된 변수는 nil 값을 가지며 가비지 포인터 (garbage pointer) 를 생성한다. A. 7) 함수형 포인터 ① 함수의 시작주소를 저장하는 포인터를 말한다. ② 일반 포인터는 변수의 주소를 담고 있지만 함수 포인터는 함수 시작주소를 담고 있으므 로 선언시 리턴타입과 인수들의 목록까지 선언해줘야 한다. 형식] 리턴타입 (*함수 포인터 이름)(인수목록) ③ int func(int a)를 함수포인터로 선언하려면 int (*funp)(int) 로 선언해야 한다. 함수 포인터 선언 예제 ④ 또한 void 포인터는 포인터 연산을 할 수가 없다. void func(double a, float b); =>> void (*funp)(int, double); ⑤ 일반적으로 void 포인터는 메모리의 동적할당이나 직접 접근할 때 사용한다. char *func(char *a, int b); #include <stdio.h> /* void형 포인터 */ void main(){ int n =10; =>> char (*func)char *, int); void func(void); =>> void (*func)(void); void *vp = &n; *((int*)vp) = 20; printf("%d", n); } [실행결과] 20 Chapter 02 C 언어의 구성 및 문법 ④ PART 07 C 언어 #include <stdio.h> int func(int a){ return a*2; } void main(){ int i; int (*pf)(int a); pf = func; i = (*pf)(2); printf("%d", i); } [실행결과] 4 8) 배열과 포인터의 관계 #include<stdio.h> void main() { char a[]="ARRAY"; char *p="POINTER"; int i; for(i=0;i<5;i++) { printf("*(a+%d) = %c\n",i,*(a+i)); } for(i=0;i<7;i++) { printf("p[%d] = %c\n",i,p[i]); } 2005 서울시 2005 국가직 2006 국가직 ① 배열명과 포인터는 메모리의 주소를 기억하므로 서로 부분적으로 호환성이 있어 배열 을 포인터처럼 포인터를 배열처럼 혼용하여 표현 할 수 있다. ② 포인터 변수는 가르키는 주소의 값을 바꾸어가며 가질 수 있으나, 배열명은 항상 선 언된 배열의 시작 주소를 가지므로, 배열명은 주소를 갖는 상수(포인터 상수)의 개념 이다. } [실행결과] *(a+0) = A *(a+1) = R *(a+2) = R *(a+3) = A *(a+4) = Y p[0] = P p[1] = O p[2] = I p[3] = N p[4] = T p[5] = E p[6] = R ☑ 배열과 포인터의 차이점 ① 배열명의 연산은 불가능 하나 포인터값의 연산은 가능하다. - a++, a-- (X) / p++, p--(O) ② 배열은 선언되면 메모리영역을 고정적으로 확보하지만 포인터는 동적으로 기억공간 을 확보한다. Chapter 02 C 언어의 구성 및 문법 PART 07 C 언어 2011 지방직 9급 Q. ② 포인터 배열은 일반적으로 문자열 배열을 선언할 때 사용한다. 다음 C++ 프로그램에서 a[2]의 값 6을 출력하기 위하여 ㉠에 들어갈 내용으로 올바른 것은? #include<iostream.h> void main() { int a[5] = { 5, 4, 6, 7, 3 }; int *pa = a; cout << ㉠ ; } ㉠ 문자열 상수의 크기에 관계없이 2차원 배열로 부분 배열의 크기를 20으로 선언했 기 때문에 문자열 상수로 채워지지 않은 부분은 메모리의 낭비를 가져온다. ① pa + 2 ② *pa + 2 ③ *(pa + 2) ④ &pa + 2 A. ③ 9) 일차원배열의 포인터 ① 포인터 자체도 하나의 데이터이므로 이에 대한 배열도 선언할 수 있다. 다음과 같이 정의한 경우에 대해 살펴보자. char *p[ ] = { "LOW", "MIDDLE", "HIGH" }; 일차원배열 a를 다시 포인터로 정의한 것으로 메모리 구조는 다음과 같다. p[0] p[1] p[2] ↓ ↓ ↓ 'L' 'O' 'W' '\0' 'M' 'I' 'D' 'D' void main(void) { char string[][20] = { "Lee seung wook", "Oh jung pyo", "Kwon oh jin" }; printf(" Total used memory : %d\n",sizeof(string)); } [실행결과] Total used memory : 60 'L' 'E' '\0' 'H' 'I' 'G' 'H' '\0' ㉠ p는 배열과 포인터의 특징을 동시에 갖는다.(주소연산은 불가능) ㉡ p[0], p[1], p[2]는 각 문자열의 시작 주소를 갖는다. ㉢ 여러 개의 문자열을 기억시킬 때 2차원 배열보다는 일차원 배열과 포인터를 이용 한 방식(char *p[ ])이 메모리를 보다 효율적으로 사용할 수 있다. ㉣ 위와 같은 경우는 16byte의 메모리가 사용되었다. ㉤ p는 다른 일차원 배열과 같이 이 배열의 첫 번째 원소의 주소를 갖고 있는 포인터 /* 16bit OS 일 경우 */ #include <string.h> /* strlen 함수를 사용하기 위해 선언 */ void main(void) { char *string[] = { "Lee seung wook", "Oh jung pyo", "Kwon oh jin" }; int ps, sum = 0, i; ps = sizeof(string); printf(" String pointer size : %d\n",ps); for (i = 0; i < 3; i++) // strlen은 문자열의 길이를 구하는 함수로 sum += strlen(string[i]) + 1; //NULL 문자는 포함되지 않기 때문에 +1 printf(" String constant size : %d\n",sum); printf(" Total used memory : %d\n",ps+sum); } [실행결과] String pointer size : 6 String constant size : 39 Total used memory : 45 ㉡ 포인터 변수가 있는 메모리(6바이트) 문자열 상수 뒤에는 항상 '\0'이 붙는다. 이와 같이 문자열 상수를 메모리의 낭비 없이 선언할 때 포인터 배열이 쓰인다. ☞ 39 + 6 = 45 바이트 10) 포인터 배열과 배열 포인터 ① 포인터 배열과 배열 포인터의 차이점 가 되므로 p = &p[0]이 된다. 그러면 *p은 당연히 p[0]이 되며 **p은 p[0]이 가리 ㉠ int (*ptr)[3]과 int* arr[3]의 차이점은 무엇일까? 키고 있는 정수값이 된다. 마찬가지로 int ia[10][5];의 경우에도 **ia는 int 유형 ㉡ C언어에서는 [ ]와 *연산자 중 [ ]의 우선순위가 높다. 따라서 *를 먼저 처리하는 의 정수가 되기 때문에, 위의 포인터 배열은 int 유형의 2차원 배열과 유사한 점 경우 ( )를 사용해서 우선순위를 높여줘야 한다. 따라서 int (*ptr)[3]은 ( )로 인 이 많다는 것을 알 수 있다. 해 *의 우선순위가 높다. 따라서 ptr은 우선 포인터이다. 그리고 뒤에 [3]이 있으 므로 열의 크기가 3인 2차원 배열을 가리키는 포인터이다. Chapter 02 C 언어의 구성 및 문법 PART 07 C 언어 ㉢ int* arr[3]은 배열이다. 바로 int 형 포인터를 3개 저장할 수 있는 배열을 나타내 는 것이다. 그렇다면 둘의 차이점은 무엇일까? 실제로 이 둘은 사용하면서도 종종 혼동된다. 하지만 사용 시 선언된 변수 내 연산자 우선순위가 어느 쪽이 높은지만 안다면 쉽게 구별할 수 있다. ㉣ 다시 정리하면, int (*ptr)[3]은 열의 크기가 3인 2차원 배열의 시작주소를 가리키 는 포인터 하나를 의미한다. int* arr[3]은 int형 포인터 3개를 저장할 수 있는 배 열인 것이다. 11) 이중 포인터 2007 국가직 2008 서울시 ① 이중 포인터는 포인터의 포인터를 말한다. 포인터 변수는 어떤 변수를 가리키는 번지를 저장하는 변수이다. 그리고 포인터의 포인터는 포인터 변수의 번지를 기억하는 변수이 다. ② 이중 포인터를 정의하는 방법은 일반 포인터를 정의할 때처럼 '*'를 한 번 더 써주면 된 다. int **dptr 이렇게 정의하고 나면 'dptr'은 이중 포인터 변수, '*dptr'은 포인터 상수, '**dptr'은 정수의 의미를 가진다. ㉠ 포인터 배열에서 배열 이름은 포인터를 가리키는 포인터이기 때문에 이중 포인터 상수라고 생각해도 된다. ㉡ 이러한 이유 때문에 다음과 같은 현상이 일어난다. *str == str[0] *(str + 1) == str[1] *(str + 2) == str[2] ㉢ 이것은 각각의 문자열을 가리키는 포인터 변수로서 어느 곳에 갖다놔도 같은 값이 나온다. 또 문자열 상수의 문자 하나하나를 지정할 수도 있다. **str == str[0][0] /* ☞ *(*(str + n) + m) ... == str[n][m] ... */ *(*(str + 1)) == str[1][0] *(*(str + 2)) == str[2][0] *(*str + 1) == str[0][1] *(*(str + 1) + 1) == str[1][1] *(*(str + 2) + 1) == str[2][1] ③ 이중포인터는 다음과 같이 초기화가 불가능하다. char **str = {"KOREA", "TOPSPOT", "BOOK"}; (X) 2011 국가직 7급 char *a[3] = {"choi", "korea", "time"}; char **b = a; (O) Q. ④ 다음은 이중 포인터의 사용 예이다. #include <stdio.h> void main(void) { int **dptr, *ptr, i; i = 10; ptr = &i; dptr = &ptr; printf(" i = %4d, *ptr = %4d, **dptr = %4d\n",i,*ptr,**dptr); printf(" &i = %4p, ptr = %4p, *dptr = %4p\n",&i,ptr,*dptr); printf(" &ptr = %4p, dptr = %4p, &dptr = %4p\n",&ptr,dptr,&dptr); } [실행결과] i = 10, *ptr = 10, **dptr = 10 &i = FFD2, ptr = FFD2, *dptr = FFD2 &ptr = FFD0, dptr = FFD0, &dptr = FFCE Chapter 02 C 언어의 구성 및 문법 다음 C 프로그램의 실행 결과로 옳은 것은? #include <stdio.h> void main() { int a[2][3] = {{-3, 14, 5}, {1, -10, 8}}; int *b[] = {a[0], a[1]}; int *p = b[1]; printf("%d, ", *b[1]); printf("%d, ", *(--p - 2)); printf("%d\n", *(*(a + 1) + 1)); } ① -3, -3, 8 ③ 1, -3, -10 ② -3, 3, -10 ④ 1, 3, 8 A. PART 07 C 언어 ③ 2011 국가직 9급 Q. 2009 국가직 7급 C++ 프로그램에서 다음과 같이 변수를 선언하였을 때, 실행 가능하지 않은 것은? Q. 다음 C 프로그램의 수행 결과는?(단, 배열 및 포인터 배열, 포인터-포 인터 변수들이 메모리에 할당된 모습은 아래 그림과 같다고 가정한다) int *a, **b, *(c[5]), d[5]; ① a=d; ② b=&a; ③ c=d; ④ b=c; A. ③ #include<stdio.h> void main(){ struct person{ char name[8]; int age; float height; }; person hong = {"gildong", 30, 172.5}; printf("%d",sizeof(hong)); } 주소 100 102 104 106 108 112 116 1 2 3 4 100 104 108 x[0][0] x[0][1] x[1][0] x[1][1] 2차원 배열 px[0] px[1] 포인터 배열 ppx 포인터 - 포인터 변수 ① 100 104 108 ② 100 104 108 102 106 112 102 106 112 2 104 1 100 ③ 100 104 108 ④ 100 104 108 101 105 109 101 105 109 21 04 1 100 A. Chapter 02 C 언어의 구성 및 문법 PART 07 C 언어 ① 6. 구조체와 ☑ 자료구조론에서 보는 배열 & 포인터 공용체 (1) 구조체(Struct) 자료구조론을 보면 배열을 사용할 경우에는 주소에 값을 바로바로 꺼내 쓸 수 있어 처 리속도가 빠르지만 메모리 문제가 있다. 포인터는 주소를 찾아야 하기 때문에 배열보다 는 처리속도가 느릴 수 있겠지만, 더욱 안전하고 최적화된 프로그램을 구현할 수 있다. 2005 서울시 2005 국가직 2007 경기교육 (가) 의미가 그룹형식인 여러 개의 멤버 성격의 변수들을 하나의 자료형으로 묶어서 취급한 다. ① 배열은 메모리가 자동으로 설정되지만 포인터는 메모리 할당이 필요하다. [형식] ② 배열은 주소의 이동이 불가능하지만 포인터는 가능하다. -> 결국 배열은 좌변값이 불가능하지만 (값이 변하는 값)포인터는 좌변값으로 사용 된다. ③ 배열의 크기는 (데이터 형 x 배열의 크기)이지만 포인터는 (16bit)2Byte 또는 (32bit)4Byte 이다. 참고로 배열이 어떠한 함수의 인자로 사용되는 경우엔 컴파일러 시 포인터로 바뀐다. 예를 들어 int refun( int a[10]); 이라면 컴파일러는 int refun( int *a); 로 바꿔서 인식한다. 배열과 포인터의 관계 main(){ char st[][6] = {"HELLO","KOREA","COREA"} ; char *p; p=st[0]; struct 구조체 이름 { 구조체 멤버 1; 구조체 멤버 2; } 구조체 변수 ; => 선언 시에는 struct 구조체이름 변수명1, 변수명2;으로 사용 구조체 사용 예제 #include<stdio.h> void main(){ struct person { char *name; int age; int height; int weight; }; printf("%s\n",st[0]+4); struct person S[3]={{"KIM",20,180,80},{"LEE",21,170,60},{"PARK",22,175,90}}; printf("%s\n",st[0]+6); printf("%s\n",st[0]+13); struct person *sp; sp=S; printf("%s\n",(p+4)); printf("%s\n",(p+6)); printf("%s\n",(p+13)); for(int i=0;i<3;i++) { printf("name:%s, age:%d, height:%d, weight:%d\n", sp->name,sp->age,sp->height,sp->weight); sp++; } } [실행결과] O KOREA OREA O KOREA OREA H E L L O \0 K O R E A \0 C O R E A \0 [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] } [실행결과] name : KIM, age : 20, height = 180, weight = 80 name : LEE, age : 21, height = 170, weight = 60 name : PARK, age : 22, height = 175, weight = 90 ① 구조체는 구조체를 구성하는 멤버 단위로 취급할 수도 있고, 구조체 변수를 이용하여 구조체를 하나의 자료형으로 취급할 수 있다. ② 구조체 형틀에는 구조체 변수에 대한 기억부류 지정자(auto, static 등)을 지정할 수 Chapter 02 C 언어의 구성 및 문법 PART 07 C 언어 있지만, 구조체 멤버를 선언할 때는 기억부류 지정자를 지정할 수 없다.(구조체 멤버 는 변수가 아니다.) ③ 구조체 멤버를 개별적으로 다룰 때는 「dot 연산자( . )」 를 이용한다. 특히, 구조체 변수가 포인터이면 「arrow 연산자( -> )」 를 이용하여 각 멤버를 취급할 수 있다. 2011 경기도 교육청 Q. #include <stdio.h> void main(){ struct rec{ int a; // 32bit int 형 double b; struct c{ int goo, su; float dan; }r1; }m1; printf(″%d \n″, sizeof(m1.r1)); } ㉠ 예 : 포인터 구조체 변수 P의 멤버변수 a( (*P).a )는 P → a로 표현가능 ④ 장점으로는 새로운 형식을 편의에 따라 자유롭게 선언하여 사용할 수 있고, 자료형이 다른 변수들을 묶어 표현할 수 있으므로 프로그램이 간결해 진다. struct student { char st_num[10]; char name[20]; short age; } std ; 10바이트 20바이트 st_num name age std.st_num std.name std.age 다음 프로그램의 출력 결과로 옳은 것은? 2바이트 이 전체가 구조체 변수 std ① 12 ③ 22 멤버별 취급시는 dot 연산자 사용 ② 16 ④ 24 A. ☑ 자기참조 구조체 2009 경북교육 ① 구조체 자료형에 자신의 구조체 멤버변수로 구조체 포인터 변수가 존재하는 구조체 struct Node{ int data; struct Node *next;//구조체 Node안에 구조체 Node의 포인터 변수가 }; //있으므로 자기참조 구조체 Node a, b, c, *head; a.data =1, b.data=2, c.data=3; head = &a; a.next = &b, b.next = &c, c.next = null; 100 멤버값 100 변수명 head → 108 1 108 a → 116 b → 1) 하나의 자료를 여러 개의 변수(공용체 멤버)가 공동으로 필요한 크기만큼 사용하 union 공용체 이름 { 공용체 멤버 1; 공용체 멤버 2; } 공용체 변수 ; => 선언 시에는 union 공용체이름 변수명1, 변수명2;으로 사용 NUL L 3 2005 서울시 [형식] 116 2 2005 국가직 는 자료형이다. ② 위 코드는 아래와 같은 연결 리스트 자료구조를 나타낸다.(메모리주소는 임의값임) 메모리주소 (2) 공용체(Union) ① c ① 공용체는 구조체와 달리 멤버중 가장 큰 자료형의 큰 자료형의 크기로 메모리가 할당 된다. 그리고 동일한 시작주소를 갖도록 메모리가 할당된다. ② 구조체와 사용방법이 동일하여 공용체 멤버를 개별적으로 다룰 때는 Dot 연산자( . ) 를 포인터이면 -> 연산자를 사용할 수 있다. ③ 공용체는 선언과 사용방법에 있어서는 동일하지만, 메모리 할당 방식에 차이가 있다. Chapter 02 C 언어의 구성 및 문법 PART 07 C 언어 2) 공통점 ① 정의 단계와 선언 단계가 구분되며, 정의와 선언을 동시에 할 수 있다. ② 멤버변수로 C언어에서 제공하는 모든 변수형을 가질 수 있다. ③ 멤버변수를 참조하기 위해 멤버변수 연산자(.)를 사용한다. ④ 포인터를 사용하여 참조할 때는 참조연산자 ->를 사용한다. ⑤ 같은 구조의 변수 간에 대입 연산이 가능하다. 2006 국가직 7급 그림 7.6 Q. 공용체와 구조체 기억장소 배치 다음은 C언어 프로그램이다. 출력값으로 옳은 것은?(단, int는 4바이트, long 8바이트) struct st{ int a; union{ int b; long c; }; }; printf("%d", sizeof(st)); 공용체 사용 예제 #include <stdio.h> union tag_kong { int a; short b[2]; }; void main(){ tag_kong un; un.a=0x12345678; printf("un.a=%x\n",un.a); printf("un.b[0]=%x\n",un.b[0]); printf("un.b[1]=%x\n",un.b[1]); } [실행결과] un.a=12345678 un.b[0]=5678 un.b[1]=1234 ① 4 ② 8 ③ 12 ④ 16 A. 7. 열거형과 ④ typedef문 (1) 열거형(enum) (3) 공용체와 구조체 비교 2006 국가직 enum 열거타입 이름 { 열거상수리스트(콤마로 구분) } 1) 차이점 ① 구조체는 struct키워드를 사용하지만 공용체는 union 키워드를 사용한다. ① 관련 상수 집합을 이름(기호) 상수로 정의하여 사용하는 정적 정수형 데이터이다. ② 구조체는 한 번에 모든 멤버 변수의 초기화가 가능하지만 공용체는 하나의 멤버 변수 ② 변수가 가질 수 있는 값을 사용자가 나열하여 정의할 수 있다. 만 초기화가 가능하다. ③ 열거형은 프로그램의 판독성을 높여주고 오류를 감소시키는 장점이 있다. ③ 구조체는 선언 시 모든 멤버변수의 크기의 합으로 메모리 영역을 할당하지만 공용체 는 가장 큰 멤버변수를 기준으로 메모리 영역을 할당한다. Chapter 02 C 언어의 구성 및 문법 ④ 값을 한번 설정하면 프로그램 도중에 변경할 수 없다. ⑤ 열거상수리스트에 초기값을 대입하지 않으면 순차적으로 0, 1, 2, ⋯ 정수값이 열거요 PART 07 C 언어 소에 할당된다. ⑥ 열거상수리스트에 직접 상수값을 대입할 수 있고, 값이 없는 경우에는 앞에 열거요소 main{ enum AA {QQ, WW, EE, RR, TT}; enum BB a, b, c, d, e; a = QQ; b = WW; c = EE; d = RR; e = TT; printf("%d %d %d %d %d\n", a, b, c, d, e); } [실행결과] 0 1 2 3 4 에 할당된 값을 기준으로 1씩 증가된 값이 다음 열거요소의 값으로 할당된다. enum PUT_TYPE { PUT-TYPE1, PUT-TYPE2, // 열거요소 「PUT-TYPE1」의 값을 0으로 해서 PUT-TYPE3, // 1씩 증가된 값이 다음 열거 요소의 값이 된다. PUT-TYPE4, PUT-TYPE5 }; enum GET_TYPE { GET_TYPE1 = 2, GET_TYPE2, GET_TYPE3, // 열거요소 「GET_TYPE1」의 값을 2로 해서 GET_TYPE4, // 1씩 증가된 값이 다음 열거 요소의 값이 된다. GET_TYPE5 }; 초기값 지정 예 1. enum AA {QQ=6, WW=99, EE=77, RR=34, TT=90}; 2. enum AA {QQ=6, WW, EE=77, RR=34, TT=90}; -> 위에서 WW값은 7이 된다. 3. enum day { saturday, sunday=0, monday, tuesday, wednesday, thursday, friday}; 에서는 순서대로 (0, 0, 1, 2, 3, 4, 5}이 된다. 4. enum status { loss = -1, bye, tie=0, win};는 {-1, 0, 0, 1}이 된다. (2) typedef 1) typedef의 필요성 ① 자주 사용되는 수형에 대해서 인식하기 쉬운 명칭을 제공하기 위함이다. ② 복잡한 수형명을 간단하게 하기 위해서이다. ③ 프로그램의 이식을 용이하게 하기 위해서이다. 2) 사용자가 새로운 자료형을 정의할 때 사용 [형식] typedef (기존 자료형 이름) (새로운 자료형 이름) ; ① typedef unsigned int UINT; → 「unsigned int」 를 「UINT」 이라는 새로운 자료형으로 정 의 ② typedef struct HUMAN Human; → 구조체 「HUMAN」를 「Human」 이라는 새로 운 자료형으로 정의. ㉠ 구조체 정의와 동시에 typedef문을 사용할 수도 있다. Chapter 02 C 언어의 구성 및 문법 PART 07 C 언어 typedef struct rec{int a; char b;}node; 2011 서울시 ③ typedef int * PINT; → 「int *」 대신에 「PINT」 이라는 새로운 자료형을 정의. 8. 함수 Q. 다음 C 프로그램의 실행 결과는? 2008 경기도 (1) 함수의 역할 ① 특정한 작업을 수행하도록 설계된 독립적인 부프로그램을 말한다. ② C언어에서는 모든 함수들이 독립적으로 해야 할 일을 정의하고, 주프로그램(main함 수)을 기준으로 필요시 호출되어 독립적으로 수행된다. (2) 함수의 특징 ① C언어는 전체적으로 함수단위로 구성되어 수행되므로 모든 함수(표준함수 및 사용자 정의함수)는 모두 동등한 구조를 가지고 있다. ② C언어에서 지원하는 매개변수 전달방식은 Call by value와 Call by reference 방식으 로 두 가지를 지원하며, 되부름(Recursive Call)을 허용한다. ③ 함수형(함수명 앞에 자료형)으로 선언된 자료형은 return 구문에 의해 값을 되돌려 보 낼때 함수형과 되돌려 보내는 값의 자료형이 일치해야 한다. 함수값을 return할 필요 가 없는 경우에는 함수형을 void형으로 선언한다. void foo(void); int x = 1; int main() { int x = 2; printf(“%d”, x); foo(); { int x = 3; x++; } printf(“%d”, x); return 0; } void foo(void) { printf(“%d”, x); } ① 212 ③ 223 ⑤ 234 ② 214 ④ 224 A. Chapter 02 C 언어의 구성 및 문법 PART 07 C 언어 ① (3) 사용자 정의함수 1) 함수 작성법 되돌리는 값의 자료형과 함수형이 다르면 되돌리는 값은 함수형으로 자동으로 형변환이 된다. ① 먼저, 두 수를 전달하면 두 수를 더한 값을 함수값으로 되돌리는 함수 「hab()」를 정 의하는 방법을 살펴보자. int hab( int x, int y); // 사용자 정의 함수 선언 void main(){ int a, b; a = 10, b = 20; printf("결과 : %d\n", hab(a, b) ); } int hab( int x, int y ){ // 함수 정의, 인수전달(Call by Value) int sum; sum = x + y; return( sum ) ; // 함수값을 되돌림 } ③ C에서 인수 전달은 다음 2가지 방법으로 처리할 수 있다. ㉠ call by value : 인수의 값을 인도한다. ㉡ call by reference : 인수의 주소를 인도한다(포인터를 이용) ④ C의 함수는 함수값을 리턴하지 않아도 된다. 이를 void형 함수라 하며 void형 함수에는 return문이 필요없다. void func(char a, int b); │ └→ 함수 func()는 char형과 int형 인수를 각각 하나씩 전달 받아서 내부적 으로 처리할 뿐이며 특정 함수값을 리턴하지 않겠다는 뜻이다. ⑤ 함수에는 인수가 없을 수도 있다. int func(void); [실행결과] 30 │ └→ 함수 func()에는 인수를 전달할 필요가 없다. 그러나 내부적으로 처리한 결과 중 어느 하나를 int형으로 함수값을 되돌리겠다는 뜻이다. (void는 2) 사용자 정의 함수 작성 시 주의점 생략가능) ① 함수 선언 시 반환형을 함수명 앞에 정의해야 한다. 반환자료형 함수명(매개변수1, 매개변수2, …){ 함수 몸체 } 반환자료형 - 계산된 결과값을 호출한 함수에 되돌려 줄 때의 자료형 함수명 - 식별자 명명규칙에 따라, 의미를 알 수 있도록 정의 3) 자료전달 방법 ① call by value (값에 의한 인수전달) 자료 전달 과정 - 실매개변수의 값이 형식매개변수로 전달되는 방법이며, 전달받은 값은 되돌려 받지 못한다. int func(char a, int b); │ └→ 함수 func()는 char형과 int형을 매개변수로 받아서 처리하고 결과값을 int형으로 반환하겠다는 의미이다. ② 함수의 반환값은 결과값을 반환하며, 함수형과 반환되는 값의 자료형을 일치시키도록 호출함수 f1(i, j) 피호출함수 f1(int x, float y) 변수 i 변수 i 의 값 변수 i 의 값 int x 변수 j 변수 j 의 값 변수 j 의 값 float y 한다. a. 함수는 형식매개변수로 여러 개의 값을 전달할 수 있다. return rtval; b. 함수는 return 문을 통해 1개의 값만 돌려받는다. return (a+b); c. 피호출함수의 형식매개변수 값이 변해도 호출함수의 실매개변수 값은 변하지 않는 다. Chapter 02 C 언어의 구성 및 문법 PART 07 C 언어 #include<stdio.h> void swap(int,int); #include<stdio.h> void swap(int *,int *); void main() { int i=1, j=2; printf("i=%d, j=%d\n",i,j); swap(i,j); printf("i=%d, j=%d\n",i,j); } void main() { int i=1, j=2; printf("i=%d, j=%d\n",i,j); swap(&i,&j); printf("i=%d, j=%d\n",i,j); } void swap(int x, { int temp; temp = x; x = y; y = temp; printf("i=%d, } [실행결과] i=1, j=2; i=2, j=1; i=1, j=2; void swap(int *x, int *y) { int temp; temp = *x; *x = *y; *y = temp; printf("i=%d, j=%d\n",*x,*y); } [실행결과] i=1, j=2 // swap 함수 호출 전 i=2, j=1 // swap 함수 내부 i=2, j=1 // swap 함수 호출 후 int y) j=%d\n",x,y); // swap 함수 호출 전 // swap 함수 내부 // swap 함수 호출 후 ② call by reference (주소에 의한 인수전달) ③ 재귀적 용법 자료전달 과정 - 호출함수와 피호출함수의 매개변수 값을 서로 교환할 수 있는 자료 전달 방식이다. 변수 i 호출함수 f1(i, j) 피호출함수 f1(int x, float y) 변수 i 의 값 ff00 int x ff04 float y ff00(주소) 변수 j 변수 j 의 값 ff04(주소) a. call by value 방식과 달리 형식매개변수 값이 변하면 호출함수의 실매개변수 값 도 변한다. b. 자료전달시 실매개변수 앞에 주소연산자 ‘&’ 를 붙여야 한다. c. 형식매개변수는 주소를 참조하는 포인터변수로 선언되어야 한다. Chapter 02 C 언어의 구성 및 문법 자료전달 과정 - 함수 안에서 자기 자신의 함수를 직접 호출하는 방법을 말한다. #include <stdio.h> int fac(int n) { if (n<1) res=1; else res=n*fac(n-1); printf("%d, ", res); /* print_2 */ } main(void) { fac(3); printf("end of program"); /* print_1 */ } [실행결과] 1, 2, 6, end of program PART 07 C 언어 변수 = getchar( ) char형 변수 ② putchar() ㉠ 표준출력장치(모니터, 프린터)로 한 문자를 출력한다. a. 재귀적 함수는 반복문에 의한 함수(iterative function)보다 스택 메모리로 인하여 putchar(자료) 기억장소의 사용이 증가하고 알고리즘으로 실행시간이 증가하기 때문에 효율성이 char형 변수 떨어진다. b. 그러나 프로그램의 이해를 향상시키고 프로그램의 우아한 형식을 필요로 하거나, 반복문으로 프로그램 작성이 어려울 경우에는 재귀적 함수를 작성하는 것이 좋다. ③ getch() ㉠ getchar() 같이 단일문자를 입력받으며, 단 입력하는 문자는 화면에 표시되지 않는 다. 2005 서울시 변수 = getch( ) Q. C함수 매개변수로 5를 주어 호출했을 때 변환되는 값은? char형 변수 int f(int n){ if( n==1 || n ==2 ) return 1; else return ( f(n-1) + f(n-2) ); } ① 2 ② 3 ③ 5 ④ 8 ④ putch() ㉠ putchar()와 같은 기능을 수행한다.(단, <conio.h> 헤더파일에 정의된 함수이므로, 프린터로 출력할 수는 없다.) putch(자료) char형 변수 ⑤ 13 A. 2007 경상북도 ③ Q. (4) 표준함수 2008 경기도 ① C 컴파일러에 구비되어 있는 함수로 사용자가 정의하지 않고 사용할 수 있다. 2) 단일문자 입출력함수(getchar() / putchar() 와 getch() / putch()) 2007 경북 ① getchar() 다음은 C 프로그램의 일부분이다. 키보드로부터 "Korea"를 입력받았을 때 출력값으로 적당한 것은? int a; a=getchar(); putchar(a); ① K ② a ③ Korea ④ 아무것도 출력되지 않음. ㉠ 단일문자를 입력받으며, 입력하는 문자는 화면에 표시된다. <Enter>를 누르면 입력 A. 이 종료되며 여러 문자를 입력해도 처음의 한 문자만을 유효하게 받아들인다. 3) 문자열 입출력 함수(gets() / puts()) Chapter 02 C 언어의 구성 및 문법 PART 07 C 언어 ① ① gets() ㉠ 키보드로부터 <ENTER>의 입력전까지 모든 문자열을 입력받아서 배열 또는 포인터 에 값을 수록한다.(null문자는 저장되지 않는다) gets(변수) char형 배열(또는 포인터) ② puts() ㉠ 지정된 문자열을 화면에 출력한다. puts(자료) char형 배열명, 포인터, 문자열 4) 문자열 파일 입출력(fputs() / fgets()) 변환기호 %d int 형을 10진수로 출력한다. 기 능 %o int 형을 8진수로 출력한다. %x int 형을 16진수로 출력한다. %u int 형을 부호 없는 10진수로 출력한다. %c char 또는 int형을 문자로 출력한다. %s 문자열(String)을 출력한다. %f float 이나 double 형을 소수점을 사용하여 출력한다. %e float 이나 double 형을 지수를 사용하여 출력한다. %g %f 또는 %e 형태중 하나로 출력한다. %ld long 형을 10진수로 출력한다. %lo long 형을 8진수로 출력한다. %lx long 형을 16진수로 출력한다. ② scanf() 함수 ① fgets() ㉠ 주어진 양식으로 자료를 입력받아 지정된 기억공간에 저장한다. ㉠ 지정한 스트림으로부터 문자열을 가져온다. ㉡ 엔터가 입력되기 전까지의 문자열이나 n-1(n은 지정된 길이)까지의 문자열만 읽어 오고 문자열 끝에 null문자가 추가 된다. scanf("입력양식", &변수 1, &변수 2, …); a. 입력양식에 사용되는 변환기호는 printf() 함수의 출력양식 기호와 동일하다. ② fputs() b. 입력양식에는 %문자가 아닌 다른 문자를 포함시켜서는 안 되며, 변수 앞에는 주소 를 의미하는 ‘&’(주소연산자)를 붙여야 한다. ㉠ 지정한 스트림에 문자열을 출력한다. ㉡ puts()와 같은 방법으로 사용되지만 puts()와는 다르게 출력스트림을 지정할 수 있고 c. 문자열이나 배열명 앞에는 ‘&’ 를 생략한다. ③ printf() 함수 fputs()는 문자열 끝에 null문자가 붙지 않고 문자열 그대로 출력된다. ㉠ 주어진 양식으로 자료를 화면에 출력한다. 5) 형식지정 입출력함수(scanf() / printf()) 2000 경기도 2006 경남 2006 경기도 printf("출력양식", 변수 1, 변수 2, …); ① 형식지정은 % 기호 다음에 여러 가지 「변환문자」를 사용하여 지정한다. 즉, % 다음에 있는 변환문자에 따라 해당하는 인수의 입출력 기능이 달라진다. a. 출력양식에 사용되는 변환기호는 scanf() 함수와 동일하다. b. %문자 다음에 숫자 또는 -(마이너스)를 사용하여 출력 폭이나 자리 위치를 지정할 수 있다. ④ printf() - 자릿수를 맞추어 출력 a. 정수형 숫자에 내해 자릿수를 맞추어 출력 출력형식: %ⓝd ( ⓝ: 출력할 전체 자릿수 ) Chapter 02 C 언어의 구성 및 문법 PART 07 C 언어 void main ( ){ int a=-5, b=23, c=5376; long d=325689; printf("정수형 숫자 format \n"); printf("1. a=%d\n", a); printf("2. a=%6d\n", a);//오른쪽 맞춤 printf("3. a=%06d\n", a);//오른쪽 맞춤 printf("4. b=%6d\n", b); printf("5. b=%+6d\n", b);//부호 맞춤 printf("6. c=%6d\n", c); printf("7. c=%-6d\n", c);//왼쪽 맞춤 printf("8. d=%6ld\n", d);//오른쪽 맞춤 } [출력결과] 정수형 숫자 format 1. a=-5 2. a= -5 3. a=-00005 4. b= 23 5. b= +23 6. c= 5376 7. c=5376 8. d=325689 b. 실수형 숫자에 내해 자릿수를 맞추어 출력 출력형식: %ⓝ.ⓓf ( ⓝ: 소숫점을 포함하여 출력할 전체 자릿수, ⓓ: 소숫점 이하 자릿수 ) void main ( ){ float a=-437.46, b=1278.9; double c=5.567; printf("실수형 숫자 format \n"); printf("1. a=%8.3f\n", a); printf("2. b=%8.3f\n", b);//오른쪽 맞춤 printf("3. c=%8.3f\n", c); printf("4. c=%8.f\n", c);//오른쪽 맞춤 printf("5. c=%8.1f\n", c); printf("6. c=%.2f\n", c);//왼쪽 맞춤 printf("7. a=%+.2f\n", a); printf("8. b=%+.2f\n", b);//부호 표시 } [출력결과] 실수형 숫자 format 1. a=-437.460 2. b=1278.900 3. c= 5.567 4. c= 6 5. c= 5.6 6. c=5.57 7. a=-437.46 8. b=+1278.90 ※ 실수인 경우에는 %f는 기본적으로 소수점 6자리까지 출력하고, 기본적으로 소수점 이상의 정수 값이 출력형식의 대상값보다 작으면 자릿수는 무시한다. printf("%4d", 12345) -> 12345 출력 printf("%3.1f", 123.45) -> 123.5 출력 c. 문자열에 대한 형식 출력형식: %ⓝs ( ⓝ: 문자열이 출력될 n개의 자리를 확보하고 오른쪽 맞춤 ) %-ⓝs ( ⓝ: 문자열이 출력될 n개의 자리를 확보하고 왼쪽 맞춤 ) %.ⓝs ( ⓝ: 문자열에 대해 n자리수 만큼 왼쪽 맞춤 ) Chapter 02 C 언어의 구성 및 문법 PART 07 C 언어 void main ( ){ char *name1="string"; char *name2="topspot"; printf("문자열 format \n"); printf("1. name1=%10s\n", name1);//오른쪽 맞춤 printf("2. name2=%10s\n", name2); printf("3. name2=%-10s\n", name2);//왼쪽 맞춤 printf("4. name1=%.3s\n", name1);//세자리까지만 왼쪽 맞춤 printf("5. name2=%.4s\n", name2); } [출력결과] 문자열 format 1. name1= string 2. name2= topspot 3. name2=topspot 4. name1=str 5. name2=tops 2009 국가직 7급 Q. 다음 C 프로그램의 수행 결과는? #include <stdio.h> void main(){ float a=3/2; float b=3.0/2; int c=(int)b; printf("%7.3f%7.3f%3d\n", a, b, c); } ① 1.000 1.500 1 ➁ 1.000 1.000 1 ➂ 1.500 1.500 1 ➃ 1.500 1.500 2 A. ① d. 진법을 출력하는 방법과 주소에 대한 형식 8진수, 16진수와 주소를 출력 구분 8진법 16진법 주소 형식 %ⓝo %-ⓝo %ⓝx %-ⓝX %u %p ⓝ개의 ⓝ개의 ⓝ개의 ⓝ개의 주소를 주소를 출력 방법 자릿수 확보, 오른쪽 정렬 자릿수 확보, 왼쪽 정렬 자릿수 확보, 오른쪽 정렬 자릿수 확보, 왼쪽 정렬, 대문자 출력 부호 없는 10진수로 변환하여 출력 16진수로 출력 ☑ fprintf 함수 fprintf 는 File printf 의 약자로 printf의 사용법에 file 개념만 추가된 것이다. 직접 파일을 열어서 그 파일에 출력할 때 주로 사용하며, 사용자가 직접 파일을 fopen 같은 함수를 이용해서 열어서 사용할 수 있으며 사용 예는 다음과 같다. 예제) void main(void){ FILE *fp; fp = fopen("tmp.txt", "w"); fprintf(fp, "테스트입니다\n"); fclose(fp); } ☑ 표준 입∙출력 함수 ① 입력함수 ㉠ scanf() : 키보드를 통해 1개 이상의 자료를 입력 받는다. ㉡ getchar() : 키보드를 통해 1개의 문자를 입력 받는다. ㉢ gets() : 키보드를 통해 문자열을 입력 받는다. ② 출력함수 ㉠ printf() : 화면에 여러 종류의 자료를 출력한다. ㉡ getchar() : 화면에 1개의 문자를 출력한다. ㉢ puts() : 화면에 문자열을 출력한다. Chapter 02 C 언어의 구성 및 문법 PART 07 C 언어 C:\DOS>xcopy * . * ☑ 표준라이브러리 함수의 헤더파일 a:/p 두번째 인자 2008 경기도 첫번째 인자 ① stdio.h : 콘솔 입출력에 관한 헤더파일(printf(), scanf(), getchar(), fprintf(), fopen(), fclose() 등) ② stdlib.h : 난수발생, 메모리의 할당 프로세서의 제어, 데이터의 정렬, 탐색 등의 함수를 가진 헤더파일(malloc(), atoi(), random(), itoa() 등) ③ math.h : 수학적인 연산과 관련된 헤더파일(sin(), cos(), tan(), abs() 등) 프로그램 이름 ② 프로그램 실행시 입력된 자료가 함수 main()의 인수로 전달되는 것으로 함수 main() 은 다음과 같이 정의하여 사용할 수 있다. ④ time.h : 시간에 관한 함수를 갖고 있는 헤더파일 (time(), ctime() 등) ⑤ conio.h : 화면 제어, 콘솔(키보드와 모니터) 입출력에 관한 함수를 갖고 있는 헤더 파일(clrscr(), gotoxy(), wherex(), putch(), cputs(), cprintf(), getch() 등) ※ conio.h는 볼랜드사의 터보 c에서 제공되던 라이브러리로 비표준이지만, 많이 사 용하는 헤더파일이라 포함시켰다. conio.h내 함수는 일부 환경에서 정상작동이 되 지 않을 수 있다. 또한 콘솔에 관한 입출력 함수이므로 프린터로 출력할 수 없다. ⑥ string.h : 문자열 처리함수를 갖고 있는 헤더파일(strcat(), strcmp(), strcpy(), strlen(), strncat(), strncpy() 등) main (int param, char *p_str1[], char *env[]) { /* 프로그램 본체 */ } 또는 main (int param, char **p_str1, char **env) { /* 프로그램 본체 */ } a. param - 실행시 명령어 행에 사용된 문자열의 개수가 param에 전달된다. 이 변 수는 Command라인에서 쓰인 인자의 개수를 정수(int)값으로 가지고 있다. 인자의 구분은 space, tab 과 같은 기호로 구분한다. 이때 정수 값은 인자가 없으면 1, 1 ☑ 문자열 처리 함수 ① strcpy(string str1, string str2) : 변수 str1에 str2의 문자열이 저장된다. ② strcat(string str1, string str2) : str1문자열에 저장된다. str2문자열이 결합되어 str1에 ③ strcmp(string str1, string str2) : 두 개의 문자열을 사전순으로 비교하여 음수, 양 수, 0으로 결과값을 반환한다. - str1 < str2 : -1반환, str1 == str2 : 0반환, str1 > str2 : 1반환 ④ strlen(string str1) : str1 문자열의 길이를 반환한다. ⑤ strncat(string1, string2, n) : str2의 왼쪽에서부터 n만큼 길이의 문자열을 str1에 결합시켜 string1에 저장한다.) ⑥ strncpy(string str1, string str2, n) : str2의 왼쪽에서부터 n만큼 길이의 문자열 을 str1에 대체한다. - 예 : strncpy("aaa", "bb", 1) // baa를 반환 개면 2와 같은 값을 가진다. b. *p_str1[]; - 명령어 행에 기술되는 문자열의 시작을 가리키는 포인터(주소). 이 것은 포인터 배열로 Command라인에서 입력한 인자들이 존재하는 메모리의 번지 수를 차례대로 기억하고 있다. 이 때 각 포인터 배열은 다음과 같다. p_str1[0] - 패스명과 실행파일 이름. p_str1[1] - 첫 번째 인자의 내용. p_str1[2] - 두 번째 인자의 내용. : p_str1[n] - n 번째 인자의 내용. c. env - 프로세서의 환경을 직접 설정할 때 사용된다. 3번째 인자인 env는 환경 변 수의 값들이 X=Y 형태의 스트링으로 넘어오게 된다. 환경 변수는 DOS의 경우에는 SET 명령에 의해 값이 정의된 변수들을 의미한다. param 처럼 개수를 알려주는 인자가 없으므로 이것의 개수는 알 수가 없고, env의 값을 증가시켜 나가다가 이 (5) 명령어행 인수를 함수 main()에 전달 값이 널 포인터가 되면 바로 이것이 데이터의 끝이라는 것을 알 수 있다. 1) main() 함수의 구조 d. 다음은 env로 넘어오는 값들을 모두 출력하는 프로그램이다. ① DOS 프롬프트가 보이는 상태에서 어떤 프로그램을 실행시키기 위해서는 그 프로그램 의 파일 이름을 치고서 <Enter>키를 누르면 실행되는 것을 알고 있을 것이다. 그리고 어떤 프로그램은 인자가 있다는 것도 알고 있을 것이다. 예를 들어서 xcopy라는 DOS 프로그램은 인자가 2개 이거나 1개이다. Chapter 02 C 언어의 구성 및 문법 PART 07 C 언어 (2) 기억클래스의 종류 #include<stdio.h> void main(int param, char *p_str1[], char *env[]) { int i = 0; while (*env) printf("env[%d] = %s\n",i++,*env++); } 1) 자동변수(auto) ① 특징 : 함수 실행 시 생성되었다가 실행이 끝나면 소멸된다. (일반적으로 auto 는 생 략) ② 유효범위 : 변수가 선언된 구역(블록 안 또는 함수내부) ③ 기억공간 : 스택에 저장되고 함수 실행 후 메모리에서 삭제된다. [실행결과] env[0] = COMSPEC=C:\COMMAND.COM env[1] = PROMPT=$P$G env[2] = TEMP=C:\NU\TEMP env[3] = PATH=C:\DOS;C:\NU;C:\TC;C:\C600\BINB;C:\C600\BIN env[4] = LIB=C:\C600\LIB env[5] = INCLUDE=C:\C600\INCLUDE env[6] = HELPFILES=C:\C600\HELP\*.HLP env[7] = INIT=C:\C600\INIT 2) 정적변수(static) ① 특징 : 변수 선언 후 고정된 메모리영역을 확보하여 프로그램이 끝날 때까지 메모리영 역을 유지한다. static 으로 선언하며, 초기화를 하지 않으면 자동으로 0 으로 초기화된 다. ② 유효범위 : 변수가 선언된 구역(블록 안 또는 함수내부) ③ 기억공간 : 일반적인 메모리영역 9. 기억클래스(Storage Class) 2005 서울시 2007 경북 2008 경기도 3) 외부변수(extern) ① 특징 : 현재의 함수가 아닌 다른 함수에서 정의된 변수를 사용할 때 선언한다. (1) 지역변수와 전역변수 extern 으로 선언하며, 기억영역 할당과 초기화 방법은 정적변수와 동일하다. 같은 범 1) 정의 위 내에 동일한 이름의 외부변수와 자동변수(지역변수)가 존재할 경우, 지역변수가 우 ① 지역변수 : 특정 범위 내에서만 통용되는 변수로서 선언된 블록이나 함수 내에서만 사용 가능하다. 선순위를 가진다. ② 유효범위 : 함수 외부에서도 선언 가능 ② 전역변수 : 함수 밖이나 외부 컴파일러에서 선언되어 프로그램 전체에 걸쳐 사용될 수 있는 변수를 말한다. 2) 특징 ① 같은 범위 내에 동일한 이름의 지역변수와 전역변수가 존재할 경우, 지역변수가 우선 순위를 가진다. 외부변수의 예제 int i[] = {1,2,3,4,5}; main(){ foo(); } extern int i[]; foo(){ int *j = i; while(*j){ println("%d\n", *j++); } } m1.c m2.c ② 전역변수는 선언된 위치 이후부터 효력이 발생하므로 프로그램 앞부분에 위치시키고, 초기화를 하지 않으면 0으로 자동초기화 된다. ③ 전역변수의 사용은 전체 프로그램의 신뢰성을 해치게 되므로 가급적이면 지역변수를 사용해야한다. extern변수로 선언된 i[ ]는 m1.c 의 i[ ]의 값들이 m2.c에서도 값을 공유한다. 4) 레지스터 변수(register) ① 특징: CPU 내의 레지스터에 자료를 저장하고자 할 때 사용된다. register 로 선언하 며, 프로그램의 실행속도를 늘리기 위해 사용되며 주로 반복문의 카운터 변수 등이 Chapter 02 C 언어의 구성 및 문법 PART 07 C 언어 해당된다. 2011 지방직 9급 ② 유효범위 및 기억공간 사용방식은 자동변수와 동일하다. Q. 기억장소의 예제 include <stdio.h> int a; static int b; main(){ (auto) int c; register int d; static int e; (auto) char *f; } #include<stdio.h> int funcA(int n) { static int s = 1; s *= n; return s; } int funcB(int n) { int s = 1; s *= n; return s; } void main() { int s1, s2; s1 = funcA(2); printf("F1 = %d, ", s1); s1 = funcA(3); printf("F2 = %d, ", s1); s2 = funcB(2); printf("F3 = %d, ", s2); s2 = funcB(3); printf("F4 = %d", s2); } // 외부변수 (전역변수) // 외부 정적 변수 // // // // 자동 변수 레지스터 변수 내부 정적 변수 자동변수(동적변수 힙영역) 2011 서울시 Q. 다음 C 프로그램의 실행 결과는? 다음 C 프로그램의 실행 결과는? void foo(void); int x = 0; int main() { foo(); foo(); return 0; } void foo(void) { static int a = 0; a += 10; x = x + 2; ① F1 = 1, F2 = 3, F3 = 2, F4 = 3 ② F1 = 1, F2 = 3, F3 = 3, F4 = 2 printf(“%d, %d ”, a, x); return; ③ F1 = 2, F2 = 6, F3 = 2, F4 = 3 ④ F1 = 2, F2 = 6, F3 = 3, F4 = 2 } A. ① 10,2 10,2 ② 10,2 10,4 ③ 10,2 20,4 ④ 20,2 20,4 ⑤ 20,4 20,4 A. ③ Chapter 02 C 언어의 구성 및 문법 PART 07 C 언어 ③ 2011 국가직 7급 Q. <프로그램 1>에서 <프로그램 3>까지 순차적으로 실행하였을 때 출력되 는 결과로 옳은 것은? <프로그램 1> #include <stdio.h> int func() { static int x = 10; return x += 10; } void main() { int x; x = func(); x = func(); printf("a = %d\n", x); } <프로그램 2> #include <stdio.h> int x = 10; void func() { x += 10; } void main() { int x = 10; func(); func(); printf("b = %d\n", x); } <프로그램 3> #include <stdio.h> int x = 10; void func() { x += 10; } void main() { func(); func(); printf("c = %d\n", x); } ① a = 10 ② a = 10 b = 30 b = 30 c = 10 c = 30 ③ a = 30 ④ a = 30 b = 10 b = 30 c = 30 c = 30 A. ③ 07 기출문제
© Copyright 2025