'Programming/C'에 해당하는 글 22건

별표 하나는 대괄호 하나에 해당한다.
2차원 배열을 포인터로 접근했을 때 별(*)표 하나는 행을 대상체로 하므로 배열 요소 자체의 값을 구할 수 없다.
포인터 변수 더하기 정수는 행 단위로 움직인다.

/* *( imsip + 1 ) 과 *imsip + 1의 차이 */
#include <stdio.h>
main() {
  int imsi[ 2 ][ 3 ] = { { 3, 5 }, { 12, 54 }, { 534, 923 } };
  int ( *imsip )[ 2 ];

  imsip = imsi;

  printf( "%#010x %#010x\n", *imsip, *imsip + 0 );
  printf( "%#010x %#010x\n", *( imsip + 1 ), *imsip + 1 );
  printf( "%#010x %#010x\n", *( imsip + 2 ), *imsip + 2 );
}
// output
0x8047d10 0x8047d10
0x8047d18 0x8047d14
0x8047d20 0x8047d18

*imsip, *imsip + 0 은 차이가 없다.
*( imsip + 숫자 ) 는 imsip + 숫자와 같고 이는 행 단위로 움직인다.
*imsip + 숫자는 배열 요소의 증가를 뜻하므로 4바이트씩 증가한다.

int imsi[ 2 ][ 3 ] = { { 3, 5 }, { 12, 54 }, { 534, 923 } };
int ( *imsip )[ 2 ];

imsip = imsi;

// 다음 포인터 변수를 사용하여 출력
printf( "%d\n", *( *( imsip + 0 ) + 0 ) );  // 3
printf( "%d\n", *( *( imsip + 0 ) + 1 ) );  // 5
printf( "%d\n", *( *( imsip + 1 ) + 0 ) );  // 12
printf( "%d\n", *( *( imsip + 1 ) + 1 ) );  // 54
printf( "%d\n", *( *( imsip + 2 ) + 0 ) );  // 534
printf( "%d\n", *( *( imsip + 2 ) + 1 ) );  // 923
// 가장 안쪽의 괄호 안의 수치는 행, 바깥쪽은 행의 배열 요소와 관련

// 다음과 같이 변경 가능
printf( "%d\n", *( imsip[ 0 ] + 0 ) );  // 3
printf( "%d\n", *( imsip[ 0 ] + 1 ) );  // 5
printf( "%d\n", *( imsip[ 1 ] + 0 ) );  // 12
printf( "%d\n", *( imsip[ 1 ] + 1 ) );  // 54
printf( "%d\n", *( imsip[ 2 ] + 0 ) );  // 534
printf( "%d\n", *( imsip[ 2 ] + 1 ) );  // 923

// for문 사용
for ( i = 0; i < 3; i++ )  // 행의 길이
  for ( j = 0; j < 2; j++ ) { // 열의 길이
   printf( "%d\n", *( imsip[ i ] + j ) );
  }
}


int ( *imsip )[ 2 ] vs int *temp[ 2 ]

#include <stdio.h>
main() {
  int ( *imsip )[ 2 ];
  int *temp[ 2 ];

  printf( "&imsip %#010x\n", &imsip );
  printf( "&temp[ 0 ] %#010x\n", &temp[ 0 ] );
  printf( "&temp[ 1 ] %#010x\n", &temp[ 1 ] );
}
// output
&imsip 0x8047d24
&temp[ 0 ] 0x8047d18
&temp[ 1 ] 0x8047d1c

temp 라는 것은 포인터를 저장할 수 있는 영역이 두 개인 것이다. (temp[ 0 ], temp[ 1 ])
그리고 temp 자체는 배열명이 된다.

WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,
배열 포인터 정의

int *imsip;  // 1차원 배열 포인터
int (*imsip2)[ 3 ];  // 2차원 배열 포인터
int (*imsip3)[ 2 ][ 3 ];  // 3차원 배열 포인터

/* 1차원 배열의 sizeof */
#include <stdio.h>
main() {
  int imsi[ 2 ];
  int *imsip;

  printf( "%d\n", sizeof( imsi ) );  // 8
  printf( "%d\n", sizeof( imsip ) );  // 4
  printf( "%d\n", sizeof( *imsip ) );  // 4
}
.
/* 2차원 배열의 sizeof */
#include <stdio.h>
main() {
  int imsi[ 2 ][ 3 ];
  int ( *imsip )[ 3 ];

  printf( "%d\n", sizeof( imsi ) );  // 24
  printf( "%d\n", sizeof( imsip ) );  // 4
  printf( "%d\n", sizeof( *imsip ) );  // 12
}

*imsip 가 가리키는 대상체는 imsi[ 0 ][ 0 ] 하나가 아니라
imsi[ 0 ][ 0 ], imsi[ 0 ][ 1 ], imsi[ 0 ][ 2 ]이다.
( *imsip )[ 3 ] 에서 첨자에 사용된 3이라는 수치가 이를 나타내고 있다.
2차원 배열 포인터 변수의 배열 첨자는 열의 개수이다.

#include <stdio.h>
main() {
  int imsi[ 2 ][ 3 ] = { { 3, 5 }, { 12, 54 }, { 534, 923 } };

  printf( "%d byte\n", sizeof( imsi ) );  // 24
  printf( "%d byte\n", sizeof( imsi[ 0 ] ) );  // 8
  printf( "%d byte\n", sizeof( &imsi[ 0 ][ 0 ] ) );  // 4
}

imsi, imsi[ 0 ], &imsi[ 0 ][ 0 ] 는 확실히 같은 번지를 가리킨다.
하지만 가리키는 대상체의 크기가 다르다는 것을 위 예문에서 보여준다.
imsi 는 배열 전체를 가리키고 있다. ( 24 byte가 증명 )
imsi[ 0 ] 는 행을 대표하고 있다. ( 8 byte가 증명 )
&imsi[ 0 ][ 0 ] 는 하나의 배열 요소를 가리키고 있다.

int imsi[ 3 ] = { 5, 3, 7 };
int *imsip = imsi;

int imsi2[ 3 ][ 2 ] = { 7, 3, 2, 5, 3, 8 };
int (*imsip2)[ 2 ];

imsip 는 imsi 배열의 첫번째 요소를 가리킨다.
5, 3, 7 전부를 가리키는게 아니라 5만 가리킨다.
2차원 포인트 변수인 imsip2 는 2차원 배열이기 때문에 요소의 행을 가리킨다.
imsip 가 가리키는 대상은 4바이트고 imsip2 는 8 바이트이다.

WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,

배열의 초기화

Programming/C 2006. 10. 24. 20:21
1차원 배열

#include <stdio.h>
main() {
  int imsi[ 3];

  imsi[ 0 ] = 0;

  printf( "%d %d %d", imsi[ 0 ], imsi[ 1 ], imsi[ 2 ] );
}
// output
0 -541085696 -541125761

위 예를 보면 배열이 어떤 값을 저장할 수 있는지를 지정하는 타입이 있다.
배열의 첨자를 이용하여 배열의 개수도 지정한다.
배열의 첨자는 0부터 시작하므로 정의할 때 첨자 수와 사용할 때 첨자 수는 -1의 오차를 보인다.
imsi[ 1 ], imsi[ 2 ]는 초기화를 하지 않았으므로, 어떠한 값이 들어가 있을지 아무도 모른다.
다음의 두가지 방법은 imsi 배열을 초기화 시켜준다.

for ( i = 0; i < 3; i++ ) {
  imsi[ i ] = 0;
}

int imsi[ 3 ] = { 0 };

다음과 같이 첨자를 생략할 수도 있다.

int imsi[] = { 4, 3, 7, 4 };

위 문장을 만나는 순간 컴파일러는 초기치의 개수를 세고 이를 첨자에 반영한다.
imsi의 첨자는 자동을 4가 되고 16바이트가 할당된다.


다차원 배열

다차원 배열은 다음처럼 할 수 있다.

int imsi2[ 2 ][ 3 ];
int imsi3[ 2 ][ 3 ][ 4 ];
int imsi4[ 2 ][ 3 ][ 4 ][ 5 ];

#include <stdio.h>
main() {
  int imsi[ 2 ][ 3 ] = { 0 };

  printf( "%d %d %d %d %d %d", imsi[ 0 ][ 0 ], imsi[ 0 ][ 1 ], imsi[ 0 ][ 2 ], imsi[ 1 ][ 0 ], imsi[ 1 ][ 1 ], imsi[ 1 ][ 2 ] );
}
// output
0 0 0 0 0 0

다차원 배열의 초기화 방법

int imsi[ 2 ][ 3 ] = { { 1, 2, 8 }, { 34, 634, 7 } };
int imsi[ 2 ][ 3 ] = { 1, 2, 4, 2, 34, 634 };
// 빈공간은 0으로 초기화
int imsi[ 2 ][ 3 ] = { { 1, 2, 8 }, {} };
int imsi[ 2 ][ 3 ] = { 1, 2, 8 };
int imsi[ 2 ][ 3 ] = { {}, 4, 7, 3 };
int imsi[ 2 ][ 3 ] = { {}, { 4, 7, 3 } };


1차원 배열과 포인터

배열명은 배열의 첫번째 배열요소의 주소를 뜻한다.
배열명은 포인터 변수가 아니라 배열명 자체임을 명심하라.

#include <stdio.h>
main() {
  int imsi[ 3 ] = { 5, 3, 7 };
  int *imsip;

  imsip = imsi;

  printf( "%#010x %#010x %#010x\n", imsi, &imsi[ 0 ], imsip );
}
// output
0x8047d1c 0x8047d1c 0x8047d1c


포인터 + 정수

주소값 + 정수값 = 주소값이다.
포인터 변수에 정수값을 더할 때 정수 값 만큼의 바이트가 더해지는게 아니라 포인터 변수의 타입 크기만큼 증가한다.
그러므로 배열의 주소값에 + 정수값을 하면 다음 첨자 값을 얻을 수 있다.

#include <stdio.h>
main() {
  int imsi[ 3 ] = { 5, 3, 7 };
  int *imsip;

  imsip = imsi;

  // 더하기(+) 보다 역참조 연산자(*)의 우선순위가 높으므로 괄호를 사용
  printf( "%d, %d, %d", *( imsip + 0 ),  *( imsip + 1 ),  *( imsip + 2 ) );
}
// output
5 3 7

WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,

포인터 변수

Programming/C 2006. 10. 23. 17:57
포인터

포인터는 번지에 대한 기호화된 표현을 말한다.

int imsi;

imsi라는 변수를 정의한 문장을 만나면 시스템은 imsi에 대하여 4바이트의 메모리를 할당한다.
시스템이 할당해 준 4바이트는 다른 프로세스들이 할당받지 못하므로 안전하게 사용할 수 있다.
4바이트는 모두 번지라고 하는 이름을 가지고 있고, 일반적으로 4바이트 형식으로 표현된다.

int imsi (4byte)
1byte : 0x8047c70
1byte : 0x8047c71
1byte : 0x8047c72
1byte : 0x8047c73

결국 포인터라는 것은 메모리의 위치를 표현한 기호인 것이다.


포인터 변수

포인터 변수는 포인터를 저장할 수 있는 변수를 말한다.
이 말은 메모리의 특정 위치를 저장한다는 말과 같다.
포인터 변수에는 번지 이외에는 그 어떤 것도 들어갈 수 없다.

int *imsip;

imsip라는 정수형 변수에 *을 붙였다.
imsip는 정수를 저장하는 곳이 아니라, 정수가 저장된 곳의 위치을 기억하게 된다.
포인터 변수 imsip에는 오로지 번지만 들어갈 수 있으므로 숫자나 문자열 등을 할당할 수 없다.

main() {
  int *imsip;

  printf( "%p\n", imsip );  // imsip 에 저장된 값 출력
  printf( "%p\n", &imsip );  // imsip 가 할당된 메모리 주소 출력 (0x8047c64 등의..)
}


& 연산자

포인터 변수에 번지 값을 저장하기 위해 '&' 연산자가 필요하다.
&는 '앤드 연산자', '번지 연산자' 하고 하며, 어떤 변수가 저장된 곳의 선두 번지를 뜻한다.

#include <stdio.h>

main() {
  int imsi = 5;

  printf( "imsi[ %d]\n", imsi );
  printf( "&imsi[ %#010x]\n", &imsi );
}
// output
imsi[ 5]
&imsi[ 0x8047d24]


포인터 변수에 번지 할당

#include <stdio.h>

main() {
  int imsi;
  int *imsip;

  imsip = &imsi;
}

imsip 라는 포인터 변수에 imsi 가 저장된 곳의 주소를 넣고 있다.
& 연산자가 특정 변수의 선두 번지를 뜻한다면, * 연산자는 포인터 변수에 저장된 선두 번지를 참조하여 하나의 값을 취한다.

#include <stdio.h>

main() {
  int imsi = 5;
  int *imsip;

  imsip = &imsi;
  printf( "*imsip[ %d]\n", *imsip );
}
// output
*imsip[ 5]
&imsi == imsip == &*imsip
.
#include <stdio.h>

main() {
  int imsi = 5;
  int *imsip;

  imsip = &imsi;
  *imsip = imsi;  // * 역참조 연산자 (deferencing operator)
  printf( "imsip[ %#010x] *imsip[ %d]\n", imsip, *imsip );
}
// output
imsip[ 0x8047d24] *imsip[ 5]
.
#include <stdio.h>

main() {
  int imsi = 5;
  int *imsip;

  imsip = &imsi;
  *imsip = *imsip + *imsip;
  printf( "%d\n", *imsip );  // output: 10
  printf( "%d\n", imsi );  // output: 10
}


포인터 변수 타입

int  *intp;
float  *floatp;
double  *doublep;
char  *charp;

포인터 변수 타입은 메모리에 4바이트가 할당된다.
그렇다면 위와 같은 포인터 변수에 왜 타입이 필요한가?
포인터 변수의 타입은 변수가 가리키는 곳으로 번지로 가서 몇 바이트를 읽어오는가에 대한 답을 주는 것이다.

WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,

Pointer & Array

Programming/C 2006. 10. 4. 11:51
포인터와 배열 (Pointer & Array)

배열에 의한 연산은 포인터를 사용해서 할 수 있다.
포인터를 사용하는 것이 더 빠르다.

int a[10];  // 크기가 10인 배열
int *pa;  // 정수형 포인터

pa = &a[0];  // pa는 a[0]의 포인터
x = *pa  // x는 a[0]과 같은 값
*(pa + 1)  // a[1] 과 같음

a[i]는 *(a + i)와 같다.


번지 연산

/* 포인터의 뺄셈 - 문자열 길이 반환 */
int strlen( char *s ) {
  char *p = s;  // p 초기화 - s 문자열의 처음을 가리킴
  while ( *p != '\0' )
   p++;
  return p - s;  // 비교한 문자의 개수, 문자열의 길이를 나타냄
}

포인터에 대한 정수를 더하거나 뺄 수 있다.
포인터를 0과 비교할 수도 있고 같은 배열내의 두 포인터를 비교할 수도 있다.
포인터에 포인터를 더하거나 뺄 수는 없다.
포인터에 실수를 더하거나 빼서도 안되며 포인터에 곱셈이나 나눗셈을 해서도 안된다.
포인터에는 비트연산을 해서도 안된다.
cast 연산자 없이 어떤 형의 포인터를 다른 형의 포인터로 사용하면 안된다.(void예외)

WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,