티스토리 뷰



문자열을 다루는 C 내장 함수


문자열은 프로그램에서 자주 사용하기 때문에 편하게 사용할 수 있도록 C언어에서 여러 함수들을 제공한다.

str 로 시작하는 문자열 표준 함수들은 string.h 파일에서 함수의 원형을 제공한다.


strlen = string + length

문자열의 길이를 구하는 문자열 표준 함수

strcpy = string + copy

문자열의 복사하는 문자열 표준 함수

strcat = string + cast

기존 문자열이 저장된 변수 이름, 새로 덧붙일 문자열



2차원 배열


데이터에 종속성이 있기 때문에 그룹을 나누기 위해 사용한다.


1차원 배열로 2차원 형태를 표현하려면?


“바둑판에 놓여있는 돌의 정보를 저장하려면?”


돌 한 개의 정보를 어떤 형식의 변수에 저장할 것인지를 결정

돌이 정보는 아래 세가지 경우, 1바이트인 char 형에 돌 한 개의 정보를 저장 가능


0 : 돌이 놓여 있지 않은 경우

1 : 검은 돌

2 : 흰 돌


바둑판 전체를 저장할 수 있는 메모리 크기를 결정한다.

바둑판은 가로 방향과 세로 방향 모두 19개의 돌을 놓을 수 있어서 총 361 의 돌을 놓을 수 있다.



2차원 배열 선언하기


1차원 배열이 필요한 이유?는 같은 크기의 변수를 나열해서 적는 것이 불편하기 때문에 배열을 사용해서 크기가 같은 변수들끼리 묶어서 사용한다.



char data1, data2, data3, data4;

char data[4];



1차원 배열 5개를 묶으려면?



char data1[4] ,data2[4], data3[4], data4[4], data5[4];

char data[5][4];



char data[5][4]을 메모리에 나열하면? 1차원 배열 5개가 일렬로 나열된다.




char data [행 개수], [열 개수] => char data [ 5 ] [ 4 ] 을 의미한다.



2차원 배열이 실제 메모리에 저장되는 형태


컴퓨터가 사용하는 메모리는 2차원 개념을 제공하지 않는다. data 변수를 위한 20바이트 메모리는 1차원 형태로 메모리에 저장된다. 즉 위에서 char data [5][4] 의 형태를 char data [20]로 저장한다.

소스코드에서 2차원 형식으로 사용할 수 있는 이유는 2차원 문법을 사용하면 컴파일러가 1차원 문법으로 변환된다.

이때 컴파일러가 2차원 문법을 1차원 문법으로 변환시, 코드가 이상하게 나올 수 있기 때문에 1차원 문법을 

사용하는 것을 추천한다.




2차원 데이터를 1차원 데이터로 변환하기


4행 4열 크기로 줄인 바둑판에서 1행 1열부터 순서대로 돌을 9개 놓는다.

돌을 놓을 때마다 0번 부터 1씩 증가시키면서 돌에 번호를 적어둔다.




1차원 데이터를 2차원 데이터로 변환하기


1차원 데이터를 2차원 데이터로 변환하려면 행 번호와 열 번호를 계산해야 한다.

2차원 배열은 메모리상에 1차원 형태로 데이터를 저장하면서 프로그래머가 이 메모리를 사용할 시 컴파일러가 

수학공식을 적용하여 2차원 개념을 제공





포인터


운영체제와 프로그래밍


포인터는 메모리의 한 지점, 즉 번지값을 가지는 변수이다. 어떤 변수든지 반드시 메모리에 보관되며 모든 메모리는 번지를 가지고 있다. ( 컴파일 과정에서 일어나는 일 )

기계어에서 변수 이름보다 변수가 위치한 메모리의 주소가 중요하다. 

변수의 이름을 사용하지 않더라도 주소만을 알고 있으면 값을 읽거나 변경 가능하기 때문이다.



메모리 주소 지정 방식


32비트 운영체제에서 메모리 주소를 4바이트 단위로 관리를 한다. 0 ~ 4,394,967,295번까지 1바이트 단위로 주소가

매겨진다. 메모리를 사용하기 위해서 사용할 주소를 지정하고 크기를 명시해주면 된다.


직접 주소 지정 방식


메모리를 사용할 때 프로그래머가 사용할 메모리 주소를 직접 적는 방식이다.



C언어의 직접 주소 지정 방식


     C언어는 변수라는 개념으로 직접 지정 방식을 사용한다. 이와 반대 개념이 포인터인데, 포인터를 다른 말로 간접 주소 

지정 방식이라 한다.


직접 주소 지정 방식의 한계


직접 주소 지정 방식은 해당 함수에서만 사용 가능하다. 이 문장이 의미하는 바는 직접 주소 지정 방식은 지역 변수를 의미한다. 지역 변수의 한계인 A라는 변수가 B라는 변수를 참조를 하지 못한다는 것이다. 

다른 함수에 선언한 변수에는 문법적으로 접근 불가하다. 다만 변수의 주소를 알 수 있다면 참조가 가능하다.


#include <stdio.h>


void Test (){

short soft = 0x0000;

soft = tips; //오류 발생

}


void main (){

short tips = 0x0005;

Test();

}




#include <stdio.h>

void Test (short data){

short soft = 0x0000;

soft = data;//오류 해결 매개변수를 사용하여.

}


void main () {

short tips = 0x0005;

Test(tips);

}


간접 주소 지정 방식


주소를 바로 주지 않고, 어떤 메모리에 가야할 메모리 주소가 적혀있으니, 어떤 메모리로 가라고 알려주는 방식이다.

32비트 운영체제에서는 4바이트를 번지로 운영한다. 그래서 사물함 역할을 하는 메모리의 크기는 무조건 4바이트이다. 

우리가 평소에 사용하는 변수들은 자료형을 선언해 사용하지만, 주소를 저장할 메모리의 크기는 따로 자료형을 사용하지 않고, 무조건 운영체제의 크기를 따라간다.


포인터


C언어에서 표현하는 간접 주소 지정 방식이다.

프로그래머가 사용하고자 하는 메모리의 주소를 저장하고 있는 메모리이다.


short * ptr ;


메모리 주소의 처음과 마지막을 알아야한다. 즉 번지가 두 개가 있어야 변수가 어디에 위치해 있는 어느 크기인지 알 수 있다. 이 두개를 아는 것은 낭비이므로 포인터가 두가지를 기억해야한다.

처음 번지는 포인터의 변수값으로 기억하고, short가 의미하는 것은 처음 번지에서 끝 번지 즉, short 의 크기만큼 떨어진 번지를 의미한다.


포인터에 선언된 변수 이름 얻기


프로그램을 실행할 때마다 사용할 메모리 공간의 주소가 다름.

-> 주소를 직접 입력하는 것보다 변수의 주소를 받아와 사용하는 것이 안전함



#include <stdio.h>


int main (void) { 

short birthday;

short * ptr;

ptr = & birthday;


printf(“번지의 주소는 : %p”,ptr);

return 0;

}


*키워드의 또 다른 이름, 번지 지정 연산자


short birthday;

short * ptr;

ptr = &birthday; // ptr에 birthday 변수 주소를 저장

*ptr = 1024; //ptr에 저장된 주소에 가서 값 1024를 대입 즉 birthday가 1024



포인터 변수


ptr =


메모리 크기는 4바이트로 고정된다.(32비트에서)

포인터 변수에 저장된 주소의 의미

-> 포인터가 가리키는 대상 메모리의 시작 주소


short * ptr;

ptr = (short*) 0x0000006C; //포인터 변수에 주소를 직접 대입.


* ptr=


ptr 형태는 포인터 변수에 대상의 주소를 넣는 것

포인터가 가리키는 대상의 값을 변경할 경우


short *ptr ;

ptr = (short *) 



다른 함수에 선언된 지역 변수 사용하기 (call by value) 

-> 직접 주소 지정 방식으로 다른 함수에 선언한 변수 사용하기


#include <stdio.h>


void swap (int a, int b){

int tmp;

tmp = a;

a = b;

b = tmp;

}


int main (void){

int start = 3, end = 4;

printf("before : start = %d , end = %d \n" , start, end);

if(start < end)

swap(start,end);

printf("after : start = %d , end = %d \n"

 , start, end);

return 0;

}

다른 함수에 선언된 지역 변수 사용하기 (call by reference)

-> 간접 주소 지정 방식으로 다른 함수에 선언한 변수 사용하기

두 변수의 값 서로 바꾸기


#include <stdio.h>

void swap (int * a, int * b){

int tmp = *a;

*a = *b;

*b = tmp;

}


int main (void){

int start = 3, end = 4;

printf("before : start = %d , end = %d \n" , start, end);

if(start < end)

swap(&start, &end);

printf("after : start = %d , end = %d \n"

 , start, end);

return 0;

}



포인터를 사용할 때 자주 발생하는 실수


포인터를 사용하거나 대입할 때 두 가지 표현이 가능

* 연산자를 사용해야 하는 곳에 실수로 누락할 시 문제 발생


const 키워드로 주소 변경 실수 막기


void swap (int * const pa, int * const pb){

int temp = *pa;

pa = pb; // pa는 const 변수라서 값을 변경 불가, 오류 발생

*pb = temp;

}


함수에서 전달 받은 주소를 변경하는 경우 거의 없음.

바뀐다면 실수일 확률이 높으므로 const를 이용하여 주소 변경 방지 가능


포인트 변수에서 const 키워드를 사용하는 여러 가지 방법


포인터 변수의 형태

저장된 값을 변경

포인터 변수가 가리키는 대상의 값을 변경

-> const를 사용하는 위치도 두 곳


const int * const p;

int * const p

int data = 5. temp = 0;

int * const p = &data;

*p = 3; // 변수가 저장하고 있는 주소에 가서 3을 대입하면 data 변수의 값이 3으로 변경

p = &temp ; //오류 발생 변수 p에 const 속성이 적용되어 p에 저장된 주소는 변경할 수 없음


사용할 메모리의 범위를 기억하는 방법


시작 주소와 끝 주소로 메모리 범위 기억하기 // 두 개를 저장

시작 주소와 사용할 크기로 메모리 범위 기억하기 // 한 개를 저장


포인터 변수의 주소 연산


포인터가 자신이 가리킬 대상 메모리의 시작 주소만 기억하면 되어서 그에 따른 특성이 있음


short dat a=0;

short *p = & data;

p = p + 1; 1이 가리키는 대상의 크기가 short이기에 short의 크기 1개만큼 증가





댓글