Call-by-value, Call-by-reference 함수 호출 방식은 함수 인자로 전달되는 대상에 따라 2가지로 나눌 수 있다. 단순히 값을 전달하는 형태이면 Call-by-value 메모리에 접근 가능한 주소값을 전달하는 형태면 Call-by-reference로 구분 가능하다. 이와 같이 호출 방식을 구분하는 이유는 다음과 같다. 예를 들어 두 값을 전달받아 서로 값을 교환하는 swap 함수를 작성한다고 하면 Call-by-value 형식으로 함수 작성 시 아래와 같다. void swap(int num1, int num2){ int temp = num1; int num1 = num2; num2 = temp; printf("num1=%d, num2=%d", num1, num2); } int mai..
함수와 포인터 배열은 매개변수로 전달할 수 없다. 따라서 배열을 통째로 넘겨주는 것은 불가능하다. 대신 함수에서 배열에 접근하기 위해서는 배열의 주소값을 전달받는다. 함수의 매개변수로 배열 전달받는 방법 함수의 매개변수로 배열을 선언받을 경우 두가지 방법이 있다. 첫번째는 포인터로 전달받는 방식 int func1(int * ptr1){ ... } 두번째는 배열형태로 전달받는 방식이다. int func2(int ptr[]){ ... } 이 두 방식은 매개변수 선언 시에만 동일한 의미로 해석된다. 함수의 매개변수 선언 시에만 int prt[] == int * ptr 이라는 것이다. 매개변수로 전달받은 배열의 길이 함수의 매개변수로 배열의 주소를 받을 경우에는 배열의 길이를 같이 전달해줘야 한다. void f..
포인터 배열 포인터 배열이란 포인터 변수들을 저장할 수 있는 배열을 말한다. 따라서 포인터 배열에는 주소값들이 저장된다. 선언 방법은 아래와 같다. int * arr1[3]; char * arr2[2] = {"Hello", "World"}; 일반 배열 선언과 다름없다. 문자열을 가리키는 포인터 배열은 큰따옴표로 묶인 문자열은 형태에 상관없이 메모리 공간에 저장 후 주소 값을 반환함으로 "Hello"가 123456 "World"가 123457에 저장되었다고 한다면 arr2[0] = 123456 arr2[1] = 123457 이 되는 것이다. 다른 자료형들을 가리키는 포인터 배열도 마찬가지이다. 포인터 배열은 가리키는 자료형에 상관없이 해당 데이터가 저장된 주소를 갖고 있는 배열이다.
문자열 표현의 두 가지 형태 문자열을 표현하는 방식에는 두 가지 방법이 있다. 첫번째는 '변수 형태의 문자열'로 배열에 문자열을 저장하는 방법이다. char str[] = "Hello world"; "Hello world"라는 문장을 배열에 저장하는 방식으로 str에는 문장의 첫글자인 H의 주소값이 저장된다. 이는 배열에 저장된 형태이므로 값의 변경이 가능하다. 그러나 str은 항상 H의 위치를 가리키고 있어야 하므로 가리키는 위치는 변경할 수 없다. 두번째 방법은 '상수 형태의 문자열'로 포인터를 이용해 저장하는 방법이다. char * str = "Hello world"; 이는 char형 포인터 변수에 메모리 공간 어딘가에 저장된 Hell world라는 문자열의 주소값을 저장하는 방법이다. 이 방식은 ..
포인터 연산 포인터를 대상으로 증감 연산을 실행할 경우 포인터의 형에 따라 증감의 크기가 결정된다. 예를 들어 int형 포인터 ptr에 +2 연산을 할 경우 증감크기(2) * 포인터형의 크기(4) = 8이 증가하게 된다. Type 형 포인터의 크기를 n 만큼 증가 시 ==> sizeof(Type) * n 만큼이 증가하는 것이다. 이를 통해 배열에 순차적으로 접근할 수 있게 된다. int arr[3] = { 11, 22, 33 }; int * ptr = arr; for (int i = 0; i < sizeof(arr)/sizeof(int); i++) printf("%d \n", *(ptr+i)); 위의 코드처럼 배열 접근 시 응용하여 사용이 가능하다. *(++ptr) = 20; *(ptr+1) = 20; ..
배열명과 포인터 배열 이름은 포인터이다. 하지만 값을 바꿀 수 없는 상수 형태의 포인터이다. 배열명은 대입 연산자의 피연산자가 될 수 없다. int arr[3] = {1, 2, 3}; //arr = &arr[1]; 위의 두번째 문장은 컴파일 에러를 일으킨다. 이를 통해 배열명은 배열의 시작 주소를 가리키며, 값의 저장이 불가능한 상수임을 알 수 있다.
포인터 C언어는 포인터를 통해 메모리에 직접 접근이 가능하기에 low 레벨 언어의 특성을 갖고 있다고 할 수 있다. 포인터 변수에도 변수의 자료형처럼 형이 존재하는데 이가 필요한 이유는 메모리 공간에 접근 시 기준을 마련해준다. 예를 들어 int형 포인터 변수 p는 p가 가리키는 변수의 내용을 4바이트를 읽어들여 이를 정수로 해석한다. 포인터 변수의 크기 32비트 시스템에서는 주소를 32비트로 표현하는 반면 64비트 시스템에서는 64비트로 표현한다. 따라서 32비트 시스템에서 포인트 변수의 크기는 4바이트, 64비트 시스템에서 포인트 변수의 크기는 8바이트이다. & 연산자 &연산자는 오른쪽에 오는 피연산자의 주소값을 반환하는 연산자로\ 피연산자는 변수만 가능하다. 상수는 피연산자 자리에 올 수 없다! 널..
널 문자와 공백 문자 널 문자의 아스키코드는 0이고 공백 문자의 아스키코드는 32이다. int main(void){ char null='\0'; char blnk=' '; printf("%d %d", null, blnk); return 0; } 위 코드 실행 시 0과 32가 출력됨을 확인할 수 있다. 문자열 널 문자의 존재 여부에 따라 문자배열인지 문자열인지가 나뉜다. 문장 끝에 널 문자 존재 시 ==> 문자열 문장 끝에 널 문자 존재하지 않을 시 ==> 문자배열 문자열 끝에 널 문자가 필요한 이유는 문자는 메모리상에서 이진 데이터로 저장되기 때문에 문자열의 시작과 끝이 표시되어 있지 않다면 문자열을 구분하는 것이 불가능하기 때문이다.
break break문은 가장 가까이 감싸고 있는 반복문을 빠져나온다 그동안 break 범위가 헷갈렸는데 가장 가까운 반복문을 빠져나오는 것이었다 continue 얘도 마찬가지로 반복문 안에서 사용되며 continue를 만나면 그 즉시 조건문으로 이동한다. continue 다음 문장을 실행하는 것이 아니라 바로 조건문으로 이동하여 조건에 부합하는지를 확인한다. static 지역변수 지역변수 앞에 static을 붙이게 되면 - 선언된 함수 내에서만 접근 가능 (지역변수 특) - 프로그램 종료 시까지 메모리에 남아있음 (전역변수 특) 의 특성을 갖게 된다`.
2의 보수 데이터를 표현할 때 가장 왼쪽 비트 MSB는 부호를 나타낸다. MSB가 0이면 양수, 1이면 음수를 나타낸다. 8비트로 정수 5를 표현하면 0000 0101이다. 그러나 -5를 표현하기 위해선 MSB를 1로 바꾼다고 되지 않는다. MSB를 1로 바꾸기만한 -5와 5를 더한 결과는 0이 아닌 다른 수가 나온다. 음수를 표현하기 위해서는 2의 보수를 사용해야 하는데 사용방법은 1) 1의 보수를 취한 후 0000 0101 🔽🔽🔽 1111 1010 2) 1을 더한다 1111 1010 + 1 ----------------- 1111 1011 2의 보수를 통해 얻은 -5와 +5를 더하면 비로소 0이 나오는 것을 확인할 수 있다. sizeof 연산자 sizeof는 사실 함수가 아닌 연산자이다. 그래서 si..