C언어
조무위키
주의. 이 문서는 공머생들이 좋아하는 주제 혹은 공머생 그 자체에 대해 다룹니다. 본 문서가 다루는 내용에 지나치게 탐닉할 경우 필연적으로 여성들과 멀어지게 됩니다. 이는 조무위키가 책임지지 않습니다. |
이 문서는 이과가 작성했거나, 또는 이과에 대해 다룹니다. 무슨 생각으로 작성한 건지는 잘 모르겠습니다만 맞는말임은 틀림 없습니다. 이과는 아다를 못 떼 마법을 쓰니까 말이죠... |
주의. 이 문서에서 다루는 대상은 너무나도 쓰레기 같습니다. 이 쓰레기는 쓰레기보다 더 쓰레기 같아서 쓰레기에게 미안한 마음이 들 정도입니다. 이 문서 보고 쓰레기 생각한 당신, 당장 쓰레기한테 사과해. |
주의! 정말 극혐인 내용을 담고 있습니다. 이 문서는 정신적 또는 시각적 피해를 받을 수 있는 내용이 담겨 있습니다. 이러한 피해를 받지 않으려면 살포시 뒤로가기를 눌러 주십시오. 이를 무시하고 문서를 보아서 피해를 입더라도 디시위키는 일절 책임을 지지 않습니다. |
c언어 갤러리 - https://gall.dcinside.com/tcpl
오래된 컴퓨터 언어이지만 배워야한다. 요즘은 트렌드가 많이 변화되어서 파이썬>C언어>C++ 트리를 추천함
근데 아직까지 고딩들 교육과정에는 c언어가 기본이라C언어를 고1,2학년때 먼저 배운후 선생들 재량에 따라서 파이썬을 추가로 배우기도 한다.
개요[편집]
50년대만해도 꼼쀼타에 직접 이진수 코드 01001... 치는게 좃같아서 어셈블리어를 만들었음. 어셈블리는 기계어와 1대1대응하기 때문에 MOV !FCNT,#8 이렇게 뭔개소린지 ,지랄같았음 그래서 만든게 C언어.
저급언어: ㄱㅣ계어 , 어셈블리어... 고급언어: c언어 java 베이sic... 위에서 알 수 있듯이 사람언어와 가장 가까운걸 고급언어라 한다. 저급언어는 010101010110 이렇게 개소리같고 컴퓨터에 촤적화된걸 말한다.
또 ADD R2, R1 이런 어셈블리어도 저급언어에 속한다.
ㄴ내가 대충 적다보니 착각한거 같아서 다시 적는데, 내가 말한 건 저수준 언어에 가깝다지 그냥 저수준 언어라는게 아니었음;;; 솔직히 C언어 지금 보면 비교적 저수준에 가까운 건 맞잖아, 안그래? 메모리 할당도 지가 풀어야 하고, 사람 편의성보다 기계적 속도에 맞춘 세팅도 많고, 최적화도 나중의 언어가 속도 조금 희생해도 확실히 구동하게 바꾸는 경우도 있는 반면 C언어와 C++은 걍 개발자 수준을 믿잖아.
ㄴ 너 말도 맞다. ㅇㅇ
위에 적혀있듯 C언어도 지금 보면 꽤 저수준적인 면모를 보인다. 난이도로 치면 기계어가 좆자고 어셈블리어가 향찰, 이두라 하면 C언어는 오늘날 훈민정음 정도의 위치에 있다고 볼 수 있다. C언어로 게임을 짜보면 뭔 말인지 이해가 갈 것이다.
메모리 할당 같은걸 너가 직접 다 해줘야 한다.. 네덕 새끼들은 이걸 배우면 해킹을 할 수 있다고 믿는 모양이다. 유우키 아스나 문서 개요 문단의 캡쳐본을 보자. C언어 배우면 너 먼저 털어준댄다ㅋㅋ
malloc free 씹극혐.
ㄴ 왜 비주얼 스튜디오 2015는 가변 길이 배열이 안돼냐 ㅅㅂ
너가 컴퓨터 관련 학과인데 동적할당을 모르면 자퇴 아니면 전과를 추천한다 씨발 틈만나면 쓴다.
이 좆같은새끼가 네트워크 통신으로 들어오면 존나 고마워진다. 사실 나는 자바를 배운적이 없어서 모르겠지만 자바로 통신을 하려고할때 구조체가 없어서 바이트단위로 패킷을 날리는게 좀 좆같았는데 C언어는 구조체로 알아서 나눠서 보내고 받을 수 있기 때문에 존나 편하다. 앙기모띠 씨발근데 코딩하기 존나싫다
께임을 하다 트롤링에 빡쳐서 상대를 해킹할 때 배워야하는 언어이다. 실제로 "내가 해킹하려고 c언어 배우고 있거든?" 발언한 사례가 있다.
안녕, 헬조선[편집]
<source lang="cpp">
- include <stdio.h>
int main() {
printf("안녕 헬조선!\n"); /*대학교가면 이걸로 삼각형 출력하는 프로그램 만드는 지랄을 함*/ printf("안녕하신가 힘세고 강한 아침\n"); return 0;
} </source>
<source lang="cpp">
- include <stdio.h>
- include <string.h>
int main() {
int score = 40; char grade[5]; if(score >= 90) strcpy(grade,"A+"); else if(score < 90 && score >= 50) grade[0] = 10 - (int)(score / 10) + 63; else strcpy(grade,"dick"); printf("당신의 점수와 등급은 %d,", score); for(int i = 0; i < strlen(grade); i++) printf("%c",grade[i]); printf("입니다. 축하합니다 병신아 전문대에 오신것을 환영합니다\n");
} </source>
<source lang="cpp"> typedef unsigned char* byte_pointer;
void show_bytes(byte_pointer start, int len){
for(int i = 0; i < len; i++) { printf(" %.2x", start[i]); }
}
int main() {
for(int i = 0; i < 99999899; i++) { int val = 0x00000001 * i * 100; byte_pointer valp = (byte_pointer) &val; show_bytes(valp,100); }
} // 올릴거면 이런 유익한 예제를 올려라. csapp 예제 응용이다. // 전혀 유용하지가 않다 차라리 스왑예제가 인생에 더 유익할거다. </source>
<source lang="cpp">
- include <stdio.h>
void swap(int* a, int* b){
*a ^= *b; *b ^= *a; *a ^= *b;
}
int main(int argc, char* argv[]) {
int num1 = -10; int num2 = 35; printf("%d %d",num1, num2); // 출력 결과 : -10 35 swap(&num1, &num2); printf("%d %d",num1, num2); // 출력 결과 : 35 -10 return 0;
} //그래서 스왑 예재도 올렸다. 싸우지 말고 야스해라 </source>
프로그래밍 언어[편집]
엣헴! 이 문서에 선비가 왔다 갔습니다. 이 문서는 선비님의 등장으로 인해 노잼이 되어가고 있는 문서입니다. 진지한 문서를 원하시면 위키백과로 가주십시오. |
C언어 소스파일. 저장할 땐 제발 뒤에 .c 붙이는 거 잊지 마라
ㄴ cpp으로 하나 c로 하나 include 할때 stdio.h 만 잘 입력 해주면 되기에 별 상관 없다. 물론 확실하게 하고프면 당연 c로 하는걸 강력 아주 강력 추천한다.
컴퓨터가 수행할 수 있는 명령어를 작성하는 데 사용하는 언어 중 하나이다. 많은 언어가 존재하며 C언어가 흔히 알려져 있다.
해킹을 배우던 게임을 개발하던 로봇을 만들던 간에 한 번쯤은 거친다. ('폰 노이만'은...)
흔한 만큼 흔히 가르치는 경우가 많아서 이쪽으로 재능이나 흥미가 없는 인간들의 경우, 문서 상단에서 볼 수 있듯이 쓰레기 취급을 한다.
애초에 컴퓨터가 존나 빠른 계산기라서 거기에 구동되는 프로그램도 수학적인 요소가 들어갈 수밖에 없다. (알고리즘)
그렇기에 C언어와 같은 프로그래밍 언어만 잘 안다고 해서 잘 한다고 말할 수는 없다.
개 씹 좆병신 언어다. 자바 등 언어에 재능 없으면 그 시간은 어떤 수면제보다 강력할 것이다.
주의! 이 문서에선 지금 병림픽이 벌어지고 있습니다! 이 문서에는 병신들이 승리한 병신이 되기 위해 병신 같은 병림픽을 벌이고 있습니다. 팝콘을 먹으며 이 병신들의 지랄을 감상하다 승리한 병신이 나왔을 때 이렇게 말해 주세요. "축하한다, 병신아." |
단순한 예제를 실험해볼 거면 VS 컴파일러보다는 Dev C++ 컴파일러를 쓰는 것이 훨 편하다.
ㄴ다만 Dev는 존나 불편하므로 코드블럭 쓰자.
ㄴㄴ걍 다 ㅈ까고 vi와 gcc조합을 쓰자 병신들아
ㄴvi 존나 불편한 쓰레기 에디터 누가 쓰냐 Sublime Text + gcc가 갑이다. 굳이 리눅스 기본 에디터를 써야겠다면 nano 써라.
ㄴvi 존나 좋다 씨발 마우스 움직이는 게 얼마나 불편한데
ㄴ 장애짓 권장하지 마라
ㄴ 컴잘알인척 하는 븅신새끼들이 하는 지랄이니 니들은 비쥬얼 스튜디오나 써라
ㄴ vi = 가오용, emacs = ㅇㄱㄹㅇ 좋아서 쓰는거
ㄴDev는 C++할때나 쳐쓰는거고
ㄴ 노트패드++써라 병신들아 존나 가볍다
다만 미친놈들이 vim과 gcc를 끼고 터미널로 컴파일하라는 개소리를 하는데, 초보자 입장에서 아무 장점도 없으므로 무시하는 게 편하다.
이 문서는 확고히 검증된 진실입니다. 이 문서는 거짓이 전혀 없는 완벽한 진실을 말하고 있습니다. 이 문서를 읽을 때는 안심하셔도 되니 편안한 자세로 보시기 바랍니다. |
위의 ㄴ충들의 말은 무시해도 좋다. 저런 말하는 애들 특징은 현업 개발 경험이 없다는 거다. 세상 어느 회사를 가도 vim, emacs, Sublime Text 따위로 개발하는 회사는 존재하지 않는다.
무슨 뜻이냐면 뭘 쓰든 현업과는 거리가 멀고 취향 차이니까 니가 쓰고 싶은 거 쓰라 이거야.
장점이라고 한다면 빠른 거. 적어도 Java같은 병신같은 최적화를 자랑하는 언어보다는 낫다.
그런데 빠른 거는 아무 짝에 쓸모없다. 프로그래밍은 속도보다 안정성이고 C언어는 메모리 관련 공격에 존나게 취약한 병신 언어이기 때문에 기본만 배우고 자바나 파이썬으로 갈아타라. 0.1초 걸릴 걸 C언어로 0.01초 걸려서 처리한다고 도움되는 거 하나도 없고 니가 코드를 스파게티마냥 좆같이 써 놓은 게 아니면 무슨 언어로 쓰든 잘 돌아가니깐 상관없다.
- ㄴ마인크래프트가 왜 느린지 모르냐? 그냥 최적화가 필요없는 건 자바 써도 문제 없겠지만, 게임처럼 최적화 필요하면 C언어나 C++ 써야 됨. 즉, 연산량이나 램을 많이 요구할수록 Java는 못 굴려먹을 언어가 되니 '아따 0.0몇초가 0.몇초가 된당께요!' 이딴 소리 하지 말자. 이걸 좀 극단적으로 확장하면 몇 분 걸릴 거 몇십 분 걸리게 만들 수도 있다.
- ㄴ 이 븅신은 메모리 관리도 똑바로 못해서 다른 언어를 권장하는데 적어도 메모리 관련에 대해 공부하기 싫으면 이쪽으로 공부하지 말도록.
- ㄴ몆기가짜리 프로그램 일생동안 손도 안대본 새끼의 지랄이다.큰 프로그램 만질수록 0.1초가 1초가 되어가고 10초가 되어간다.우리 게이는 10초랑 100초가 같노?
- ㄴ C언어 쓰다보면 은근좋다
그리고 C언어가 확장성이 정말 크다보니 개같은 함정들이 한가득(그리고 알고보면 OOP라 하기도 뭣하긴 하다.)이긴 해도 OOP같은 걸 구현하기도 했다. 메모리 관련 공격도 짝퉁 OOP 구현처럼 충분히 패치하는 방법 있음. (물론 어디까지나 '짭'인걸 잊진 말자.)
//OOP : Object Oriented Programming (객체 지향 프로그래밍)
입문자에게 도움될만한 팁[편집]
자신이 정말 언어쪽에 소질이 있거나 머리가 비상하지않으면 노오오오오오오력 할수밖에 없다
노오오오오오력과 진짜 주위에좀 물어봐라 독학하다가 게임만 처하지말고 좀 븅신들아
진짜 초보자용 주의사항[편집]
만약 본인이 프로그래밍 처음 시작하는 사람인데 주변 사람이나 인터넷으로부터 각종 얘기를 듣고 그걸 바탕으로 첫 언어를 c로 선택했다면 웬만해선 python이나 java 등의 언어로 바꾸길 권한다.
진지하게 프로그래머로 살아갈 생각이라면 언젠가는 c를 반드시 배워야 되는게 맞다. 하지만 윈도우에 비주얼 스튜디오 깔고 헬로월드 구구단 별찍기 정도로만 하게될 초심자 입장에서 c는 그저 좆같이 불편하고 세그멘테이션 폴트나 내뱉는 고물일 뿐이다.
c가 강력한 언어일 수 있는건 포인터를 활용해 고수준 언어 중에서 비교적 자유롭게 하드웨어를 제어할 수 있다는 점이다. 그래서 임베디드, 커널 분야에서는 c가 아직도 대세다. 하지만 이건 자신이 시스템 아키텍쳐에 어느정도 이해를 갖췄을때 가능한 얘기고, 초보자들에게는 하드웨어 제어라는 강점이 좆대로 작동해서 버그를 생산한다는 단점으로만 보일 뿐이다.
io도 몰라서 stdio.h를 studio.h로 잘못쓰는 사람이 태반인데 그럴 수 있을리가 만무하다. 거기에 포인터, 배열, 동적할당까지 얘기하면... 반도 못가서 사람들 대부분 나가떨어진다.
자동완성이 없던 시대에 나온 물건이라 죄다 약자 투성이인 것도 이해하기 어렵게 만드는 데 한몫한다. stdio가 그 약자의 무수한 흔적들 중 하나임. 함수나 예약어 대부분이 축약어다.
요약하자면 c를 배우고 싶다면 그 전에 하드웨어와 시스템에 대해 지식을 어느정도 쌓고 오거나 공부를 병행할것
이 외에도 몇가지 이유때문에 c는 갈수록 입문용 언어로는 권장하지 않는 추세다. 국내외 유수의 컴공과에서도 신입생 입문용 언어를 python java 등으로 바꾸는게 대세다. it는 대세를 빨리 캐치하고 거기에 따라가는 것이 중요하다. 여러분들도 어지간해서는 대세를 따르는게 좋을것이다. 특히 초심자일수록.
자꾸 c가 깊게 안파면 기초니까 좋다는 주장이 나오는데, 그렇게 배울거면 OOP가 적용된 타 언어로 입문하는게 낫다. 순서지향으로 머리가 굳어버리면 고치기 존나 힘들다.
가끔 실수하는 것들[편집]
가장 큰 실수는 좋은 gcc를 두고 귀찮은 VC를 쓴다는 것이다 니네들 존나 프로젝트 개쩔게 하는 것도 아니잖아 걍 터미널이나 cmd에서 컴파일하자
ㄴ그건 더 귀찮잖아
ㄴvim으로 코드짜고 gcc로 컴파일하고 gdb로 디버깅하는게 어떻게 더 좋냐 븅신아
처음 배우는 애들이 가끔씩 Win32 Console Application 항목이 아닌 Win32 Project를 누르는 경우가 있다.
도스로 예제를 작성하거나 만든다면 Win32 Console Application을 눌러라 안그러면 오류난다
딱히 실수는 아닌데 웬만하면 Empty Project누르고 하는게 좋다 안그러면 미리 만들어진 프로젝트가 생성되는데
책에서는 대체로 Empty Project를 체크후 예제를 적는데 체크 안하고 할 경우 헷갈려한다.
- 부디 함수 정의부, 조건문, 반복문 등의 구문에는 세미콜론 찍지마라 특히 반복문은 그렇게하면 오류 안뜬 상태로 블록안의 내용 무시하고 반복한다
- 책 뒷장 먼저 피지마라
- C언어를 제대로 배울거면 .cpp 말고 .c로 확장자 바꿔라
- void main() 안쓰길 바란다 나중에 교수한테 까일지도 모른다 (ISO 9899:1999 표준안 참고)
- 문자열 대입한답시고 char[] 형 변수에 "내용"같은 리터럴 상수를 대입하거나 다른 char[]형 변수를 대입하지마라 (리터럴 상수 대입은 초기화만 가능)
string.h 헤더파일 추가하고 strcpy 함수 써라
- 문자열 비교는 if(var == "어쩌고") 가 아니라 if(strcmp(var,"어쩌고") == 0) 로 해야한다 안그러면 주소 비교하는거다.
(배열변수의 이름은 배열의 시작주소를 나타낸다는 것을 잊지말길)
위의 내용은 if(*var == *"어쩌고")로 비교할 수도 있다.
- 그냥 씨발아 자바 배워
ㄴ 자바 존나느려
- 전역변수 사용 할꺼면 확장자를 c++로 만들어야 오류가 나지 않는다.
쓸만한 꿀 함수[편집]
컴파일러마다 지원하는 함수가 있고 하지 않는 함수도 있으니 조심해서 쓰길
printf 이런건 적지 않겠다.
scanf (soocanf) 이런것도 적지 않겠다. 물론 이것도 못하는 새끼들이 있더만...
Sleep (); 잠을잔다.
<stdlib.h>
- int atoi(const char *str); // 인자로 넣은 문자열을 숫자로 반환시켜준다. ("111" 넣으면 숫자 111로 반환)
- char *itoa(int value,char *str,int radix); // 숫자를 넣고 문자열 변수를 넣으면 숫자가 문자열로 변환되어 나온다! (radix는 진수) 표준이 아니니까 조심하자.
참고로 toi는 int 형으로 바꾸겠다는 의미의 이름이다. (to int) double이나 float은 약자로 d랑 f를 쓰므로 ~tod나 ~tof로 쓰면 된다.
그렇지만 이것들보다 sscanf나 sprintf를 쓰는게 더 낫다. 저것들은 ANSI 표준이 아니다.
- int rand(); // 의사난수를 반환한다 쓰기전에 srand 함수를 써줄 것.
- void * malloc(size_t size); // size만큼의 공간을 할당하고 반환한다 이걸로 동적 배열을 만들 수 있다. 자매품으로 calloc realloc이 있다.
(free로 마지막에 할당해제 해야한다, VS는 자동으로 해제해준다 그러나 다른 시스템에서는 반드시 쓰자)
(존나 쓰기 어렵다.)
<math.h>
- double pow(double x,double y); // x의 y제곱을 반환한다.
- double sqrt(double x); // 루트 x를 구해줌
삼각함수,삼각함수의 역함수 등이 있으므로 찾아보면 좋음
맛보기[편집]
주의. 이 문서는 심히 진지하여 노잼일 수 있습니다. 이 글은 놀랍게도 디시위키에서 진지를 빨고 있습니다. 노잼이다 싶으시면 여기를 클릭하시어 이 문서를 탈출할 수 있습니다. |
이 문서는 귀찮아서 덜 썼거나 귀차니즘과 관련된 것에 대해 다루... 으으... 기차나.. |
주의! 이 문서를 작성한 새끼는 위키 문법을 모릅니다. 혹시 너도 모르면 디시위키:문법을 참고해서 멀쩡한 문서로 완성해 주세요. |
작성자가 길게 썼다가 한번 날리고 존나 귀찮아졌으니 대충쓴다 진짜 배울 사람은 이거말고 책보는걸 추천한다 교수님 강의 듣거나
개시발 노잼의 연속이다. 진짜 차라리 강의를 들어라. 초반부는 뇌에 똥찬새끼가 아니라면 충분히 할 수 있다.
C언어 강의하는 사람 치고 재밌게 가르쳐주는 사람 드물다.
전처리기[편집]
# 으로 시작한다.
컴파일 하기전 먼저 실행될 구문이라 보면된다.
ex :
#include <stdio.h> /* stdio.h라는 헤더파일을 소스에 포함한다는 뜻이다 헤더파일은 존나 귀찮게 몇백줄 적어야할 소스를 미리 적어두고 추가하는 파일들이다.
근데 시발 이거 쓰지말고 cstdio쓰자.
ㄴ 댕청하다... cstdio나 stdio.h나 차이 없다. 그리고 .h 안붙어 있는 헤더는 C++용이므로 C언어 쓸땐 곱게 이거쓰자.
cstdio를 써도 된다. 허나 기능상의 차이는 없다.
단지 namespace가 다를뿐인데 그것도 C++에서나 생각해야할일 뿐이다.
전세계구급으로 많이 쓸것들은 컴파일러가 알아서 추가한 표준 라이브러리 함수등이 있다 stdio.h도 그중 하나로 표준 입출력함수들이 들어있다.
가끔 몇몇 사람들이 스튜디오나 스트디오라고 읽는데 스탠다드io라 읽거나 스탠다드인풋아웃풋 이라고 읽거나 에스티디아이오라고 읽자 극혐하는 교수들이 있다.
- /
#define FIREEGG 2 // 부랄이 두개 아닌사람에게는 미안하다. 특정 값을 상수로 정의할 수 있는데 예제에서는 FIREEGG라 적으면 컴파일러가 2라고 치환한다고 보면된다.
#pragma once
//소스를 한번만 컴파일하게 해준다. 이건 나중에 언어 배우다보면 왜 필요한지 알듯
#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 붙이고 사용법대로 호출해라
- /
#ifdef #endif //귀찮으니까 대충설명하면 특정 상수가 정의되어 있으면 #endif까지 컴파일하고 아니면 컴파일 하지 않는다.
//ㄴ 미친새끼들 컴공새끼들이라고 ㄴ을 붙이면서도 "//"를 추가하네 극혐이다 시발;; 어느곳에서도 볼 수 없는 주석처리를 여기서는 해놓다니 씹극혐;;
// /* */ 로 내가 바꿨다
함수[편집]
y = x+1 이라고 보자
선언 정의 호출 3가지가 있는데
선언은 반환자료형 함수이름 (변수자료형 변수이름); 으로 할 수 있다.
ex) int Add(int x); // x라는 매개변수로 입력을 받고 Add앞에 붙은 int는 Add라는 함수가 정수형으로 반환할 것이란걸 알려준다.
int는 자료형중 하나로 정수형을 나타낸다고 보면된다 (integer의 줄임말)
주의 : 함수이름이 main 일 경우 프로그램의 시작점이 되며 지금 설명할 것은 사용자 정의 함수이므로 main함수와는 다르다
정의는 선언에 세미콜론 때고 중괄호 만들어주고 할일을 넣으면된다.
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 )
이런식으로 보관해두면 나중에 더하거나 빼거나 나누거나 곱하거나 별 지랄을 부릴 수 있다.
반대로 상수가 있는데 이건 변수처럼 지랄을 부릴 수 없다.
#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를 써야 되기 때문이다.
주석[편집]
내가 소스에 // 치고 글쓴걸 봤을텐데 실제로 소스에다가 그냥 말을 써재끼면 당연히 오류를 뿜겠지?
근데 나는 이 소스를 누구에게 보여주거나 과제 제출용 혹은 배포해야 하는데 소스 설명은 해야하잖아
그럴때 쓰는게 주석이야 //를 붙이고 뒤에 글을 쓰면 컴파일러는 그 글을 무시하고 컴파일 한다
//는 행 단위 주석이라고 하는데 //친 시점에서 그 행은 전부 주석처리 되는거지.
근데 주석을 여러개 쓰려고할려면 예를들어
//존나
//귀찮다
//밥먹을까
이렇게 쓰면 일일이 // 치기도 귀찮잖아?
그러니까 /* */ 사이에 글을 적으면 그부분은 주석처리가 된다 이걸 블록 단위 주석이라고 하는데 어떻게 부르건 맘대로
/* 존나
귀찮다
시발
*/
주석처리는 소스와는 상관없이 그냥 소스에대해 설명하기 위해 적어두는 메모 같은 개념이야 위에서 내가 조금 대충 설명했나 미안
ㄴ/* 원래 C에서의 주석은 /* */ 였다 그런데 C99에서 //를 C++에서 가져다 추가한것이다. */
연산자[편집]
가감승제, 조건, 비교, 비트 연산자 등이 존재함
int var; // 이런 변수가 있다고 하면.
var = 30 ; // 대입 연산자 의외로 수학하는 사람이 약간 헷갈린다더라. var이라는 공간안에 30을 대입한 것
var = var + 20; // var의 값과 20을 더하고 대입했다. 연산자에도 순서가 있는데 대입 연산자가 제일 순위가 낮아 마지막에 연산된다 보면된다.
var += 20; // 복합 대입 연산자라고 한다 방금 전 했던 구문을 줄인 것으로 더하고 대입하는 작업은 똑같다.
위와 같은 방법으로 - / * %도 가능하니 심심하면 해보길 바람.
복합 대입 연산자는 종류가 더 있다.
<<= >>= &= ^= |=
<<= >>= 는 시프트 복합 대입연산자 인데 비트 배우고나서 배워라
var <<= n 일경우 n만큼 비트를 왼쪽으로 이동시킨다 >>=는 오른쪽
&= 와 ^=, |= 는 각각 And 연산 후 복합대입 , XOR 연산 후 복합대입 OR연산 후 복합대입
비트 연산자에 대입 연산자 붙인거라 생각해라
조건 연산자는 >, <, >=, <=, ==, != 가 존재한다 부등호를 모른다면 프로그래밍보단 기본 교육부터 받는걸 추천한다.
==는 서로 같음 (수학에서의 = 가 이것이다.)
!=는 서로 다름
이 연산자는 참일경우 1을 반환한다. (거짓은 0)
참고로 삼항 연산자도 조건 연산자라고 한다.
조건 ? 참의경우 : 거짓의 경우
이런식으로 구성할 수 있다. (ex : var > 30 ? printf("30보다 큼") : printf("30과 같거나 자금"); )
/*
* ? : 연산자는 반환값이 있는 점에서 if와 다르다(삼항연산자는 표현식, if는 문장) * foo = bar > 30 ? 5 : 3; * 이런식으로 변수에 값을 묶어주는게 아니라면 그냥 if쓰는게 낫다(가독성) */
많은 사람들이 모르는 건데 C99부터 iso646.h을 인클루드 하면 !=를 not_eq ||를 or &&를 and, !을 not, |를 bitor, &을 bitand 등으로도 쓸 수 있다.
하지만 ==은 그 헤더파일에 정의되어 있지 않다.
비트 연산자를 위에서 잠깐 언급했는데 자세히 얘기한다
너가 컴퓨터로 보고있는 숫자는 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
----
0101 // 이해가 됐는지는 모르겠는데 위와 아래 자리가 둘다 1이므로 1이고 나머지는 둘다 1이 아니므로 0이다.
| 는 OR 연산자이며 이 연산자는 AND와는 다르게 두개의 비트중 하나라도 1이면 1이되고 아니면 0이 된다.
5 | 13 으로 다시 예를 들자면
0101
1101
----
1101 // 13이 되는거시다!
^ 는 XOR 연산자인데 꽤나 특이한 것이 각 비트가 서로 달라야 1이되고 같으면 참이된다 즉 서로 배타적이여야 참인데 그래서 배타적 논리합 이라고 한다.
5 ^ 13 으로 다시 예를 들자면
0101
1101
----
1000 // 8이 되었다 이해가 가는가?
~ 는 NOT 연산자인데 이 연산자는 0을 1로 1을 0으로 바꿔버린다.
~5 할경우
0101
----
1010
알아둬야 할 것이 있는데 만약 일반 정수를 ~해서 바꿀경우 음수가 되는데 왜냐하면 정수의 맨 앞비트(MSB)는 부호비트로 부호를 결정하는 비트이다.
2진수로 표현된 음수는 바로 알아보기는 힘드므로 2의 보수를 취해 그 크기를 알수 있다 (2의 보수 : 모든비트 반전후 +1)
1010이 결과라고 했지만 실제 프로그램 내부 정수는 4바이트므로 11111111 11111111 11111111 11111010 으로 된다.
참고로 여기서 1010에 +1을 해줄경우 원래 숫자 ( 5 )를 음수로 바꾼 값이 나온다 (var = 5 , ~var+1 == -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("Hello\n"); // 부들부들.. 왜 요즘 애들은 이 좋은 puts 함수를 모르는 거냐? puts("Hello");
//puts가르쳐놓고 변수출력하라할거냐? 문자열만 출력한답시고 puts랑 printf랑 번갈아가면서 쓰면 맛보기로 보는데 참 좋아라하겠다
}
이러한데 제어문은 실행할 명령이 1줄 일경우 굳이 중괄호를 치지 않아도 된다.
if( var > 5 && var < 10 )
printf("Hello\n");
이렇게 조건을 걸어 참일 경우 특정 명령을 실행할 수 있다.
그런데 만약 다른 예외의 경우가 있다고 한다면 if 문을 또 써야할텐데 그럴때는
else if 문을 사용할 수 있다
if문과 사용방법은 같지만 if문 뒤에 와야한다.
예를들어 var 이 10과 같거나 크고 15보다 작을 때 Welcome 을 출력한다면
if( var > 5 && var < 10 )
printf("Hello\n");
else if( var >= 10 && var < 15 )
printf("Welcome\n");
이처럼 예외를 만들어 줄 수 있다.
다만 두개의 조건이 거짓일때 Bye라고 해줘야한다면 일일히 조건걸기 매우 힘들것이다.
else문을 사용하여 쉽게 만들 수 있는데 else문은 if, else if 에서 나온 조건들이 전부 거짓일경우 중괄호 안 혹은 한줄의 경우 바로 밑 명령을 실행한다.
if( var > 5 && var < 10 )
printf("Hello\n");
else if( var >= 10 && var < 15 )
printf("Welcome\n");
else
printf("Bye\n");
위에서도 말했지만, 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("Hello, World!\n"); 를 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("Hello, World!\n");
}
자 한번 정리해서 보자
초기식 : 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("Hello, World!\n")); 이렇게써도 된다 다만 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("Hello, World!\n");
}
이렇게 무한루프에서 빠져나올 수 있다.
break와 자매품으로 continue가 있는데 이건 break처럼 반복문을 한번 나오고 끝이 아니라 밑의 내용을 실행하지 않고 바로 다음 반복을 실행한다.
이게 뭔말이냐 하면 만약 짝수 (2의 배수) 일 경우 Hello, World!를 출력을 못하게 하려 한다면
int var;
for(var = 0;;var++)
{
if(var % 2 == 0 && var != 0)
continue;
printf("Hello, World!\n");
}
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 한다음
int *grade = (int*) malloc( sizeof(int) * students);
하면 students 변수의 값만큼 int형 변수를 만들 수 있다.
위 malloc함수는 바이트 수만큼 메모리를 할당하여 주소를 반환해주는데 이 때 반환해주는 자료형이 void* 이므로 캐스팅연산자 즉 (int*)를 앞에 적어 준다.
grade 옆에랑 (int*) 에 붙은 *가 뭔지 모를텐데 그냥 해당 자료형을 가르키는 주소를 보관하는 자료형이라 보면된다.
약간 비약을 섞어 말하자면 *가 안붙으면 값을 보관하고 *가 붙으면 주소를 보관한다고 보면 된다.
자매품으로 ** 도 있는데 이건 주소를 보관하는 변수의 주소를 보관하는 변수다.
*의 갯수에 따라 n차 포인터라고 한다.
포인터 항목에서 다시 설명하겠다.
아무튼 저렇게 선언하고 평소대로 grade[0] = 30; 이런식으로 쓰면된다.
배열이 중요한 이유는 선언의 간편함도 있지만 관리가 매우 유용하기 때문인데
예를들어 배열 없이 학생성적을 전부 출력하려고 한다면
printf("1번 학생 점수 : %d \n",grade1);
printf("2번 학생 점수 : %d \n",grade2);
...
printf("30번 학생 점수 : %d \n",grade30);
같은 개떡같은 상황인데 개쩌는 배열은 다 좆까고 반복문 사용해 2줄이면 된다.
int i;
for(i=0;i<30;i++)
printf("%d번 학생 점수 : %d \n",i+1,grade[i]);
ㄴ TMI지만 1줄로도 된다. for(int i=0; i<30; i++) printf("%d번 학생 점수 : %d \n", i+1,grade[i]);
반복문을 사용해 i를 증감시키면서 printf문을 30번 반복하고 grade 첨자 안에 증감되는 i를 넣어 0부터 29까지 전부 접근해서 출력할 수 있다.
아까 첨자에 변수넣는거 안된다고 하지않았나 하면 다시봐라 변수 선언시에만 상수로 만드는거다.
그리고 그 배열을 free함수로 할당해준 메모리를 해제 해줘야한다. ( 하는법은 free(grade); )
이 밖에 특이한점은 char 자료형의 배열인데. char이 문자형 이였지만 배열일 경우에는 문자열 이라고 한다.
문자형과 문자열의 구분은 '와 ' "와 " 인데 printf 함수 안에 문자열을 넣은걸 보면 쉽게 알 수 있다.
char ch = 'a';
char string[10] = "abcdefghi";
이렇게 차이가 존재한다.
문자열을 선언 할 때는 "문자열" 이렇게 적어서 초기화 할 수 있는데.
정작 대입할때는 안된다 예를 들자면
char string[10] = "hello"; // 이건 된다.
string = "bye"; // 이건 에러난다.
그리고 주의할 점이 있는데 문자열은 맨뒤에 \0 즉 널문자가 붙는다. '\0' == (char)0
컴퓨터의 입장에서 C의 문자열은 단지 메모리에 쭉 늘어선 숫자들일 뿐이기 때문이다. 문자열 관련 함수는 자신이 처리해야할 문자열과 건드려서는 안 되는 다른 데이터를 구분해 줄 표식이 필요한 것이다.
아무튼 널문자가 붙으므로 한 자리를 비워둬야한다. 예를들면 첨자에 10넣어서 배열 선언하면 문자열은 9개의 문자만 사용해야한다.
참고로 한글은 2byte이므로 9개가 아니라 4개밖에 못쓴다. 알파벳은 1byte 맞는데 한글이나 특수기호는 아니다.
위에 사용함으로써 얻는 장점들을 꼽자면
1. 다수의 변수 선언이 매우 용이하다.
2. 같은 용도의 많은 변수 관리가 매우 편해진다.
3. 위의 2가지를 해결함으로써 반복적 코딩을 줄이고 동적 배열로 메모리의 효율적 사용도 가능해진다.
배열은 arr[첨자] 로 각 첨자에 있는 변수에 대한 접근이 가능하다 설명했는데
이러한 접근도 가능하다.
*(arr+0) = 3;
위 구문은 arr[0] = 3; 과 결과적으로 똑같으며
위의 구문을 이제부터 알 수 있도록 C 입문자들이 그렇게 혐오한다는 포인터에 대한 설명을 하겠다.
맛보기2[편집]
왠지 배열 다음으로 만들면 오류나길래 새로 만든다.
포인터[편집]
이걸 만든 새끼는 진짜 병신 새끼입니다! 도대체 무슨 생각으로 이딴 걸 처만들었는지 모르겠습니다. 이 새끼들은 자기가 만든 것으로부터 직접 고통 받게 해야 합니다! |
포인터는 그 부분만해서 책으로 내놓기도 하고 그만큼 지금까지 배웠던 것 보다는 높은 이해력을 요구한다.
따라서 글을 쓰고있는 작성자도 비약적인 내용을 담을 수 있으며 잘못된 내용이 나올 수 있음을 경고한다.
그러므로 잘못된 부분이 있다면 필히 지적해주길 바람
포인터는 C언어의 장점이라 할 수도 있으며, 또한 단점이라고 할 수도 있다.
그 이유는 저수준 접근과 입문자의 인간적 사고를 지녔던 일상과는 달리 컴퓨터 입장에서 봐야하기도 하는 이유 때문이기도 하다.
포인터는 간단하게 설명하자면 주소에 직접 접근하는 것을 일컫는데, 주소를 가리킨다는 의미에서 포인터라 하는 사람도 있다.
여기서 주소란 위에서 설명한 변수의 진짜 이름이라고도 할 수 있는데, 실질적인 메모리 공간의 위치를 주소라 한다.
주소는 4바이트 정수로 표시하는데 (정확히 하자면 unsigned int 즉 부호없는 정수) 대부분 16진수로 표기한다.
예를들어 내가 변수를 선언하였고 이름을 var 이라고 정했다 ( ex - int var; )
변수는 값을 저장하기 위한 공간이라고 할 수 있는데, 이름을 정하는 이유는 그 공간의 진짜 주소인 메모리 주소를 일일이 기억하기 어렵기 때문이다.
실제로는 0x00000000 이런식의 주소에 저장되어있다. ( 물론 임의로 정한거고 실제는 안 이렇다.
( 절대적인건 아니고 다를 수 있다 codingground 사이트에서는 6바이트의 주소로 나오더라 ) ㄴ 아키텍쳐마다 다름 x86 이면 32bit, x86-64면 64bit 이런식
이걸로 이해가 안가는 사람들을 위해 내가 이해했던 방식으로 설명해준다.
예를 들어 니이름이 강동원이라고치자, 그리고 이글 읽는 너는 분명 급식충이니까 대충 디시중학교 2학년 18반 18번이라고 치자.
그리고 너는 헬조선 학생이라서 맨날천날 학교에 들러붙어서 사는 하이퍼 급식충이다.
그러면 선생님들이 너를 부를때 '야, 강동원이, 느그아부지 뭐하시노'라면서 부를 수도 있지만, '2학년 18반 18번 나와!'라면서 너를 간접적으로 부를수도 있다는 말이다.
그러니까
int name = 강동원 //만약에 문자열을 왜 int형으로 저장하냐는 새끼있으면 머가리 조져버린다.
이라고 선언했을때, 컴퓨터는 자동으로 니놈을 메모리 어딘가의 주소로 보내버린다.
보통은 간지나게 0x000A3같은 16진수로 표현되는데 이 주소에 접근하는거랑 2학년 18반 18번이랑 같은 표현이라는거다.
존나 추상적으로 설명해서 미안하지만, 그건 내가 글을 못써서 그렇다. 미안ㅠ
포인터 변수란것은 그 주소를 보관함으로써 가리키는 변수라고 하는데 간단하게 포인터 변수는 주소를 보관한다고 보면된다.
포인터 변수를 선언하려면 자료형과 이름 사이에 *를 붙이면 되는데.
int * ptr;
이라고 선언 가능하다 그리고 이것을 포인터 변수라 하고 좀더 풀어쓰자면
'정수형 변수를 가리키는 포인터 변수 ptr' 이라고 할 수 있다.
*이 붙은 모든 포인터 변수의 크기는 보통 4/8byte이며 이유는 주소 크기가 그렇기기 때문이다 cpu 아키텍쳐의 주소 크기를 따라감( double * ptr 도 4byte 라는 얘기)
포인터 변수를 만들었으니 무언가 주소를 보관하고자 한다면
int var;
int * ptr = &var;
하면 var 변수의 주소 (ex - 0x00000000)를 ptr이 갖게 되며 이를 가리켰다 라고 표현한다.
& 연산자는 옆에 붙은 변수의 주소를 반환한다 (&var = 0x00000000)
그니까 한마디로 ptr에 0x00000000 를 대입한셈!
이제 주소를 갖게 되었으니 한번 그 주소에 접근해보자
int var;
int *ptr = &var;
*ptr = 3;
printf("%d",var);
출력결과는 3이 나올것이다.
*ptr = 3; 이 구문은 ptr변수가 갖고있는 주소를 가리키라는 연산자이다.
따라서 갖고있는 주소는 var 변수의 주소이므로 var 변수에 3 대입하는것과 같다!
그러므로 var 변수를 출력하면 3이 나오게 되는 것이다.
왜 쓰는지 궁금할 수도 있는데 이것을 사용하는 이유는 말그대로 변수가 갖고있는 실주소에 접근할 수 있기 때문이다.
(다른 이유도 있지만 쉽게 예를 들기 위한 이유이다.)
흔히 포인터에 관해 예를들때 Swap 함수를 만들어보는 예제를 많이들 사용하는데
변수 두개의 값을 바꾸는 Swap 함수를 만들어 본다고 하자.
void Swap(int a,int b)
{
int temp = a;
a = b;
b = temp;
}
이렇게 함수에 인자로 두 변수를 받고 temp에 a변수의 값을 보관하고 a에는 b를 넣고 b에는 a를 보관한
temp를 넣는다.
이렇게 하고 main 함수에서 Swap(var1,var2); 로 호출 했다고 하고
var1 var2를 출력해보면 전혀 안바뀌었는데 이런 이유는 함수 설명에서 알 수 있는데
함수의 인자는 값 전달이지 변수 그 자체를 전달하는 것이 아니다
함수 정의에서 인자로된 a와 b 변수는 그저 함수의 인자 전달을 위해 만들어진 가짜 변수 이며
매개변수 이기도 하다. (매개변수 뜻을 알면 알 수 있는데 말그대로 매개하는 변수이다.)
이런 이유 때문에 함수 정의부에서 적은 int a,int b 를 매개변수라 하고
실제로 넘겨준 var1,var2 변수를 인자라고 단어를 구분짓는 이유기도 하다.
아무튼 이러한 값만 전달하는 특성에 의해 값을 바꾸는 함수 Swap이 제대로 되지 않는다.
여기서 주소에 접근하는 포인터가 있다면 상황은 달라지는데
void Swap(int *a,int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
라고하고 호출을 Swap(&var1,&var2); 이렇게 하면 이제 값이 바뀐다!
이유는 잘 이해 했다면 알 수 있는데 여기서 넘겨받은건 값이 아니라 주소 이며 ( &var1,&var2 )
함수 내부에서도 *연산자로 a와 b에 보관돈 주소에 접근(가리킴)하여 서로 값을 바꾸었으므로
실제로 그 주소의 공간을 갖고있는 변수인 var1과 var2의 값이 바뀐것이다.
포인터 연산[편집]
디시위키 오랜만에 와서 문서 추가하니까 왜이러냐;; 원래 문서도 미리보기하면 오류나냐ㅋㅋㅋㅋㅋ
포인터는 아무 생각없이 일반 증감,가감 연산자를 쓸 경우 생각했던거와 다른 결과를 도출할 수 있는데,
여기서는 간단히 설명하겠다
포인터에 관련된 연산자는 아까 본듯이 * 와 & 가 있었고
++나 --같은 연산자를 사용할 수 있는데 의미가 다르다.
간단하게 생각하자면 포인터 변수는 주소를 저장하는데 더하거나 뺄경우 주소의 증감 및 가감이 일어난다.
아까의 예제를 다시보자.
int var = 0;
int * ptr = &var;
이경우 var의 주소를 알기쉽게 0x00000000 이라고 할때
ptr이라는 포인터 변수로 var에 접근하여 값을 1 올리고싶다.
이 경우 (*ptr)++; 를 적으면 *연산자로 ptr이 가진 주소에 접근하여 ++연산자로 1 증감한다
ptr은 var의 주소를 가지고 있었으므로 var의 값은 최종적으로 1이 된다.
근데 엥? ptr++; 로 적어도 되는 각 아니냐? 해서 적었을경우
ptr은 값을 가지고 있는게 아니라 주소를 가지고 있기에 주소가 4 증가한다.
4 증가하는 이유는 포인터 변수의 자료형 바이트 크기에 영향을 받기 때문이다 ( int형은 4바이트 )
왜 4바이트냐 하면 배열같은 동일 자료형일 경우 다음 원소로 쉽게 접근하기 위해라고 생각하는데 글쎄 나도 진짜는 아몰랑 아는 사람있으면 적어줘
ㄴ맞다. 포인터가 단순한 주소값 그 이상의 의미를 갖게 되는 핵심 개념이다.
ㄴ메모리 주소 자체가 4바이트(32비트)이며 이는 시스템에 따라 달라짐
가감도 이와같이 1을 뺄경우 4씩 내려가는데
n을 더하거나 뺀다고 하면 n*sizeof(int) 이런식으로 깎인다고 생각하면 된다. (int형이 아닐경우 자료형의 크기를 맞게 고쳐주고 곱하면 맞다)
근데 포인터 변수에 * 나 / 를 적진 마라 C2296오류 난다
배열을 설명할때 arr[0] 이런식으로 대괄호 안에 숫자를 넣어 해당 원소에 접근했었는데
배열의 이름이 시작주소라는 점을 이용해 포인터를 이용해 각 원소에 접근 할 수 있다.
int arr[10];
for(int i=0;i<10;i++)
{
arr[i] = i;
}
가 아닌
int arr[10];
for(int i=0;i<10;i++)
{
*(arr+i) = i;
}
이 가능하단 소리 ㅎㅎ
구조체[편집]
구조체는 쉽게 말하면 너가 원하는 새로운 자료형을 만드는 것 과 같다고 보면된다.
예를들어 학생의 이름과 수학,과학,영어 점수를 저장해야 할 때,
단순히 구조체를 모르는 상황에선 이런식으로 변수를 선언할 것이다.
<source lang="cpp">
- include <stdio.h>
- define STUDENTS 5
int main() { char s_name[STUDENTS][12]; int s_math[STUDENTS]; int s_science[STUDENTS]; int s_english[STUDENTS];
for (int i = 0; i<STUDENTS; i++) { printf("%d번의 학생의 이름은? : ",(i+1)); scanf("%s", s_name[i]);
printf("%s 학생의 수학점수는? : ",s_name[i]);
scanf("%d", &s_math[i]);
printf("%s 학생의 과학점수는? : ",s_name[i]);
scanf("%d", &s_science[i]);
printf("%s 학생의 영어점수는? : ",s_name[i]);
scanf("%d", &s_english[i]); } for (int i = 0; i<STUDENTS; i++) { printf("%s\n", s_name[i]);
printf("수학 : %d\n",s_math[i]); printf("과학 : %d\n",s_science[i]); printf("영어 : %d\n",s_english[i]);
} return 0;
} </source>
구조체를 안쓴상태에서 간단히 짜보았을때 이런 형태를 띌 것이다.
간단한 예제이므로 단순히 입력받고 출력할 뿐인 형태지만
변수 배열 4개를 선언하고 각각에 집어넣는 식이다.
배열첨자를 학생번호로 사용하여 접근할 수 있는데
구조체를 사용하면 좀 더 간결하고 관련된 변수들을 모아 하나의 자료형을 만들어준다
예를들어 위의 예제를 구조체로 만든다면
<source lang="cpp">
- include <stdio.h>
- define STUDENTS 5
typedef struct _STUDENT { char name[12]; int math; int science; int english; } Student;
int main() { Student students[STUDENTS];
for (int i = 0; i<STUDENTS; i++) { printf("%d번의 학생의 이름은? : ", (i + 1)); scanf("%s", students[i].name); printf("%s 학생의 수학점수는? : ", students[i].name); scanf("%d", &students[i].math); printf("%s 학생의 과학점수는? : ", students[i].name); scanf("%d", &students[i].science); printf("%s 학생의 영어점수는? : ", students[i].name); scanf("%d", &students[i].english); } for (int i = 0; i<STUDENTS; i++) { printf("%s\n", students[i].name); printf("수학 : %d\n", students[i].math); printf("과학 : %d\n", students[i].science); printf("영어 : %d\n", students[i].english); } return 0;
} </source>
이렇게 할 수 있다
뭔소린지 몰라도 괜찮다 일단 밑의 설명을 보고 다시 위 예제를 보면된다.
일단 단순히 아까 4개의 배열이 students 라는 하나의 배열로 묶여진 것만 확인하면 된다.
구조체는 여러 변수들을 하나로 모아 새로운 자료형을 만들 수 있는데
그냥 구조체 자료형이라고 해도 되지만 몇몇 사람들은 사용자 정의 자료형이라고도 부른다.
선언 방법은 struct 키워드로 시작하는데
<source lang="cpp"> struct 구조체이름 {
저장할 변수;
}; </source>
로 만들 수 있다
이렇게 만든 구조체로 변수 선언을 할때는
struct 구조체이름 변수이름;
원래는 이렇게 선언하고 struct를 붙이는게 싫다면 구조체 선언시 typedef를 쓰면 되는데
VC컴파일러로 cpp확장자 써놓고 걍 struct 무시하고 쓰더라
요즘 표준은 모르겠는데 일단 struct 안붙이면 에러나는 컴파일러도 있으니 확실히 명시해주는편이 좋다.
참고로 typedef란 자료형의 이름을 새로 정의할 수 있다.
(새로 정의한다고 기존 이름을 지울 수 있는건 당연히 아니다)
typedef 기존자료형이름 새로운이름
이렇게 쓴다면 새로운 자료형 이름으로 변수를 선언할 수 있다.
<source lang="cpp">
- include <stdio.h>
typedef int Google;
int main() { Google fantasy=3; return 0;
} </source>
int를 Google이라는 이름으로 새로 정의하고
변수를 하나 선언하고 3을 대입했다
이때 Google은 int형의 새로운 이름이니 정수대입이 가능한것이다.
define 전처리기 처럼 단순히 치환하는 방식인지는 따져본건 아니니 자세한건 못알려준다.
다만 typedef는 전처리문이 아니므로 치환은 아닐거라고 본다.
그리고 전처리문이 아니며, 함수 블록 내에서도 쓸 수 있으며 순서에 영향을 받는다.
<source lang="cpp">
- include <stdio.h>
int main() { Google fantasy=3; // 오류! typedef int Google; Google fantasy1 = 2; // 오류 아님 return 0;
} </source>
이렇게 문장의 위치에 따라 문제가 생길수도 있다.
근데 보통은 그냥 전처리문 밑에 적는다.
돌아가서 구조체에 대한 설명을 계속하자면 구조체안에 선언한 변수들은 . 으로 접근할 수 있다.
소스로 보자면
<source lang="cpp">
- include <stdio.h>
typedef struct _MAN { int hungry; float temperature; } Man;
int main() { Man who; who.temperature = 36.5; return 0; } </source>
위의 예제에서는 _MAN이라는 구조체를 만들고 hungry 변수와 temperature 변수를 기술하고
typedef로 Man이라는 이름으로 바꿨다.
main함수에서 Man 구조체 자료형의 변수인 who를 선언하고
who 에 . 을 붙여 temperature 라는 아까 기술한 변수이름을 적어 해당 변수에 접근하고 있다.
마찬가지로 who.hungry = 100; 이라고 쓸 수 도 있다.
참고로 구조체는 C++에 가서도 사용이 가능하나 클래스를 쓰기에 그리 많이 사용되진 않는다.
공용체[편집]
공용체란 단어의 의미를 생각하면 쉽게 알듯이
다른 자료형의 변수들과 메모리 영역을 공유한다.
뭔 지랄맞은 소리냐 하면,
예를들어 변수 3개가 선언된 구조체는 해당 변수의 자료형을 토대로 3개의 구분된 메모리 공간을 할당한다.
허나 공용체는 3개의 변수를 선언했을 때 제일 큰 자료형의 크기만큼 1개의 메모리 공간할당이 된후 그 메모리 공간을 3개의 변수가 같이 쓴다.
구조체와 쓰는법은 흡사하다.
#include <stdio.h> struct st { char sc; int si; double sd; }; union un { char uc; int ui; double ud; }; int main() { struct st s; union un u; printf("구조체 크기 : %d, 공용체 크기 : %d \n",sizeof(s),sizeof(u)); printf("sc=%p si=%p sd=%p\n",&s.sc,&s.si,&s.sd); printf("uc=%p ui=%p ud=%p\n",&u.uc,&u.ui,&u.ud); } 실행 결과 구조체 크기 : 16, 공용체 크기 : 8 sc=0012FF70 si=0012FF74 sd=0012FF78 uc=0012FF68 ui=0012FF68 ud=0012FF68
출처 : 제대로 배우는 C언어 프로그래밍
이해가 쉽도록 예제를 찾아 가져왔다.
구조체와 공용체 변수를 만들고, 크기와 해당 변수들의 주소를 반환하는 것을 출력하는 예제이다.
여기서 눈여겨 볼 점은 구조체 크기는 단순히 생각하면 char, int, double 자료형의 변수 3개가 있으니 크기가 13 아닌가 할 수도 있지만,
Struct Alignment라는 Visual C/C++의 내부 기능에 의해 16바이트로 맞춰진 것이니 그리 상관하지 않아도 좋다.
(프로세스 성능 저하 방지, 좀더 따지자면
해당 변수에 접근할 때 변수가 메모리상의 2의 n승 단위의 값에 위치한 메모리에 있으면 효율적으로 메모리를 읽을 수 있기에 사용하는 것이다)
(사실 좆도 몰라도 보통은 상관 안하더라)
아무튼 공용체의 크기는 8이라는 점이다 이는 제일 큰 자료형의 크기를 가진 double형의 변수가 있기에 8로 만들어진 것이다
그리고 주소도 구조체는 각 변수의 주소가 나눠져 있는데 비해,
공용체는 주소가 나눠지지 않고 하나의 시작주소로 시작한다.
이걸로 암호화하거나 몇몇 알고리즘에 이용할 수 있다.
근데 난 게임개발 하면서 과제를 하려든 대회를 나가든 뭐하든 별로 안써봤다.
내가 병신인지 원래 게임에서 사용빈도가 높지 않은건지는 글쎄~
가변인자[편집]
printf 함수를 쓰다보면 요녀석 인자가 여러개 들어가는게 신통방통하네 한 경우가 있거나
나도 이런 함수 만들고 싶다 라고 생각하는 때가 있다.
도움이 될 것같아 이걸 먼저 쓰도록 한다.
이러한 가변인자를 사용하는 함수를 만들려면 ellpsis를 사용해야 한다 ... <- 요거 점3개가 ellpsis(생략 부호) 이다
그리고 stdarg 헤더파일을 포함해줘야 한다.
개귀차나서 간단히 쓰는법만 설명한다
<source lang="cpp">
- include <stdio.h>
- include <stdarg.h> // stdarg 헤더파일을 포함해준다.
void fun(int a, ...); // 여기서 ellpsis 즉 생략부호를 넣어준다.
int main(int argc, char *argv[]){
fun(1, 10); // 인자는 여러개
fun(2, 10,20); // 넣어줘도 된다. 대신 맨 앞 인자는 뒷 인자들의 갯수를 적어줘야한다.
return 0;
}
void fun(int a, ...){
va_list vl; // vl은 ...에 들어간 인자들에 접근하기 위해 만든 변수이다. int i = 0;
va_start(vl, a); // va_start는 가변인자를 읽기 시작하는 동시에 몇개까지 읽을 것인가를 설정하는 함수라 보면된다.
for (i = 0; i < a;i++) printf("[%d 번 인자] %d\n",i+1, va_arg(vl, int)); // va_arg에 vl과 int 를 넣어줬는데 눈치깠겠지만 int는 읽을 인자의 자료형이다
va_end(vl); // 끝낸다.
} </source>
사실 더 설명을 써야하는데 너무 졸리니까 그만씀
ㄴ좆같은 C 쓰지말고 C++17로 갈아타라
<source lang="cpp">
- include <iostream>
template<class...T> // 가변 인자 템플릿 void fun(T...arg) {
(std::cout << arg, ...); // C++17 의 fold-expression
}
int main(int argc, char *argv[]){ fun(1, 2, 3, 4, 5, 6, 7, 8); fun(1, 2.3, "asdf"); // 다른 타입들도 가능
return 0;
} </source>