종류 | 설명 | |
\a | Alarm or Beep | bell 울리기 (컴퓨터에 따라 다를 수 있음) |
\b | Backspace | 커서를 이전으로 옮기기 |
\f | Form Feed | 커서를 다음페이지의 시작부분으로 옮기기 |
\n | New Line | 개행 (줄바꿈) <- 제일 많이쓴다! ★ |
\r | Carriage Return | 커서를 지금 라인의 첫번째로 옮김 |
\t | Horizontal Tab | 탭 (그냥 tap 하는거랑 똑같음) |
\v | Vertical Tab | 수직방향으로 탭 (줄바꿈해서, 탭한느낌!) |
\\ | Backlash | \ <- 문자를 출력! |
\’ | Single Quote | ' <- 문자를 출력 |
\” | Double Quote | " <- 문자를 출력 |
\? | Question Mark | ? <- 문자를 출력 |
\ooo | Octal Number | 8진수를 표현하는것 (\o12) |
\xhh | Hexadecimal Number | 16진수를 표현하는것 (\xAB) |
\0 | NULL | NULL표시 |
\e | Escape sequence | It represents the ASCII escape character. |
\s | Space Character | It represents the ASCII space character. |
\d | Delete Character | It represents the ASCII DEL character. |
%d, %i | signed int | 10진수 표현 |
%hhd, %hhi | signed char | |
%hd, %hi | signed short int | |
%ld, %li | signed long int | |
%lld, %lli | signed long long int | |
%u | unsigned int | |
%hhu | unsigned char | |
%hu | unsigned short int | |
%lu | unsigned long int | |
%llu | unsigned long long int | |
%f, %F | float, double | |
%e, %E | float, double | |
%o | unsigned int | 8진수 표현 |
%hho | unsigned char | |
%ho | unsigned short int | |
%lo | unsigned long int | |
%llo | unsigned long long int | |
%x, %X | unsigned int | 16진수 표현 |
%hhx, %hhX | unsigned char | |
%hx, %hhX | unsigned short int | |
%lx, %lX | unsigned long int | |
%llx, %llX | unsigned long long int | |
%a, %A | float, double | |
%c | char | 문자 한개 |
%s | char* | 문자열 (string) |
%p | void* | 포인터 주소 |
%n | 앞에 입력된 문자의 개수 | printf("test%n",&a); -> a에 4가 입력됨 (%n앞에 test 4개의 문자) |
%% | % | % 문자 출력 |
1. scanf("%s", str) : 제일 간단한(?)방법 but 문자열 중간에 띄어쓰기와 같은 공백문자가 있는경우, 거기가 잘려버린다
=> hello world 를 한번에 입력받고 싶어도, hello만 받아옴
1-1. scanf("%[^\n]%*c", str) : 이러면 scanf로도 공백을 포함해서 문자열을 읽을 수 있다. [^\n]이 \n를 만날때까지 문자열을 읽어라는 뜻이고, *c는 문자열에 담을 때 \n는 빼고 담으라는 뜻이된다!
2. fgets(str, sizeof str, stdin) : \n을 만날때까지, 최대 str의 사이즈만큼, stdin을 이용해 입력받음. => 중간에 띄어쓰기가 있어도 크기만 넘지 않으면 잘 받아온다! (문자열의 일부로 \n까지 받아들임 주의!)
2-1. gets(str) : 입력하는 문자열이 str크기보다 커졌을 때, 자동으로 멈추는게 아니라 다음 공간까지 침범한다 == 위험한 상황이므로 fgets를 사용하자!
a. 산술연산
- Bi operators (operands가 두개있는것)
+ | 덧셈 |
- | 뺄셈 |
* | 곱셈 |
/ | 몫 -> float/float인 경우 소수점까지 살림 & int/int인경우 몫만 결과로 냄 |
% | 나머지 (mod) -> float에는 사용 불가능! |
- Uni operators (operand가 1개)
++ | +1 해주기 | prefix (x++) -> x 사용한 다음 값 올려주기 | y = x++ // x : 11, y : 10 |
postfix (++x) -> 값 올려준 다음 x사용하기 | y = ++x // x : 11, y : 11 | ||
-- | -1 해주기 | prefix (x--) -> x사용한 다음 값 내려주기 | y = x-- // x : 9, y : 10 |
postfix (--x) -> 값 내려준 다음 x사용하기 | y = -- x // x : 9, y : 9 |
=> 단독 사용할때는 맘대로 해도 되지만, 할당할 때 쓰려면 주의할것!
★ int b = ++a + a++ + --a; // undefined behavior
c 컴파일러는, 이런식으로 변수의 수정과 사용이 반복되어 있을 때 순서를 보장하기 힘들다고 한다
(컴파일러 최적화, 표현식의 우선순위 결정.. 등에서 차이가 날 수 있다는듯)
C언어에서 아래와 같은 경우에는 순서를 보장할 수 없다
1. 수정, 사용이 하나의 표현식에 있는경우 : 동일한 표현식에서 (위와같이 하나의 식에서) 변수의 수정과 사용이 반복되는 경우, 순서를 보장할 수 없다
2. 컴파일러 최적화 : 컴파일러가 성능 최적화를 위해 맘대로 표현식의 평가순서를 변경할 수 있다.
=> 그러니까 내 머릿속에서는 ++a 다음 a++ 다음 --a 가 평가되어야 된다고 생각하지만,
컴파일러 최적화 등등.. 의 이유로 a++가 먼저 평가될 수 있다는것이다!
=> 즉 순서를 보장하고 싶으면 b = ++a; b+= a++; b+=--a; 이렇게 나눠서 해줘야 한다.
b. 비트연산(bit wise)
주의할점 : 논리연산과 헷갈리지 말것!
& | AND |
| | OR |
^ | XOR |
~ | NOT |
=> "비트" 연산이니까, 해당 변수의 각 비트에 적용시키는것이다 (논리연산아님!!!주의!!!!!!!)
그냥 넣어본 진리표
AND | 0 | 0 | 0 | XOR | 0 | 0 | 0 |
0 | 1 | 0 | 0 | 1 | 1 | ||
1 | 0 | 0 | 1 | 0 | 1 | ||
1 | 1 | 1 | 1 | 1 | 0 | ||
OR | 0 | 0 | 0 | NOT | 0 | 0 | |
0 | 1 | 1 | 1 | ||||
1 | 0 | 1 | 1 | ||||
1 | 1 | 1 |
>> | 오른쪽 쉬프트 | 부호를 유지한다 (제일 왼쪽이 1이었으면, 오른쪽으로 옮기고 남은 빈칸을 1로 채우고, 양수였으면(0) 0으로 채워줌!) ★ CPU에 따라 무조건 0으로 채우는 등, 예상과 다른 결과가 나올 수 있으므로 사용을 지양해야한다. |
ex) x >> 3 // x를 오른쪽을 3비트 쉬프트 하시오 |
2^n으로 나누는것과 같은 효과를 낼 수 있다! (몫만 취함) |
<< | 왼쪽 쉬프트 | 빈칸을 그냥 0으로 채워줌 | ex) x << 3 // x를 왼쪽으로 3비트 쉬프트 하시오 |
2^n으로 곱하는 효과를 낼 수 있다! => 2를 곱해야할때는 *를 쓰는것보다 쉬프트를 이용해주는게 더 효율적임 |
c. 할당 (Assignment)
= | assign | x = 20; // 할당 |
+= | Add & assign | x += 20; // x = x + 20; |
-= | Subtract & assign | x -= 10; // x = x - 10; |
*= | Multiply & assign | x *= 5; // x = x * 5; |
/= | Divide & assign | x / 10; // x = x / 10; |
&= | bit and & assign | x &= 1; // x = x & 1; |
|= | bit or & assign | x |= 1; // x = x | 1; |
^= | bit xor & assign | x ^= 1; // x = x ^ 1; |
%= | modulus & assign | x %= 2; // x = x % 2; |
>>= | right shift & assign | x >> 1; // x = x >> 1; |
<<= | left shift & assign | x << 1; // x = x << 1; |
d. Relational
=> 두개를 "비교"하는것
true | false | |||
== | equal | x == y | 같을 때 | 다를 때 |
!= | not equal | x != y | 다를 때 | 같을 때 |
> | 초과 | x > y | x가 클때 (초과) | y가 크거나, 같을때 |
>= | 이상 | x >= y | x가 크거나, 같을때 (이상) | y가 클때 |
< | 미만 | x < y | x가 작을 때 (미만) | y가 작거나, 같을 때 |
<= | 이하 | x <= y | x가 작거나, 같을 때 (이하) | y가 작을 때 |
e. Logical
=> 논리연산 (AND, OR, NOT 등등)
★ C언어에서는, 0이 아닌 모든 숫자를 true라고 판단한다
== 0만이 false로 판단됨!!
true | false | |||
&& | AND | x && y | x와 y가 둘 다 true일 때 (0이 아닐 때) | x나 y 둘 중 하나라도 false일 때 (하나라도 0일 때) |
|| | OR | x || y | x나 y 둘 중 하나라도 true일 때 | x랑 y가 둘 다 false일 때 |
! | NO | !x | x가 false였을 때 (0이었을 때) | x가 true였을 때 (0이 아니었을 때) |
f. other
- size
- tenary
- address
- deference
- subscriptor
a. if
if(조건){ // true일 때 실행되는곳 } |
if(조건){ // true일 때 실행되는곳 }else{ // false일 때 실행되는곳 } |
if(조건1){ // 조건1이 true일 때 실행 }else if(조건2){ // 조건1이 false, 조건2가 true일 때 실행 } |
* 실행할 코드가 한줄일 때 {}를 생략할 수 있음 (그냥 아래 붙이기)
b. switch
=> case가 여러개로 갈라지는 경우, else if를 여러개 사용하기보다 switch를 사용하는게 더 보기에도 좋음!
switch(변수){ case 1: // 실행할것 break; case 2: // 실행할것 break; ... default: // 실행할것 break; } |
switch(변수) case 1: case 2: case 3: ... defalut: |
=> 변수에는 "정수"가 들어가야함 (int, char, short) * case 뒤에 대응하는 정수를 넣어주면 됨 * case에 걸리지 않는 모든것들은 default로 들어감 * break가 없으면, 그 다음 케이스로 타고타고 내려감 * {}는 switch 전체를 감싸는것 하나만 있으면됨 (case끼리는 {}로 묶어줄 필요가 없음) |
break가 없는 상황 => 만약 변수에 2가 들어있으면 case 2를 실행한 다음, 그 아래 case들 (case3 .. 부터 default) 전부 실행됨! => 상황에 따라 필요한경우에 적용할것 |
* case 뒤에는 무조건 상수가 들어가야한다 (변수, const 등등,, 전부 안되고 그냥 숫자로 때려박아줘야함!)
★ C# 에서는 (7.0 이후) switch 변수에 다양한 자료형이 올 수 있다 (문자열도 가능함)
★ C에서 문자열을 비교하고 싶으면? => enum을 이용하자! (문자열은 아니지만,, 문자열 상수)
=> 그냥 strcmp랑 if 섞어쓰는게 제일 베스트인것같다!
a. for loop
for(start; condition; action){ // 실행할것 } |
for(int i = 0; i<10; i++){ // 실행할것 } |
int i; for(i = 0; i<10; i++){ // 실행할것 } |
★ i 선언의 위치 : 일반적으로는 저렇게 start 부분에서 선언과 초기화를 같이해도 정상적으로 작동했다. (이경우 i의 생존범위는 for loop 안쪽까지만!)
근데 저번에 임베디드 실습하면서, c언어로 코드를 작성할일이 있었는데 저렇게 하니까 안되고 무조건 선언을 for밖에서 했어야 했다.
다들 for문 선언할 때 변수 어디에 선언하시나요? | KLDP
전 for(int i=0; ...) 이런식으로 선언하는것이 편해서 이 방법을 고수하는데 동기들 보면 for문 내에 선언하지 않고 위에 선언하는 사람들이 더 많더군요 두 방법 다 틀렸다고는 할 수 없지만 개발자
kldp.org
다음과 같은 글을 찾았다! 저렇게 안에서 선언해주는 문법은 C++부터 나왔고, C99부터 C에서도 허용을 하고있다고 한다.
오른쪽과 같이 외부에서 선언해주고, for에서는 초기화만 해주는게 C에 맞는 문법인것 같으니 앞으로 밖에서 선언해주는것에 더 익숙해져야겠다.
* for( ; ; ); -> 이런식으로 작성하면 그냥 무한반복을 돈다.
b. while loop
while(condition){ // 실행할것 } |
while(x != 10){ // 실행할것 } |
=> condition이 true일동안 무한반복함! (내부에 반드시 탈출을 위한 장치를 만들어줘야함)
이런 코드를 이용하면, password를 맞출때까지 입력을 무한반복 시키는 코드를 만들 수 있다!ㅋㅋ
int password = 1234;
int x = 0;
while(x != password){
scanf("%d", &x);
}
c. Do while
do{ // 실행할것 }while(condition); |
do{ //실행할것 }while(x != 0); |
=> 일단 실행 한번 해본다음에 조건을 확인한다 == 무조건 한번실행은 보장됨
* while 뒤에 ; 적는거 까먹지 말것!
위에 비밀번호 코드랑 비교해보면,,,,
do while의 경우, x 조건에 false여도, 일단 실행되므로 무조건 x를 입력받아야함!
만약 비밀번호라고 치면, do while을 쓰면 x에 이미 비밀번호가 들어가있어도 무조건 입력받으니까 그냥 냅다 통과해버리는 상황을 방지할 수 있게된다.
int x = 0;
do{
scanf("%d", &x);
}while(x != 0);
e. break, continue
break : 가장 가까운 반복문을 "탈출"
while 탈출조건에 유용하게 사용할 수 있음
continue : 가장 자까운 반복의 다음반복으로 넘어감 <- 탈출하는게 아님
=> 적절히 이용해 중간에 탈출조건이나, skip같은 동작을 포함해줄 수 있다!
5. 아두이노 (2) - 각종 장치 살펴보기 (0) | 2024.09.02 |
---|---|
4. 아두이노 (1) - 시작해보기 (0) | 2024.08.30 |
3. c 리뷰 2 (0) | 2024.08.21 |
1. MinGW - w64 설치하기 (0) | 2024.08.07 |