C언어

    배열과 포인터의 관계 (2)

    배열과 포인터의 관계 (2)

    배열명과 포인터의 차이 포인터가 배열명처럼 쓰이기는 하지만 서로 다른 점이 더 많다 차이점 1. sizeof 연산의 결과가 다르다 배열명에 사용하면 배열 전체의 크기를 구하고 포인터에 사용하면 포인터 하나의 크기를 구한다 따라서 배열명을 포인터에 저장하면 포인터로 배열 전체의 크기를 확인하는 것은 불가능하다 int ary[3]; int* pa = ary; sizeof(ary) // 12바이트, 배열 전체 크기 sizeof(pa) // 4바이트, 포인터 하나의 크기 차이점 2. 변수와 상수의 차이가 있다 포인터는 그 값을 바꿀 수 있지만 배열명은 상수이므로 값을 바꿀 수 없다 즉, 포인터 pa에 1을 더하여 다시 pa에 저장할 수는 있으나, 배열명 ary는 1을 더 하는 것은 가능하고 그 값을 다시 저장하..

    배열과 포인터의 관계 (1)

    배열과 포인터의 관계 (1)

    배열명으로 배열 요소 사용하기 주소는 정수처럼 보이지만 자료형에 대한 정보를 갖고 있는 특별한 값이다 주소 + 정수 --> 주소 + (정수 + 주소를 구한 변수의 크기) ==> 배열명은 첫 번째 배열요소의 주소 값이다 #include int main(void) { int ary[3]; int i; *(ary + 0) = 10; *(ary + 1) = *(ary + 0) + 10; // ary[1] = ary[0] + 10 printf("세 번째 배열 요소에 키보드 입력 : "); scanf_s("%d", ary + 2); // ary[2]가 세 번째 배열 요소이므로 &를 사용하여 입력, ary + 2는 &ary[2]와 같다 for (i = 0; i < 3; i++) { printf("%5d", *(ary..

    전처리 지사자 (2)

    전처리 지사자 (2)

    이미 정의된 매크로 매크로에는 이미 그 정의가 약속되어 있어 사용자가 취소하거나 바꿀 수 없는 매크로명이 있다 #include void func(void); int main(void) { printf("컴파일 날짜와 시간 : %s, %s\n\n", __DATE__, __TIME__); // 컴파일을 시작한 날짜와 시간으로 치환 printf("파일명 : %s\n", __FILE__); // 전체 디렉터리 경로를 포함한 파일명으로 치환 printf("함수명 : %s\n", __FUNCTION__); // 매크로명이 사용된 함수 이름으로 치환 printf("행번호 : %d\n", __LINE__); // 매크로명이 사용된 행 번호로 치환(10행에서 사용했으므로 정수 10이 됨) #line 100 "marco...

    전처리 지시자 (1)

    전처리 지시자 (1)

    전처리 ==> 전처리기가 소스 코드를 컴파일하기 좋게 다듬는 과정이며 소스 코드에서 #으로 시작하는 지시자를 처리한다 다양한 전처리 지시자 파일을 포함하는 #include #include는 지정한 파일의 내용을 읽어와 지시자가 있는 위치에 붙여놓은다 꺽쇠갈호()는 컴파일러의 헤더파일을 포함할 때 사용한다 큰따음표(" ")는 사용자의 헤더파일을 포함할 때 사용한다 student.h (사용자가 만든 헤더파일) typedef struct { int num; char name[20]; } Student; main.c (소스파일) #include // 컴파일러가 만든 헤더파일을 포함한다 #include "student.h" // 사용자가 만든 헤더파일을 포함한다 int main(void) { Student a =..

    포인터 완전 정복을 위한 포인터 이해하기 (2)

    포인터 완전 정복을 위한 포인터 이해하기 (2)

    포인터의 대입 규칙 규칙 1. 포인터는 가리키는 변수의 형태가 같을 때만 대입해야 한다 #include int main(void) { int a = 10; int* p = &a; double* pd; pd = p; printf("%lf\n", *pd); return 0; } ==> 위에 그림처럼 *pd가 사용하는 영역이 변수 a의 영역보다 크기 때문에 알 수 없는 값이 나오는 것이다 (포인터 pd의 반환형이 int형 이라면 컴파일했을 때 10이 나왔을 것이다) 규칙 2. 형 변환을 사용한 포인터의 대입은 언제나 가능하다 double a = 3.4; double *pd = &a; int *pi; pi = (int*)pd; // double형 포인터 pd를 int형으로 바꿔줬다 ==> 위의 그림처럼 *pi가..

    포인터 완전 정복을 위한 포인터 이해하기 (1)

    포인터 완전 정복을 위한 포인터 이해하기 (1)

    포인터는 주소를 저장하는 일정한 크기의 메모리 공간이다 주소와 포인터의 차이 주소 변수에 할당된 메모리 저장 공간의 시작 주소 값 자체 '상수' 포인터 그 값을 저장하는 또 다른 메모리 공간 '변수' *즉 두 포인터가 같은 주소를 저장하는 일도 가능해짐 주소와 포인터의 크기 포인터의 크기는 저장할 주소의 크기에 따라 결정됨 포인터의 크기는 컴파일러에 따라 다를 수 있다 모든 주소와 포인터는 가리키는 자료형에 관계없이 크기가 같다 #include int main(void) { char ch; int in; double db; char* pc = &ch; int* pi = &in; double* pd = &db; printf("char형 변수의 주소 크기 : %d\n", sizeof(&ch)); printf..

    포인터의 기본 개념 (2)

    포인터의 기본 개념 (2)

    간접 참조 연산자 * , const를 사용한 포인터 포인터와 간접 참조 연산자 : * 포인터 주소를 저장하는 변수로 일반 변수와 마찬가지로 선언 후에 사용한다 (선언할 때 변수 앞에 *만 붙여준다) #include int main(void) { int a; // 일반 변수 선언 int *pa; // 포인터 변수 선언 pa = &a; // 포인터에 a의 주소값 대입 *pa = 10; // 포인터로 변수 a에 10 대입 printf("포인터로 a 값 출력 : %d\n", *pa); printf("변수명으로 a 값 출력 : %d\n", a); return 0; } *pa == a ==> 값이 같은 걸로 보았을 때 위에 코드처럼 포인터 pa와 변수 a는 같다는 것을 알 수 있다 int *pa; ==> 포인터의 ..

    포인터의 기본 개념 (1)

    포인터의 기본 개념 (1)

    포인터를 시작하기에 앞서.. 지금까지 변수 선언으로 메모리 공간을 확보하고, 그곳을 데이터를 넣고 꺼내 쓰는 공간으로 사용했다. 변수명은 그러한 메모리 공간을 식별할 수 있는 이름이었다 그러나 변수는 선언된 블록 {} 또는 함수 내부로 사용이 제한되어 있다. 그래서 사용 범위를 벗어난 경우도 데이터를 공유할 수 있는 방법인 포인터를 알아야 한다! 메모리의 주소, 주소 연산자 & 메모리의 주소 메모리라는 것은 우리가 데이터를 넣고 꺼내 쓰는 공간으로, 그 위치를 식별할 수 있어야 한다 프로그램이 사용하는 메모리의 위치를 주소 값으로 식별할 수 있다 메모리의 위치를 식별하는 주소 값은 바이트 단위로 구분된다 0부터 시작하고 바이트 단위로 1씩 증가하므로 2바이트 이상의 크기를 갖는 변수는 여러 개의 주소 값..