반응형
배열의 이름

배열의 이름은 배열의 시작 주소 값을 의미하는 포인터(배열의 첫 번째 요소)입니다.

단순히 주소 값이 아닌 포인터인 이유는 메모리 접근에 사용되는 * 연산이 가능하기 때문입니다.

 

배열의 모든 요소는 붙어있다. 그래서 배열의 요소들의 주소값은 연속된 값이다.

 

그렇다면 배열 이름과 포인터 변수는 같은 용도냐?

그것은 아닙니다 아래의 표에서 둘의 차이점을 알아보겠습니다

배열이름과 포인터 변수의 비교

포인터 변수는 주소를 변경가능하지만

배열은 주소가 고정되기에 포인터 변수처럼

주소값 변경이 불가능합니다.

 

 

1차원 배열 이름의 포인터형

아래의 코드에서 int형 포인터인 arr1은 *연산의 결과 4바이트 메모리 공간에 정수를 저장한다.

double형 포인터 arr2는 8바이트 메모리 공간에 실수를 저장한다.

int arr1[3] = {10,20,30};
double arr2[3] = {1.1, 2.2, 3.3};

*arr1 += 100;
*arr2 += 120.5;
printf("%d %g \n", arr1[0], arr2[0]);	// 101 121.6

 

 

 

포인터의 배열접근

아래의 코드에서 포인터 변수 또한 배열처럼 메모리 공간에 접근이 가능하다는 것을 알 수 있습니다.

int arr[5] = {1,2,3,4,5};
int arrLen = sizeof(arr) / sizeof(int);		// 배열의 길이
int* ptr = &arr[0]; 	// int* ptr = arr;	배열의 이름은 배열의 시작주소와 같다.

for(int i = ; i < arrLen; i++)
{
	printF("%d %d \n", ptr[i], arr[i]);	// 1 1 / 2 2 / 3 3 / 4 4 / 5 5
}

 

 

포인터와 배열의 관계 정리

포인터와 배열은 같다.

 

arr은 int형 배열이다.

ptr은 int형 포인터이다.

 

배열의 변수명은 배열의 시작주소를 의미합니다.

 

int형 포인터를 선언하는곳에

배열을 넣으면 정상적으로 작동합니다.

 

int형 포인터는 주소의 값을 담습니다.

그곳에 배열 변수명을 할당해주면 배열의 변수명은

배열의 시작주소를 뜻하기에 할당이 가능합니다.

 

이는 곧 int형 배열은 int형 포인터와 같다는 뜻입니다!

int arr[3] = {10, 20, 30}
int* ptr = arr;	// 컴파일 성공!

 

이미지 출처 : 윤성우의 열혈 C 프로그래밍  

 

반응형

 

반응형

'C' 카테고리의 다른 글

포인터 배열  (0) 2023.05.15
포인터 연산  (0) 2023.05.15
문자열에 대해서!  (0) 2023.05.15
C언어의 꽃 포인터!  (0) 2023.05.14
난수에 대하여!  (0) 2023.05.12
반응형
배열을 이용한 문자열

아래의 코드에서 Hello World!에서 공백까지 포함해서 12글자인데 str[13]으로 표현한 이유는

문자열의 끝에는 \0(NULL)문자가 있어야 하기 때문입니다.

 

컴파일러는 문자열의 끝을 \0(NULL)문자로 판단합니다.

char str[13] = "Hello World!";

 

참고로 \0(NULL)과 공백은 다릅니다.

\0(NULL)은 아스키코드 값0에 해당하며,

공백은 아스키코드 값32에 해당합니다.

 

널 문자는 모니터 출력에서 의미를 갖지 않는다.

그래서 아무것도 출력이 되지 않을 뿐입니다.

 

 

 

문자열입력 : scanf함수

char형 배열 즉 문자열은

입력할때 서식문자로 %s로 받으며,

인자로 넣을때 주소연산자 &를 쓰지 않는다.

문자배열 즉, 문자열은 주소의 의미를 가지고 있습니다!

char str[50];

scanf("%s", str);

 

아래의 코드에서

문자열을 입력할때 abc def를 입력하지만

결과는 abc만 나온다. 아래의 코드는 문자열에서

널문자를 만나기전 까지 문자열의 인덱스를 순회하면서

한글자씩 출력하는 코드입니다.

그렇다면 abc 와 def사이에 공백이 있지만 끝나지 않을거 같지만

scanf는 공백기준으로 입력을 받는다.

그렇기에 입력버퍼에는 abc def가 들어가 있지만

scanf의 기능 때문에 입력버퍼에는 def가 남아있고

abc가 출력이 되는것입니다!

char str[50] = {0};
int index = 0;

printf("문자열 입력: ");           // abc def
scanf("%s" , str);
printf("입력 받은 문자열 : %s \n", str);      // abc

printf("문자 단위 출력 : ");
while(str[index] != '\0')
{
	printf("%c", str[index]);	// abc
    index++;
}

 

NULL문자 표현방법
  • '\0'
  • NULL
  • 0

 

아스키코드표 출처 : http://cafe.daum.net/flowlife

 

데이터 과학자(Data Scientist) 세상

컴퓨터 프로그래밍/데이터 과학자/데이터 엔지니어에 관심있는 분들과 함께합니다.

cafe.daum.net

 

반응형

 

반응형

'C' 카테고리의 다른 글

포인터 연산  (0) 2023.05.15
포인터와 배열의 관계  (0) 2023.05.15
C언어의 꽃 포인터!  (0) 2023.05.14
난수에 대하여!  (0) 2023.05.12
배열에 대하여!  (0) 2023.05.12
반응형
포인터란?

포인터 변수는 주소 값의 저장을 목적으로 선언됩니다.

주소의 시작 주소를 뜻한다.

 

 

 

포인터 변수

아래의 그림처럼 포인터 변수를 선언하는 방법은

자료형 * 변수명; 입니다.

포인터에 같은 자료형 변수의 주소값을 할당하여 저장할 수 있습니다.

 

포인터 변수의 크기는 시스템의 주소 값 크기에 따라 다릅니다.

16비트 시스템 => 주소 값 크기 16비트 => 포인터 변수 크기 16비트

32비트 시스템 => 주소 값 크기 32비트 => 포인터 변수 크기 32비트

64비트 시스템 => 주소 값 크기 64비트 => 포인터 변수 크기 64비트

int num = 1;

// 포인터 변수	자료형 * 변수명;
int * pnum;

// 정수형 포인터변수에 정수현변수의 주소 값을 넣는다.
pnum = &num;

 

 

 

포인터 변수 선언

변수의 자료형에 따라 포인터 변수의 선언방법에도 차이가 있다.

포인터 변수에 저장되는 값은 도무 정수의 형태이지만, 그래도 선언하는 방법에 차이가 있다.

차이가 있는 이유는 변수의 자료형에 따라 메모리 접근방식이 다르기 때문이다.

 

아래의 세개의 포인터 선언은 모두 동일한 선언문이다.

*의 위치에 따라서 차이는 없다.

 

하지만 2번 권장

1. int * ptr;
2. int* ptr;
3. int *ptr;

 

 

 

&연산자

&연산자는 변수의 주소 값을 반환해주는 연산자입니다.

연산자이기에 상수가 아닌 변수가 피연산자이어야 합니다.

&연산자의 반환 값은 포인터 변수에 저장을 합니다.

int num = 10;
int* pnum = &num;

 

포인터 변수에 변수의 주소값을 저장하려면 자료형이 같아야 합니다.

 

* 연산자

* 연산자는 포인터가 가리키는 메모리를 참조합니다.

* 연산자는 피연산자는 포인터변수여야 한다

아래의 코드에서 pnum은 num의 주소값을 가지고 있고,

*pnum은 num의 주소에 있는 값을 가지고 있다. 

*pnum의 값을 바꾸면 num의 값 또한 바뀌게 된다.

int num = 10;
int * pnum = &num;
*pnum = 20;
printf("%d", *pnum);

 

이 부분은 다소 헷갈릴 수 있으니 아래의 예시를 통해서 자세히 알아보자!

int num1 = 10;
int num2 = 8;

int *pnum;

pnum = &num1;		// 포인터 pnum이 num1의 주소를 뜻함.
(*pnum) += 10;		// *pnum은 num1에 주소에 있는 값을 건드린다. 즉 num1 += 10;

pnum = &num2;		// 포인터 pnum이 num2의 주소를 뜻함.
(*pnum) -= 3;		// *pnum은 num2에 주소에 있는 값을 건드린다. 즉 num2 -= 3;

// num1 : 20, num2 : 5 포인터로 주소를 참조하여 값을 변경

 

 

 

잘못된 포인터 사용법

아래의 코드에서 1번 예시와 2번 예시는 잘못된 예시이다.

1번 예시에서 pnum1에는 쓰레기 값으로 초기화 된다. 따라서 값을 저장하더라도

그 값이 어디에 저장되는지 알 수 없다.

 

2번 예시에서 pnum2에는 데이터를 저장했는데 저장된 곳이 어디인지 아무도 모른다.

 

포인터를 선언할 때는 3번 예시처럼 널 포인터로 초기화 하는것이 안전합니다.

널 포인터 NULL은 숫자 0을 의미하며 0은 주소값이 아니라 아무것도 가리키지 않는것을 뜻합니다.

NULL로 초기화하는 것을 권장합니다!

// 1번 예시
int * pnum1;
*pnum1 = 10;


// 2번 예시
int * pnum2 = 20;
*pnum2 = 10;


// 3번 예시
int * pnum3 = 0;
int * pnum4 = NULL;

 

 

 

포인터 정리
  • int* ptr = &num; 은 포인터를 선언하는 방법이다
  • ptr 은 할당받은 주소를 뜻한다.
  • *ptr 은 할당받은 주소의 값을 뜻한다.
  • &ptr 은 ptr 자체의 주소를 뜻한다.

아래의 코드를 예시로 설명하겠습니다.

num1의 주소는 100이라고 가정하겠습니다.

 

ptr의 값은 num1의 주소(100)를 할당받는다.

*ptr의 값은 ptr에 할당되어 있는 num1의 주소(100)에서 값(10)을 받는다.

&ptr의 값은 ptr자신의 주소(300)를 뜻합니다

 

ptr = &num2; 이후

ptr의 값은 num2의 주소(200)를 할당받는다

*ptr의 값은 ptr에 할당되어 있는 num2의 주소(200)에서 값(20)을 받는다.

&ptr의 값은 ptr자신의 주소(300)를 뜻합니다.

int num1 = 10; // &num1 = 100(주소값)
int num2 = 20;	// &num2 = 200(주소값)
int *ptr = &num;	// &ptr = 300(주소값)
ptr => ?	// ptr의 값은 num1의 주소를 할당받는다.
*ptr => ?	// ptr에 할당되어 있는 num1의 주소에서 값을 받는다.
&ptr => ?	// ptr자체의 주소값이며 지금은 300

ptr = &num2;
ptr => ?	// ptr의 값은 num2의 주소를 할당받는다.
*ptr => ?	// ptr에 할당되어 있는 num2의 주소에서 값을 받는다.
&ptr => ?	// ptr자체의 주소값이며 지금도 300

 

반응형

 

반응형

'C' 카테고리의 다른 글

포인터와 배열의 관계  (0) 2023.05.15
문자열에 대해서!  (0) 2023.05.15
난수에 대하여!  (0) 2023.05.12
배열에 대하여!  (0) 2023.05.12
재귀함수에 대하여!  (0) 2023.05.10
반응형
난수란?

난수는 정의된 범위 내에서 무작위로 추출된 수를 뜻한다.

 

난수를 사용하기 위해서는 라이브러리 두개를 추가해야함

  • #include 는 rand함수를 쓰기 위한 라이브러리
  • #include 는 time함수를 쓰기 위한 라이브러리

아래의 코드처럼 실행하면 같은 수만 계속 뜬다.

// 난수발생
int random = rand();

printf("%d", random);		// 랜덤 난수 출력

 

 

 

그래서 계속 변하는 난수를 생성해주기 위해서는 아래의 코드처럼 실행해야 한다.

srand는 난수를 생성해주는 함수이다. 인자 값으로 쓰이는 time으로 시간이 흐르면서 seed값이 달라지도록 설정해준다.

time의 인자인 NULL은 현재시간이 흐르는 것을 기반으로 시간정보를 호출해준다.

 

직접 난수를 생성해주는 rand함수를 쓰기 전에 srand함수를 써서 시간의 흐름에 따라 변수가 나오도록 설정해줘야 합니다!

void RandNum()
{
	// 난수발생
	srand((unsigned int)time(NULL)); // 인자값은 
	// 현재시간을 기반으로 seed값을 만들어준다.
	// 시간은 흐르므로 seed값은 계속 달라진다.
	// time은 현재시간 정보를 호출한다


	int random = rand(); // C표준 난수 발생함수 호출할때마다 정수형태의 난수를 return
	int randNum = rand()%10; // 0~9까지 난수 발생 / 나머지 연산자로 인해서

	printf("%d\n", random); // 랜덤 난수 출력 / 매번 출력하면 같은 수가 나온다.
	printf("%d", randNum); // 랜덤 난수 출력 / 매번 출력하면 같은 수가 나온다.
}

 

반응형

 

반응형

'C' 카테고리의 다른 글

문자열에 대해서!  (0) 2023.05.15
C언어의 꽃 포인터!  (0) 2023.05.14
배열에 대하여!  (0) 2023.05.12
재귀함수에 대하여!  (0) 2023.05.10
함수에 대하여!  (0) 2023.05.10
반응형
배열이란

같은타입의 변수들로 이루어진 유한집합입니다.

 

배열에 데이터를 저장한다.

 

같은 데이터 타입을 가진 변수들이 여러개 필요할때 사용된다.

 

배열의 길이를 설정하면 수정이 불가하다.

 

인덱스로 배열의 요소(변수)들을 구분한다.

인덱스는 배열에 저장된 데이터를 참조한다.

인덱스로 배열의 변수들에 접근이 가능하다.

 

배열을 쓰는 이유

같은 타입의 이름만 다른 변수가 많이 필요할때

변수의 개수가 너무 많아져서 코드가 길어져서 가독성이 떨어지고

변수 이름이 많아지면 해당 변수를 추적하기도 쉽지 않다.

 

배열은 컴파일 타임에 메모리 사이즈가 정해진다.

 

배열의 구조

(데이터 타입) (배열명)[배열의 길이]

// int형 타입 배열, 길이는 30
int student[30];

배열은 인덱스로 요소(변수)에 접근할 수 있다. 

아래의 코드에서

1. char형 cArr[5] 배열은 char형 크기의 연속된 메모리 공간을 5byte를 할당

2. int형 iArr[5] 배열은 int형 크기의 연속된 메모리 공간을 20byte를 할당

char cArr[5]; //char 타입의 변수 5개 집합
int iArr[5]; // int 타입의 변수 5개 집합

printf("%d\n", sizeof(arr));		// 5바이트(5x1바이트)
printf("%d\n", sizeof(iArr));		// 20바이트(5x4바이트)

 

인덱스는 무조건 0부터 시작! 인덱스의 끝은 (배열의 길이 - 1)!!!!

 

선언에서 int st[5]이기에

틀린 예시 ) st[5] = 120;

인덱스가 5인 것까지 초기화 해줘야 할 것같지만

선언부에 5는 길이가 5인것을 뜻하기에 인덱스가 0~4까지의

공간까지에만 변수를 초기화할 수 있습니다.

int st[5];	// 선언하고

// 초기화
st[0] = 90;
st[1] = 10;
st[2] = 20;
st[3] = 50;
st[4] = 100;

printf("st[0]번째에 저장되어 있는 값 : %d\n", st[0]);		//결과값 : 90 출력
printf("st[1]번째에 저장되어 있는 값 : %d\n", st[1]);		//결과값 : 10 출력
printf("st[2]번째에 저장되어 있는 값 : %d\n", st[2]);		//결과값 : 20 출력
printf("st[3]번째에 저장되어 있는 값 : %d\n", st[3]);		//결과값 : 50 출력
printf("st[4]번째에 저장되어 있는 값 : %d\n", st[4]);		//결과값 : 100 출력

 

 

 

변수 선언, 초기화

아래의 방법에서는 배열의 길이를 넣지 않지만

내가 데이터의 길이를 알고 있다면 명시적으로 표현해주는게 좋다!

 

  • 배열 선언
  • 선언과 동시에 초기화
  • 길이정보 생략
  • 길이만큼 변수들을 초기화 하지 않는다 => 초기화 하지 않은 변수들은 0으로 초기화
int arr[5];	// 5개의 인덱스에 전부 쓰레기 값이 들어간다.

// 선언과 동시에 초기화
int iSt[5] = {1,2,3,4,5};


// 길이를 생략하고 초기화 하는 방법
int arrNum[] = {1,2,3};   // 길이는 자동으로 3이 된다.

// 길이만큼 변수들을 초기화하지 않으면 자동으로 0으로 초기화된다
int arrNum[5] = {1,2};

 

 

 

for문으로 배열의 변수에 접근하여 출력할 수 있다.

범위를 벗어나는 인덱스에 접근하면 쓰레기 값이 나온다.

int st[5];

st[0] = 10;
st[1] = 20;
st[2] = 30;
st[3] = 40;
st[4] = 50;

for(int i = 0; i < 5; i++)
	printf("%d\n, st[i]);		// 10, 20, 30, 40, 50 의 값이 순차적으로 출력된다.

for(int i = 0; i < 10; i++)
	printf("%d\n, st[i]);		// 10, 20, 30, 40, 50, 쓰레기값, ... , 쓰레기 값

 

인덱스의 값을 비교한다

int num[2] = {1,2};
int num1[2] = {1,3};

if(num[0] == num[1])
{
	printf("둘은 같다");
}

 

 

 

배열의 길이 구하는법

밑에 코드에서 arrLen은 5가 나온다.

sizeof(arr)은 배열요소들의 메모리크기의 합을 구해주고

sizeof(int)는 arr인덱스 하나의 메모리크기이다.

이 둘을 나누면 인덱스의 길이가 나오게 된다.

int arr[5] = {1, 2, 3, 4, 5}
int arrLen = 0;

// sizeof(arr) = 4byte x 5(인덱스의 길이) = 20
// sizeof(int) = 4byte
arrLen = sizeof(arr) / sizeof(int);		// arrLen = 5

 

 

 

배열 복잡도

O(n)(상수)     / 작을수록 좋다

.

반응형

 

반응형

'C' 카테고리의 다른 글

C언어의 꽃 포인터!  (0) 2023.05.14
난수에 대하여!  (0) 2023.05.12
재귀함수에 대하여!  (0) 2023.05.10
함수에 대하여!  (0) 2023.05.10
조건문에 대하여!  (1) 2023.05.10

+ Recent posts