조무위키
조무위키
둘러보기
대문
최근 바뀜
임의의 문서로
미디어위키 도움말
도구
여기를 가리키는 문서
가리키는 글의 최근 바뀜
특수 문서 목록
문서 정보
행위
문서
토론
편집
역사 보기
C언어
편집하기 (부분)
경고:
로그인하지 않았습니다. 편집을 하면 IP 주소가 공개되게 됩니다.
로그인
하거나
계정을 생성하면
편집자가 사용자 이름으로 기록되고, 다른 장점도 있습니다.
스팸 방지 검사입니다. 이것을 입력하지
마세요
!
==맛보기== {{진지주의}} {{귀차니즘}} {{문법병신}} 작성자가 길게 썼다가 한번 날리고 존나 귀찮아졌으니 대충쓴다 진짜 배울 사람은 이거말고 책보는걸 추천한다 교수님 강의 듣거나 개시발 노잼의 연속이다. 진짜 차라리 강의를 들어라. 초반부는 뇌에 똥찬새끼가 아니라면 충분히 할 수 있다. C언어 강의하는 사람 치고 재밌게 가르쳐주는 사람 드물다. ===전처리기=== ---- <nowiki>#</nowiki> 으로 시작한다. 컴파일 하기전 먼저 실행될 구문이라 보면된다. ex : <nowiki>#</nowiki>include <stdio.h> /* stdio.h라는 헤더파일을 소스에 포함한다는 뜻이다 헤더파일은 존나 귀찮게 몇백줄 적어야할 소스를 미리 적어두고 추가하는 파일들이다. 근데 시발 이거 쓰지말고 cstdio쓰자. ㄴ 댕청하다... cstdio나 stdio.h나 차이 없다. 그리고 .h 안붙어 있는 헤더는 C++용이므로 C언어 쓸땐 곱게 이거쓰자. cstdio를 써도 된다. 허나 기능상의 차이는 없다. 단지 namespace가 다를뿐인데 그것도 C++에서나 생각해야할일 뿐이다. 전세계구급으로 많이 쓸것들은 컴파일러가 알아서 추가한 표준 라이브러리 함수등이 있다 stdio.h도 그중 하나로 표준 입출력함수들이 들어있다. 가끔 몇몇 사람들이 스튜디오나 스트디오라고 읽는데 스탠다드io라 읽거나 스탠다드인풋아웃풋 이라고 읽거나 에스티디아이오라고 읽자 극혐하는 교수들이 있다. */ <nowiki>#</nowiki>define FIREEGG 2 // 부랄이 두개 아닌사람에게는 미안하다. 특정 값을 상수로 정의할 수 있는데 예제에서는 FIREEGG라 적으면 컴파일러가 2라고 치환한다고 보면된다. <nowiki>#</nowiki>pragma once //소스를 한번만 컴파일하게 해준다. 이건 나중에 언어 배우다보면 왜 필요한지 알듯 <nowiki>#</nowiki>pragma warning(disable:4996) /*_s 같은 접미어 안붙은 (printf,scanf) 함수들 경고내는걸 없애준다. (2015 버전부터는 오류가 뜨지않으니 안써도 된다) ㄴ 씹극혐; #define _CRT_SECURE_NO_WARNINGS 최상단에 놓으면 된다고 컴파일러가 메시지로 친히 알려 주잖냐. 보안 경고 없애려고 저 전처리문 붙이는 놈 없길 바란다. ㄴ 오류를 끄라는 말도 컴파일러가 친히 메세지로 알려준다 저런식으로 disable해주거나 말그대로 #define _CRT_SECURE_NO_WARNINGS 달거나 설정꺼라 그리고 밑에 #define _CRT_SECURE_NO_WARNINGS도 사용가능하다고 써놓던가 씹극혐은 뭐냐? 극혐충 소름 ㄴ 읭... 2015버전에서 scanf 쓰면 오류를 띄워주는 게 아니라 아예 컴파일 자체가 안 됨. #define _CRT_SECURE_NO_WARNINGS 붙여야 컴파일 해 준다. ㄴ 세상 븅신들이 많은데 처음 설정할 때 빈프로젝트 말고 프로젝트 마법사로 만들면 된다. 저딴 븅신같은거 쓰지말고 첨부터 똑바로 만들어라 '''msdn에서도 두가지 방법이 제일 간단한 방법이며 보안적 문제가 있다고 한다 정리하면 거기서 거기다 진짜로 제대로 쓸거면 _s 붙이고 사용법대로 호출해라''' */ <nowiki>#</nowiki>ifdef <nowiki>#</nowiki>endif //귀찮으니까 대충설명하면 특정 상수가 정의되어 있으면 <nowiki>#</nowiki>endif까지 컴파일하고 아니면 컴파일 하지 않는다. //ㄴ 미친새끼들 컴공새끼들이라고 ㄴ을 붙이면서도 "//"를 추가하네 극혐이다 시발;; 어느곳에서도 볼 수 없는 주석처리를 여기서는 해놓다니 씹극혐;; // /* */ 로 내가 바꿨다 ===함수=== ---- y = x+1 이라고 보자 선언 정의 호출 3가지가 있는데 선언은 '''반환자료형 함수이름 (변수자료형 변수이름); '''으로 할 수 있다. ex) int Add(int x); // x라는 매개변수로 입력을 받고 Add앞에 붙은 int는 Add라는 함수가 정수형으로 반환할 것이란걸 알려준다. int는 자료형중 하나로 정수형을 나타낸다고 보면된다 (integer의 줄임말) <big>'''주의 : 함수이름이 main 일 경우 프로그램의 시작점이 되며 지금 설명할 것은 사용자 정의 함수이므로 main함수와는 다르다'''</big> 정의는 선언에 세미콜론 때고 중괄호 만들어주고 할일을 넣으면된다. int Add(int x) { return x+1; } //return은 함수를 종료시켜주는 동시에 우변에 있는 값을 반환해준다. 호출은 선언도 했고 정의도 했으니 써먹는 부분에 해당한다. Add(3); // 3을 인자로 넣어줬는데 이러면 정의부분 매개변수에 값이 넘겨지고 return x+1; 구문에 의해 4가되어 반환된다. 참고로 Add(3);은 반환되어진 4로 변환된다고 생각하면 나중에 연계해서 배우기 쉽다 (ex : if( 4 == Add(3) ) 같은 구문) 4로 변환되었는데 변환되기만했지 출력도 안하고 저장도 안했으므로 저장을 해보고자 한다. ===변수=== ---- 변수는 말그대로 변할 수 있는 수를 의미한다. 값을 보관하므로 매우 중요하다고 볼 수 있다. 선언만 해주면 그다음부턴 이름만 쓰면 된다. 선언 방법은 자료형 변수이름; 이 되는데 뒤에 = 숫자 를 붙여서 그 변수에 값을 넣어 초기화 할 수도 있다. ex - int Height = 171; 내 키는 좀더 클테니까 변수로.... ㅅㅂ ㄴ 근데 Weight는 몸무게인데 몸무게가 171이냐 ㄴ 지적 고맙다 잘못 적었다 존나 파오후네 시발ㅋㅋ '''참고로 C언어는 변수의 선언을 위에 둬야 한다 물론 .cpp 확장자를 가지고 C언어를 쓰면 오류가 없긴한데 그게 표준임''' ㄴ 글쎄, 현재 C 표준(C99 이상)에 따르면 중간에 변수 선언해도 된다. 다만 대부분의 컴파일러가 C 버리고 C++로 넘어간지 오래이기에 거의 지원 안 한다. ㅅㅂ ㄴ 답글 말대로 C99 부터는 제한이 풀림으로 상관 없다(옛날 책을 봐서 그런지 몰랐음), 하지만 Visual Studio 2013 부터 C99가 적용되니 그 이하버전은 조심해라 변수 이름은 규칙에 맞게 만들어야함 언더바( _ ) 를 뺀 다른 특수문자들과 공백, 맨 앞글자에 숫자를 넣는건 금지된다. 단어에 의미를 가지고있는 키워드도 금지된다 예를들어 (int int;) 그냥 변수이름 썼는데 갑자기 이름이 파래지면 딴거써라 int fucking_awesome; ( O ) int Monkey D. Luffy; ( X ) int 30cent; ( X ) int var1; ( O ) 이런식으로 보관해두면 나중에 더하거나 빼거나 나누거나 곱하거나 별 지랄을 부릴 수 있다. 반대로 상수가 있는데 이건 변수처럼 지랄을 부릴 수 없다. <nowiki>#</nowiki>define으로 만들거나 const 자료형 변수이름 = 값 ; 이렇게 선언 할 수 있다. 10 3.14 'A' 같은 단순히 숫자나 문자 문자열만 있으면 리터럴 상수라고 한다. (이름이 없는 상수) ===자료형=== ---- 처음보는 사람은 이미 문서를 닫았을테지만 좀더 쓰자면 정수는 int라고 적어둔것을 보았을 텐데 맨 처음 배우고 자주 쓰는 자료형을 적자면 void - [[이종범]] int - 4byte (예전엔 2byte 였다는데) 정수형 integer의 준말 /* int형은 운영체제가 몇비트냐에 따라서 달라진다. 64비트면 8바이트 이런식.*/ ㄴ 웃고간다ㅋㅋㅋㅋㅋㅋ 64비트 운영체제에서도 int는 4바이트다. long int는 크기가 다르지만 그것보다 중요한 것은, 32비트와 64비트가 의미하는건 주소값을 저장하는 공간, 즉 포인터의 크기라는거다. 가만히 있으면 반이라도 가지ㅋㅋㅋㅋㅋㅋ ㄴ 사실 이것도 정확한 설명은 아니고... int는 컴파일러에 따라서 4바이트 8바이트일수도 있다. 컴파일러가 LP64나 LLP64같은 모델사용하면 4바이트고 ILP64쓰면 8바이트된다. 2바이트도 있긴했는데 그건 터보C같은데서나 볼수있었던거고 지금은 별볼일없음. float - 4byte 실수형 (소수점 붙은애들 3.14 이런거) char - 1byte 문자형 (알파벳 하나 보관가능하다 한글은 2byte임을 잊지말자) (정수형과 상호변환이 가능한데 이는 문자형이래도 사실 아스키코드로 보관되므로 변환이 된다.) ㄴ 뭐 간혹 문자형이라고 불리긴 하는데 좆도없다. 그냥 문자보다는 1바이트 저장가능한걸로 생각하는게 덜 편협한 시각을 갖게된다. C가 많이 늙었다고는 하지만 C의 기본 자료구조 이름은 정말 병신같이 지어진거같다. 변수형을 char라고 헷갈리게 적어놔서 문자만 들어갈수있는걸로 착각하게 만들잖아. 차라리 의자형이라고하지 시발 long - int가 2byte였던 시절 4byte 정수형으로 활약했다. 요즘은 long long 써서 8byte 한다더라 double - 8byte 실수형 (VS컴파일러에서 그냥 소수를 적으면 double로 인식한다 float로 할려면 f 접미어 붙이자 3.14f 처럼) ㄴ 공간복잡도 문제 큰 거 아니면 그냥 속편하게 double쓰고 나중에 문제 생길 여지를 만들지 말자 ===Hello, World=== ---- 배운걸로 함 써보자 <source lang="c"> #include <stdio.h> // 아까 말한 표준 입출력 함수(cmd에 글씨 쓰거나 입력받는 함수들)가 들어있는 stdio.h파일을 포함한다. int main() // main함수는 반환형 int로 해주자 ( ) 사이에는 아무것도 안넣을경우 void로 알아서 인식한다. // ㄴ 사실 다르다. 하지만 초보가 신경 쓸 부분은 아니니까 생략. { printf("Hello, World\n"); // printf함수를 호출했고 문자열 Hello, World\n 을 인자로 넣었다. // \n은 escape sequence중 하나로 개행을 해준다. return 0; // 값을 0 반환했는데 main함수에서의 return은 프로그램 종료를 의미한다. 근데 딱히 안 써도 되는 경우가 많다. // ㄴ EXIT_SUCCESS는 어떤 일베충의 지적으로 수정함 자주쓰는 헤더파일이다보니 상관없이 썼다 미안. } </source> 참고로 puts를 쓰라는 사람이 있는데 puts는 put + string이다 즉 문자열만 인식된다. 글자수가 더 적어도 초보자들한테 printf를 가르치는 이유가 숫자 같은거 넣어보기 위해서는 printf를 써야 되기 때문이다. ===주석=== ---- 내가 소스에 // 치고 글쓴걸 봤을텐데 실제로 소스에다가 그냥 말을 써재끼면 당연히 오류를 뿜겠지? 근데 나는 이 소스를 누구에게 보여주거나 과제 제출용 혹은 배포해야 하는데 소스 설명은 해야하잖아 그럴때 쓰는게 주석이야 //를 붙이고 뒤에 글을 쓰면 컴파일러는 그 글을 무시하고 컴파일 한다 //는 행 단위 주석이라고 하는데 //친 시점에서 그 행은 전부 주석처리 되는거지. 근데 주석을 여러개 쓰려고할려면 예를들어 //존나 //귀찮다 //밥먹을까 이렇게 쓰면 일일이 // 치기도 귀찮잖아? 그러니까 /* */ 사이에 글을 적으면 그부분은 주석처리가 된다 이걸 블록 단위 주석이라고 하는데 어떻게 부르건 맘대로 /* 존나 귀찮다 시발 <nowiki>*/</nowiki> 주석처리는 소스와는 상관없이 그냥 소스에대해 설명하기 위해 적어두는 메모 같은 개념이야 위에서 내가 조금 대충 설명했나 미안 ㄴ/* 원래 C에서의 주석은 /* */ 였다 그런데 C99에서 //를 C++에서 가져다 추가한것이다. */ ===연산자=== ---- 가감승제, 조건, 비교, 비트 연산자 등이 존재함 int var; // 이런 변수가 있다고 하면. var = 30 ; // 대입 연산자 의외로 수학하는 사람이 약간 헷갈린다더라. var이라는 공간안에 30을 대입한 것 var = var + 20; // var의 값과 20을 더하고 대입했다. 연산자에도 순서가 있는데 대입 연산자가 제일 순위가 낮아 마지막에 연산된다 보면된다. var += 20; // 복합 대입 연산자라고 한다 방금 전 했던 구문을 줄인 것으로 더하고 대입하는 작업은 똑같다. 위와 같은 방법으로 - / * %도 가능하니 심심하면 해보길 바람. 복합 대입 연산자는 종류가 더 있다. <<= >>= &= ^= |= <<= >>= 는 시프트 복합 대입연산자 인데 비트 배우고나서 배워라 var <<= n 일경우 n만큼 비트를 왼쪽으로 이동시킨다 >>=는 오른쪽 &= 와 ^=, |= 는 각각 And 연산 후 복합대입 , XOR 연산 후 복합대입 OR연산 후 복합대입 비트 연산자에 대입 연산자 붙인거라 생각해라 조건 연산자는 >, <, >=, <=, <nowiki>==</nowiki>, != 가 존재한다 부등호를 모른다면 프로그래밍보단 기본 교육부터 받는걸 추천한다. <nowiki>==</nowiki>는 서로 같음 (수학에서의 = 가 이것이다.) !=는 서로 다름 이 연산자는 참일경우 1을 반환한다. (거짓은 0) 참고로 삼항 연산자도 조건 연산자라고 한다. '''조건 ? 참의경우 : 거짓의 경우 ''' 이런식으로 구성할 수 있다. (ex : var > 30 ? printf(<nowiki>"30보다 큼"</nowiki>) : printf(<nowiki>"30과 같거나 자금"</nowiki>); ) /* * ? : 연산자는 반환값이 있는 점에서 if와 다르다(삼항연산자는 표현식, if는 문장) * foo = bar > 30 ? 5 : 3; * 이런식으로 변수에 값을 묶어주는게 아니라면 그냥 if쓰는게 낫다(가독성) */ 많은 사람들이 모르는 건데 C99부터 iso646.h을 인클루드 하면 !=를 not_eq ||를 or &&를 and, !을 not, |를 bitor, &을 bitand 등으로도 쓸 수 있다. 하지만 <nowiki>==</nowiki>은 그 헤더파일에 정의되어 있지 않다. 비트 연산자를 위에서 잠깐 언급했는데 자세히 얘기한다 너가 컴퓨터로 보고있는 숫자는 0과 1을 표현할 수 있는 비트의 집합이다. 컴퓨터를 어느정도 사용했다면 컴퓨터는 2진수 연산을 한다는걸 들었을텐데 2진수란 2에서 자리올림이 되는 수 표현법중 하나라고 생각하면 된다. 0+1 = 1 1+1 = 10 (2라고 생각할텐데 그건 10진수고 이건 2진수다) 10 + 1 = 11 11 + 1 = 100 (이제 법칙을 알겠지? 2가되면 자리올림이다) 2진수화된 숫자를 10진수로 바꾸는걸 힘들어하던 몇몇 고등학생이 생각나는데 컴퓨터 개론에서 배우는 8421코드만 대충 알아도 시간주면 푼다 물론 여기서 설명하긴 귀차느므로 128 64 32 16 8 4 2 1 이렇게 2의 n배수 표를 만들고 그밑에 너가 10진수로 바꾸려는 2진수를 오른쪽부터 채워넣어라 그리고 1이 된 2의 n배수들을 전부 더하면 그게 변환된 10진수다. 아무튼 비트연산자는 일반 정수를 넣고 그 비트를 주작할 수 있는 고마운 연산자인데 & | ^ ~ 가 있다. & 는 AND 연산자인데 이 연산자는 왼쪽 오른쪽 비트의 각 자리를 대조해서 둘다 1일경우 1을 변환하며 나머지는 0으로 처리한다 예를들어 2진수 101(10진수로는 5) 와 1101(10진수로는 13) 을 AND 연산한다면 ( 5 & 13 ) 0101 (101 앞에는 0으로 채워두는게 비교하기 편하다) 1101 <nowiki>----</nowiki> 0101 // 이해가 됐는지는 모르겠는데 위와 아래 자리가 둘다 1이므로 1이고 나머지는 둘다 1이 아니므로 0이다. | 는 OR 연산자이며 이 연산자는 AND와는 다르게 두개의 비트중 하나라도 1이면 1이되고 아니면 0이 된다. 5 | 13 으로 다시 예를 들자면 0101 1101 <nowiki>----</nowiki> 1101 // 13이 되는거시다! ^ 는 XOR 연산자인데 꽤나 특이한 것이 각 비트가 서로 달라야 1이되고 같으면 참이된다 즉 서로 배타적이여야 참인데 그래서 배타적 논리합 이라고 한다. 5 ^ 13 으로 다시 예를 들자면 0101 1101 <nowiki>----</nowiki> 1000 // 8이 되었다 이해가 가는가? ~ 는 NOT 연산자인데 이 연산자는 0을 1로 1을 0으로 바꿔버린다. ~5 할경우 0101 <nowiki>----</nowiki> 1010 '''알아둬야 할 것이 있는데 만약 일반 정수를 ~해서 바꿀경우 음수가 되는데 왜냐하면 정수의 맨 앞비트(MSB)는 부호비트로 부호를 결정하는 비트이다.''' '''2진수로 표현된 음수는 바로 알아보기는 힘드므로 2의 보수를 취해 그 크기를 알수 있다 (2의 보수 : 모든비트 반전후 +1) ''' '''1010이 결과라고 했지만 실제 프로그램 내부 정수는 4바이트므로 11111111 11111111 11111111 11111010 으로 된다.''' '''참고로 여기서 1010에 +1을 해줄경우 원래 숫자 ( 5 )를 음수로 바꾼 값이 나온다 (var = 5 , ~var+1 <nowiki>==</nowiki> -5) ''' 시프트 연산자는 아까 설명했으니 따로 설명하지는 않는다. 논리 연산자는 && || ! 가 존재하는데. A && B 는 A와 B가 둘다 1(참)일 경우 1을 반환하며 아닐경우 0(거짓)을 반환 A || B 는 A와 B가 둘중 하나만 참이여도 1을 반환하며 아닐경우 (두개다 0) 0을 반환 !A A를 반전한다 (A가 1이면 0으로 0이면 1로) ===제어문=== ---- '''C언어 입문 통틀어서 매우 중요도 높음 이거 모르면 프로그램 못짠다''' 제어문은 말그대로 프로그램의 흐름을 제어하는 구문들이다. 조건문 반복문 goto문이 존재한다. (혹시 빠트린거 있으면 추가바람) '''제어문 옆에 세미콜론 붙이는거 아님''' 조건문의 종류로는 if, else if, else, switch-case 문이 존재한다. if문은 대표적인 조건문으로 if( 조건 ) { 명령 } 이런 구성이다. 조건이 참일경우 ( 1일 경우 (조건 연산자가 1과 0을 반환하는 이유 중 하나) ) 중괄호 사이의 명령을 실행한다. 예를들어 var 이라는 변수가 5보다 크고 10보다 작을경우 Hello를 출력해보자 if( var > 5 && var < 10 ) { printf(<nowiki>"Hello\n"</nowiki>); '''// 부들부들.. 왜 요즘 애들은 이 좋은 puts 함수를 모르는 거냐? puts(<nowiki>"Hello"</nowiki>);''' //puts가르쳐놓고 변수출력하라할거냐? 문자열만 출력한답시고 puts랑 printf랑 번갈아가면서 쓰면 맛보기로 보는데 참 좋아라하겠다 } 이러한데 제어문은 실행할 명령이 1줄 일경우 굳이 중괄호를 치지 않아도 된다. if( var > 5 && var < 10 ) printf(<nowiki>"Hello\n"</nowiki>); 이렇게 조건을 걸어 참일 경우 특정 명령을 실행할 수 있다. 그런데 만약 다른 예외의 경우가 있다고 한다면 if 문을 또 써야할텐데 그럴때는 else if 문을 사용할 수 있다 if문과 사용방법은 같지만 if문 뒤에 와야한다. 예를들어 var 이 10과 같거나 크고 15보다 작을 때 Welcome 을 출력한다면 if( var > 5 && var < 10 ) printf(<nowiki>"Hello\n"</nowiki>); else if( var >= 10 && var < 15 ) printf(<nowiki>"Welcome\n"</nowiki>); 이처럼 예외를 만들어 줄 수 있다. 다만 두개의 조건이 거짓일때 Bye라고 해줘야한다면 일일히 조건걸기 매우 힘들것이다. else문을 사용하여 쉽게 만들 수 있는데 else문은 if, else if 에서 나온 조건들이 전부 거짓일경우 중괄호 안 혹은 한줄의 경우 바로 밑 명령을 실행한다. if( var > 5 && var < 10 ) printf(<nowiki>"Hello\n"</nowiki>); else if( var >= 10 && var < 15 ) printf(<nowiki>"Welcome\n"</nowiki>); else printf(<nowiki>"Bye\n"</nowiki>); 위에서도 말했지만, if문 옆에 세미콜론(;) 절대 붙이지마라. 안그러면 조건에 맞지 않는데도 if문 안이 실행되서 엥? 하기 때문이다. switch문은 어떤 한 변수를 두고 그 변수가 무슨 값이냐에 따라 하나를 선택하는데 다중 선택 제어문 이라고도 부른다 switch(변수) { case 값1: 명령 break; case 값2: 명령 break; } 이런식으로 구성되는데 예를들어 한 게임의 scene에 따라 화면 구성을 바꾸려고하는데 1은 시작화면 2는 대기화면 3번은 게임화면이라고 하자. switch(scene) { case 1: //시작화면 break; case 2: //대기화면 break; case 3: //게임화면 break; } 이렇게 나누면 아주 좋다 break문으로 switch를 빠져나가는데 나중에 배울 반복문에도 사용가능하다. 참고로 break;문을 해주지 않으면 어떻게 되는지는 예를들어 설명하겠다. switch(scene) { case 1: //시작화면 break; case 2: //대기화면 case 3: //게임화면 break; } 현재 이런식으로 된 스윗치문이 있다고하면 2번 case에는 break; 가 없다 이경우 실행해보면 3번 case 까지 실행하는데 아마도 하나의 케이스를 찾으면 그 다음 케이스 부터는 무조건 참으로 들어가 명령을 실행한다 보면된다. 작성자들 고마워! 위키 보면서 제일 쓸모있는 문서같다 추가 제발 while(a>3)이 된다고 switch(a>3)도 되겠지? 하지마라. 반복문은 말그대로 반복하는 구문인데 활용도가 굉장히 높고 안쓰이는 프로그램을 찾아보기 힘들 정도로 대부분에 사용된다. 어느정도 배웠던 혹은 위를 천천히 읽어본 독자는 printf 라는 함수로 간접적으로 메세지를 출력하는 방법을 알았을 것이다. 어느날 시험으로 Hello, World! 를 100번 출력하라는 문제가 제출되었다고 하면. 반복문을 배우지 않은 사람은 printf(<nowiki>"Hello, World!\n"</nowiki>); 를 100번 쓰기위해 Ctrl+C, V를 남발할 것이며, 적어도 소스가 100줄이상은 나올것이다. 만약 컴파일러에게 저 문장을 100번 반복해 라고 하면 얼마나 편할까? 반복문은 for, while , do while 이 존재한다. for문은 for을 쓰고 소괄호 안에 초기식 ; 조건식 ; 증감식 이 되어 이 식들에 따라 괄호안에 있는 문구를 반복한다. 즉 for(초기식;조건식;증감식) 이런식으로 작성되고 ;(세미콜론) 은 각 식들의 구분점이 된다. (그리고 초기문 증감문 증감문 으로 하든 뭐라하든 개념만 잡히면 되므로 별로 명칭은 중요하지 않다.) '''주의 ) 가끔씩 for(초기식;조건식;증감식); 이런식으로 끝에 ;를 붙이는 사람이 있는데 그러면 중괄호 내용이 반복되지 않는다''' ''' ;은 문장의 끝을 알려주는 역할로 알면 쉬운데 말그대로 { }가 닿기전 for문 끝에 ; 에 의해 for문이 지혼자 반복하다가 끝나고''' ''' { } 안에 있는 내용은 그냥 하나의 블록이 되어 한번 실행하고 넘어간다.''' ''' 허나 프로그램 지연(Delay)을 위해 사용되기도 하는데 어처피 다 Windows.h 불러와서 Sleep 함수 쓰거나 다른 처리를 하므로 ''' ''' 실질적으로 Delay를 이렇게 주진 않는다고 보면 된다. (허나 어느 강의에서는 가르치기도 하고 좋은 경험이 될 수 있으므로 봐두는게 좋음''' 백문이 불여일견 예시를 작성하자면 int var; for(var = 0;var<100;var++) { printf(<nowiki>"Hello, World!\n"</nowiki>); } 자 한번 정리해서 보자 초기식 : var = 0 조건식 : var<100 증감식 : var++ => var=var+1 (1씩더해주는것이다 두개 의미는 같다.) ㄴ 미묘하게 다르다. var++의 값은 var이지만 var=var+1의 값은 var+1이다. 여기서 기능상 차이는 없지만 같은 의미를 고집하고 싶으면 ++var을 쓰면 된다. 초기식은 말그대로 반복하기에 앞서 맨처음 실행되는 식이다 이때 var에 0이 대입되어 var이라는 공간안에는 0라는 값이 들어있다. (0도 값이다) 조건식은 반복문이 중괄호 { } 의 내용을 실행할지 말지를 결정하는 조건이 되며 참 일경우 실행 거짓 일경우 for문 실행을 중단하고 그 다음 구문으로 넘어간다. 조건식은 중괄호의 내용이 한번 반복할때마다 실행되며, for문이 초기식을 실행하고 조건식을 걸쳐 { } 사이의 내용이 실행된 다음 증감식 실행 후 조건식 실행 후 { } 실행 이 반복된다. 초기식 조건식 { } 실행 증감식 조건식 { } 실행 증감식 조건식 { } 실행 ... // 이런식의 반복이다. 증감식은 말그대로 변수를 증가 감소 시키기위해 사용되는 식인데 사실 무조건 증가 감소만 되는게아니라 곱하기 나누기도 되며 심지어 함수 호출도 된다! 그리고 초기식과 증감식은 , 연산자로 두개 이상하는것도 가능하다 ( for(var1=0,var2=0;var1<=100;var1++,var2++) 이렇게 (보기어려우면 ;를 구분해서 봐라)) 두개의 조건식을 원한다면 논리 연산자를 사용하는것이 좋다. ( x == 1 && y == 2 ) (예시를 좀더 간단히 쓴다면 for(var=0;var<100;var++,printf(<nowiki>"Hello, World!\n"</nowiki>)); 이렇게써도 된다 다만 99번출력되므로 알아서 조건식 1더하던가 해라) 증감식은 대체로 반복문을 중단시키기 위한 용도로 사용되는 경우가 많다. 증감식에서 변수를 증가하거나 감소시켜 원할때 조건문을 참, 거짓으로 만들어 원하는 작업을 실행할 수 있다. 그리고 조건 연산자를 얘기할때 참일경우 1 거짓일경우 0으로 나타낸다고 했는데 그 조건연산자를 조건문에서 실행하는 것으로 보아 조건문에는 실질적으로 1 혹은 0 이 들어갈 수 있음을 유추할 수 있는데. for(;1;) 이렇게 될경우 무조건 조건식이 참(1) 이 되므로 { } 에 있는 명령을 무한 반복한다. (무한루프라고 부름) for(;0;) 은 무조건 거짓이므로 반복 될 수 없으며 조건식을 거치지 못했으므로 { } 의 명령은 한번마저도 실행될 수 없다. 다만 for(;;) 이라 해도 무한반복 한다. 무한 반복은 거의 쓸모없어 보이나, 의외로 쓰는 사람이 꽤 있는데 게임만드는 사람은 공부할적에 한번씩 써봤을 것이다. 이유라 하면 상대방의 입력을 받고 화면에 출력하며 끄라는 명령이 언제 내려질지 모르므로 무한 반복해놓고 나중에 사용자가 끌려고 할 때 break 문이라는 것으로 무한반복되는 반복문을 빠져나간다. break; 문은 단어에서 오는 느낌 그대로 반복문을 깨버린다. (다만 반복문에 한정되지 않고 switch에서도 사용된다.) 예시를 들자면 조건문을 비워둔 상태(무한반복) 에서 그 반복문을 나가야 할 경우 int var; for(var = 0;;var++) { if(var >= 100) // 또는 if(var == 100) 해도 별로 상관은 없다. break; printf(<nowiki>"Hello, World!\n"</nowiki>); } 이렇게 무한루프에서 빠져나올 수 있다. break와 자매품으로 continue가 있는데 이건 break처럼 반복문을 한번 나오고 끝이 아니라 밑의 내용을 실행하지 않고 바로 다음 반복을 실행한다. 이게 뭔말이냐 하면 만약 짝수 (2의 배수) 일 경우 Hello, World!를 출력을 못하게 하려 한다면 int var; for(var = 0;;var++) { if(var % 2 == 0 && var != 0) continue; printf(<nowiki>"Hello, World!\n"</nowiki>); } var % 2 == 0 에서 조금 헷갈릴 수 있는데 %는 나머지 연산자이며 좌항을 우항으로 나눈 나머지를 연산해주고 그 나머지가 0이라면( == 0 ) 그리고 논리연산자 &&(AND) 가 붙음으로 var의 값이 나머지가 0이고 var의 값이 0이 아니라면 (var != 0) continue;가 실행되 바로 다음 반복으로 간다. ( 밑의 printf는 호출되지 않고 바로 넘어가서 증감문->조건식->{ } 실행 ->증감문->조건식 ...) 반복문은 for뿐만 아니라 while도 있는데 while문은 소괄호 안에 조건식만 있는 간단한 형태임 while(조건식) { ... } 이런식인데 초기식과 증감식이 없는 관계로 따로 추가해줘야된다. 초기식 while(조건식) { ...//명령 증감식 } 이런식의 배치를 하면 for문과 같은 순서로 실행 가능하다. while과 for문 어느것을 쓸지는 이러저리 말이 많은데 그냥 꼴리는대로 쓰면 된다. do while 문도 존재하는데 for문이나 while문은 처음 반복 시작할때도 조건이 거짓이면 실행조차 되지않는데, 무조건 한번은 명령이 실행되어야 할 경우에 사용한다. do { 명령 } while(조건식); 이렇게 쓰면된다. 세상에는 여러 작업들이 있는만큼 반복하면서 또 반복해야 할 경우도 많은데 예를들어 창문을 닦을때 창문이 10개라고 가정할때 반복문 10번 돌게하고 창문을 닦는 명령을 하면되는데 창문을 닦을때 분무기를 3~4 번 뿌리고 신문으로 닦는다고 가정하자 그러면 반복문안에 반복문이 또 들어가는 상황이 연출되는데 그것을 이중루프 또는 다중루프 라고 한다. 한번 예시를 작성해보자 int var1,var2; for(var1=0;var1<10;var1++) { for(var2=0;var2<4;var2++) { 분무기 칙칙 } 창문 닦기 } 반복문 안에 또 반복문이 있는 형태인데 약간 머리가 어지러울 수 있으니 어떻게 진행되는지 천천히 잘 생각해라. 반복문 1 시작 (초기식->조건식) 반복문 2 시작 (초기식->조건식) 분무기 칙칙 반복문 2 (증감식->조건식) 분무기 칙칙 반복문 2 (증감식->조건식) 분무기 칙칙 반복문 2 (증감식->조건식) 분무기 칙칙 반복문 2 (증감식->조건식) (4번돌아 var이 4가 되었으므로 거짓이 되고 반복문을 빠져나옴) 창문닦기 반복문 1 (증감식->조건식) 반복문 2 시작 (초기식->조건식) 분무기 칙칙 반복문 2 (증감식->조건식) ... 이렇게 진행된다 글로적기 좀 뭐한감이 있는데. 1번째 반복문이 n번을 돌때 2번째 반복문이 m번을 돈다하면 2번째 반복문은 총 n*m번을 돌게된다 즉 하고싶은 말은 1번째 반복문에 의해 2번째 반복문이 반복된다는 말이다. goto문은 강력한 흐름제어문인데 웬만하면 안쓰는게 좋다. goto문을 남발할경우 C언어의 특징인 절차적임을 잃고 흐름이 중구난방하게 꼬인다. 그에따라 가독성도 나빠지고 작성하기도 꽤 곤란해지는 경우가 많다. 사용법은 특정한 지점에서 적당한 이름짓고 :를 붙여서 나중에 필요할때 goto 이름; 하면 그 특정한 지점으로 이동하여 다음 명령을 실행한다. 반복된 루프에서 한번에 빠져나가기 곤란할때 꽤 유용하다. (break문은 한번에 하나의 루프를 빠져나간다.) ===배열=== ---- 아까 설명했던 변수는 값을 보관하기 위한 공간이라고 말했는데, 그 공간을 여러개를 나열한 것을 배열이라고 보면된다. 내가 예를들어 int a; 라고 적으면 정수를 보관하기 위한 공간이 생기고 그 공간을 a라고 하는데 예를들어 여기에 30명의 학생들 성적을 보관한다고 치면 int grade1,grade2,grade3,grade4...grade30; //실제로는 ... 치면안되고 일일이 끝까지 적어야한다. 이렇게 일일이 전부 적어야하는 노가다,시간낭비하는 좆병신같은 상황이 연출되는데 그럴때 쓰는게 배열이다 위에서 변수를 30개 만들때 일일이 다쳤다고하면 배열은 int grade[30]; 이거 하나로 끝난다. [와 ] 사이에 30이 적혀있는걸 볼 수 있는데 왠만한 병신이 아니고서야 만들고자 하는 변수의 갯수란걸 알 수 있다. 이렇게되면 int형 변수 30개가 만들어지는데 점수를 넣고자 하면 grade[0] = 73; // 변수에 접근하고자 할때는 [와 ] 사이에 첨자 (나열된 변수의 번호 개념,index) 를 적어서 거기에 대입하면 된다 주의할 점은 '''첨자는 0번부터 시작한다 그리고 29번까지 사용한다.''' 즉 처음에 변수 선언할때 적은 0 ~ 첨자 - 1 까지 쓰는 것 이다. 참고로 변수 선언시에는 [ 와 ] 사이에는 '''무조건 상수'''만 들어갈 수 있다 변수 안된다. 위에 설명한것 처럼 변수 선언할때 첨자를 적어서 만들어진 배열을 정적 배열이라고 한다. 정적 배열의 단점은 변수 갯수를 변수 선언할때 무조건 정해야 하므로 만약 갯수가 딱 맞지 않는다면 공간 낭비 혹은 공간 부족 등의 문제가 있을 수 있는데 이를 해결하는 것이 바로 동적 배열이다. 예를들어 학생 성적 기록 프로그램을 만든다고 하자. 학생이 29명인지 30명인지 31명인지 모르므로 정적 배열일 경우 많이 만들어놓고 필요한 공간만 쓸 수 밖에 없는데 그렇게 되면 남는 공간은 만들어진 채로 썩어가게 되는데 동적 배열을 사용해 임의의 공간을 할당하고 해제 하여 사용할 수 있다. 사용법은 조금 어려워 보일 수 있는데 stdlib.h 를 include 한다음 <nowiki>int *grade = (int*) malloc( sizeof(int) * students);</nowiki> 하면 students 변수의 값만큼 int형 변수를 만들 수 있다. 위 malloc함수는 바이트 수만큼 메모리를 할당하여 주소를 반환해주는데 이 때 반환해주는 자료형이 void* 이므로 캐스팅연산자 즉 (int*)를 앞에 적어 준다. grade 옆에랑 (int*) 에 붙은 *가 뭔지 모를텐데 그냥 해당 자료형을 가르키는 주소를 보관하는 자료형이라 보면된다. 약간 비약을 섞어 말하자면 *가 안붙으면 값을 보관하고 *가 붙으면 주소를 보관한다고 보면 된다. 자매품으로 ** 도 있는데 이건 주소를 보관하는 변수의 주소를 보관하는 변수다. <nowiki>*</nowiki>의 갯수에 따라 n차 포인터라고 한다. 포인터 항목에서 다시 설명하겠다. 아무튼 저렇게 선언하고 평소대로 grade[0] = 30; 이런식으로 쓰면된다. 배열이 중요한 이유는 선언의 간편함도 있지만 관리가 매우 유용하기 때문인데 예를들어 배열 없이 학생성적을 전부 출력하려고 한다면 printf(<nowiki>"1번 학생 점수 : %d \n",grade1); </nowiki> printf(<nowiki>"2번 학생 점수 : %d \n",grade2); </nowiki> ... printf(<nowiki>"30번 학생 점수 : %d \n",grade30); </nowiki> 같은 개떡같은 상황인데 개쩌는 배열은 다 좆까고 반복문 사용해 2줄이면 된다. int i; for(i=0;i<30;i++) printf(<nowiki>"%d번 학생 점수 : %d \n",i+1,grade[i]); </nowiki> ㄴ TMI지만 1줄로도 된다. for(int i=0; i<30; i++) printf(<nowiki>"%d번 학생 점수 : %d \n", i+1,grade[i]); </nowiki> 반복문을 사용해 i를 증감시키면서 printf문을 30번 반복하고 grade 첨자 안에 증감되는 i를 넣어 0부터 29까지 전부 접근해서 출력할 수 있다. 아까 첨자에 변수넣는거 안된다고 하지않았나 하면 다시봐라 변수 선언시에만 상수로 만드는거다. '''그리고 그 배열을 free함수로 할당해준 메모리를 해제 해줘야한다. ( 하는법은 free(grade); )''' 이 밖에 특이한점은 char 자료형의 배열인데. char이 문자형 이였지만 배열일 경우에는 문자열 이라고 한다. 문자형과 문자열의 구분은 <nowiki>'와 ' "와 "</nowiki> 인데 printf 함수 안에 문자열을 넣은걸 보면 쉽게 알 수 있다. char ch = 'a'; char string[10] = <nowiki>"abcdefghi"</nowiki>; 이렇게 차이가 존재한다. 문자열을 선언 할 때는 <nowiki> "문자열" </nowiki> 이렇게 적어서 초기화 할 수 있는데. 정작 대입할때는 안된다 예를 들자면 char string[10] = <nowiki>"hello"</nowiki>; // 이건 된다. string = <nowiki>"bye"</nowiki>; // 이건 에러난다. 그리고 주의할 점이 있는데 문자열은 맨뒤에 \0 즉 널문자가 붙는다. '\0' == (char)0 컴퓨터의 입장에서 C의 문자열은 단지 메모리에 쭉 늘어선 숫자들일 뿐이기 때문이다. 문자열 관련 함수는 자신이 처리해야할 문자열과 건드려서는 안 되는 다른 데이터를 구분해 줄 표식이 필요한 것이다. 아무튼 널문자가 붙으므로 한 자리를 비워둬야한다. 예를들면 첨자에 10넣어서 배열 선언하면 문자열은 9개의 문자만 사용해야한다. 참고로 한글은 2byte이므로 9개가 아니라 4개밖에 못쓴다. 알파벳은 1byte 맞는데 한글이나 특수기호는 아니다. 위에 사용함으로써 얻는 장점들을 꼽자면 1. 다수의 변수 선언이 매우 용이하다. 2. 같은 용도의 많은 변수 관리가 매우 편해진다. 3. 위의 2가지를 해결함으로써 반복적 코딩을 줄이고 동적 배열로 메모리의 효율적 사용도 가능해진다. 배열은 arr[첨자] 로 각 첨자에 있는 변수에 대한 접근이 가능하다 설명했는데 이러한 접근도 가능하다. <nowiki>*(arr+0) = 3;</nowiki> 위 구문은 <nowiki>arr[0] = 3;</nowiki> 과 결과적으로 똑같으며 위의 구문을 이제부터 알 수 있도록 C 입문자들이 그렇게 혐오한다는 포인터에 대한 설명을 하겠다.
요약:
조무위키에서의 모든 기여는 CC BY-SA 4.0 라이선스로 배포된다는 점을 유의해 주세요(자세한 내용에 대해서는
조무위키:저작권
문서를 읽어주세요). 만약 여기에 동의하지 않는다면 문서를 저장하지 말아 주세요.
또한, 직접 작성했거나 퍼블릭 도메인과 같은 자유 문서에서 가져왔다는 것을 보증해야 합니다.
저작권이 있는 내용을 허가 없이 저장하지 마세요!
취소
편집 도움말
(새 창에서 열림)