본문으로 바로가기

 

지역변수

 

지역 변수란 함수 안에 선언한 변수나 매개변수를 말한다. 또한 함수와 같은 생명주기를 가진다.

단, 지역 변수는 스스로 초기화되지 않는다.

 

 

지역변수의 활용 (num 에러)

 

지역변수는 자신을 선언한 함수 안에서만 사용 가능하고 다른 함수에서 선언된 지역 변수는 사용불가하다.

num이라는 지역변수는 ReturnNum이라는 함수에서만 선언되어 있고 main함수에서는 선언되지 않았기 때문에 main함수에서 지역변수 num을 사용할 수 없다. 따라서 위와 같이 소스코드를 작성하면 빌드 오류가 발생한다.

 

지역변수 이름은 중복해서 사용할 수 있다.

 

함수 안에서 동일한 이름의 지역변수가 있는 경우 오류가 발생한다.

지역변수는 자신을 선언한 함수 안에서만 사용 가능하다.

함수와 함수는 독립적이기 때문에 지역변수의 이름을 중복 적으로 사용하는것이 가능하다.

 

Ex) 아파트에도 101동 301호 102동 301호가 있듯이 함수를 동 변수를 호라고 비교 할 수 있다.

단, 같은 함수 안에 같은 이름을 가진 지역변수가 있으면 안된다.

 

전역변수

 

전역변수란  함수 밖에서 선언한 변수를 뜻한다. 전역변수는 특별한 초기화 값이 없으면 0으로 초기화 된다.

프로그램이 시작할 때 만들어졌다가 프로그램이 종료될  때 함께 사라진다.

프로그램과 수명이 동일하다. 전역변수는 특정 함수 내에 소속된 변수가 아니라서 프로그램 전체 어느 함수에서 든지 선언 가능하다.

동일한 이름의 전역변수를 프로글매 내에서 다시 선언하면 문제가 발생한다.

프로그램을 복잡하게 만들기 때문에 가능하면 전역변수를 쓰지 않는 것이 좋다.

여러명에서 소스코드를 나누어서 만들때 전역변수를 많이 사용하면 내가 쓴 전역변수 이름하고 다른 사람이 쓴 전역변수의 이름이 다르면 피해가 생긴다.

 

전역변수의 활용

 

 

전역변수를 사용할 때 주의할 점

 

함수에 전역변수를 사용하면, 함수가 전역변수에 종속적이 된다.

함수의 독립성을 강조하는 C언어의 장점을 퇴색 시키기 때문에 전역변수의 사용을 지양한다.

 

지역변수와 전역변수의 이름이 같다면?

 

C언어 문법은 전역변수보다 지역변수를 우선해서 처리한다.

지역변수와 전역변수의 이름이 같다면 지역변수를 먼저 처리한다.

즉 지역변수의 우선순위가 전역변수의 우선순위보다 높다. 서로 다른 성격의 변수이기 때문에 에러가 나지 않는다.

전역변수 앞에 g_와 같은 접두어를 사용해서 지역변수와 전역변수를 구분해 주는 것이 좋다.

 

소스파일을 분리할 때 발생하는 오류

 

소스코드가 길어져 연관이 깊은 함수끼리 묶어 파일을 나누어 관리하면 변경된 부분이 있는 소스코드만 다시 컴파일 할 수 있어 편리하다. 소스코드를 분리할 때 나뉘어진 두 함수에서 동일한 전역 변수를 사용하는 경우 한쪽에서 전역변수를 참조하지 못해 오류 발생

 

extern 키워드

 

프로그램을 한 소스로 가지고 있으면 전역변수에 의한 오류가 발생하지 않지만 소스를 분리할 때 가장 처음으로 생기는 오류는 전역변수로 인한 오류이다.

따라서 소스를 분리 할때 extern이란 키워드를 추가해서 자기 소스안에 extern 변수명이 해당하는 변수명 전역변수를 찾아간다.

즉, extern 키워드를 사용하면 다른 소스파일에 잇는 전경변수를 참조하게 된다. 따라서 컴파일러가 extern 키워드를 만나면 이 전역변수는 다른 소스파일에 선언되어 있다고 가정하고 기계어 번역을 계속 진행하게 된다. 그리고 나중에 해당 전역 변수가 다른 소스파일에 없으면 목적 파일을 연결하는 링커가 전역변수가 있다고 했는데, 없다고 하면서 링크오류를 발생시킨다.

정확히 다시 말하자면 extern으로 변수를 선언하면 실제로 변수가 선언된것이 아니라 어떤 소스파일인지 모르겠지만 이 프로그램을 구성하는 소스파일중에 해당 전역변수가 선언되어있으니, 나중에 목적파일과 연결할때 연결해 달라는 뜻으로 사용되는 키워드 입니다.

 

extern 키워드를 사용할 때 주의할 점 (A.c, B.c 라는 소스파일이 있다고 가정하자)

 

A.c와 B.c 파일에 같은 이름의 전역변수가 있으면 링크오류가 발생한다.

A.c 파일에 선언되지 않은 전역변수를 extern 키워드를 참조했으므로 오류 발생한다. 하지만 표준전역변수가 선언 되었을때 extern 키워드를 사용하면 초기화 할 수 없고 extern 없는 것만 할 수 있다. 현재는 extern 키워드 뒤에 초기화를 사용하면 extern 키워드가 떨어져 나가고 전역변수로 바뀐다.

extern 참조에서 초기화를 사용하면 일반 전역 변수로 처리 된다. 하지만 프로그래밍에서 잘 사용하지 않기 때문에 참고만 해두자.

 

특정 소스 파일에서만 전역변수 사용하기(static 키워드)

 

전역변수의 사용 범위를 변수가 선언된 소스파일로 제한한다.

다른 소스 파일에서 extern 키워드로 참조 불가한다. 같은 이름의 전역변수를 다른 소스 파일에서 선언해도 오류가 발생하지 않는다.

static 키워드는 c++에서 의미가 더 넓어진다. 프로그래밍에서 static은 자신의 기능의 일부가 제한된 이라는 뜻을 가진다.

전역변수 앞 static은 다른 소스파일에서 이 static 전역변수를 참조 할 수 없다. static을 선언한 .c 소스파일에서만 사용 할 수 있다.

 

static 키워드를 사용할 때 주의할 점 (A.c, B.c 라는 소스파일이 있다고 가정하자)

 

A.c 파일에 같은 이름의 전역변수가 있으면 링크 오류가 발생한다.

A.c 파일의 static int data와 B.c 파일의 int data는 별개의 전역변수로 처리한다.

static으로 선언된 전역변수를 extern으로 참조하면 오류가 발생한다.

 

특정 함수에서만 전역변수 사용하기

 

전역변수를 특정 함수 안에서만 사용하도록 제한한다.

static 키워드를 사용한 함수의 지역 변수들은 지역 변수의 특성을 가지지만, 생명 주기는 전역 변수와 동일하다.

 

static 지역변수, static 전역변수 둘 다 메모리에 올라갈 때 위치가 다르다.

static 전역변수는 혼자 초기화 되지 않지만 딱 한번만 초기화 된다. 단, 전역변수는 초기화 하지 않아도 자동 초기화 된다.

 

 

 

 

const 키워드

 

값을 변경하지 말아야 하는 변수를 변경하는 경우에 문법적으로 오류가 발생하도록 제공하는 문법이다.

const는 constant의 약자이다. 변수를 상수처럼 값을 변경하지 않고 쓰고 싶을 때 사용한다.

프로그래머의 실수 방지를 위해 제공하는 문법이다.

컴파일러가 해석할 때 const를 무시하고 컴파일 하기 때문에 const 키워드를 사용하더라도 효율성이 떨어지지 않는다.

 

Day1, Day2, Day3, Day4, Day5의 부록

 

함수가 필요한 이유

 

소스코드를 만들면서 계속 반복되는 부분이 발생하기 마련이다. 이런 반복되는 부분을 하나의 함수로 만들어 사용하면 복잡한 작업을 하지 않아도 보다 간편하게 사용할 수 있다. 또한 소스코드를 만들다보면 바뀌어야할 부분이 반드시 생기게 되는데 일일히 반복되는 소스에 가서 직접 바꿔주기 보다 함수의 내용을 바꾸면 더 쉽고 편리하게 소스코드를 수정 할 수 있다.

 

프로그램에서 if 조건문은 가능한 줄이는 것이 좋다. (반복문 속에 if를 줄이는 것이 프로그램의 효율성에 도움을 준다.)

 

if 조건문을 사용하여 실행 흐름을 자주 변경하면 수행 능력이 떨어진다. 따라서 조건문을 최대한 적게 사용하는 것이 좋다.

 

 

로직 또는 구조

 

조건문과 관계 연산자는 바꿔 쓸 필요가 거의 없다. 실제로 기계어로 번역하면 거의 비슷하다.

 

if 조건문에서 조건 수식은 단순화 시키자.

 

조건 수식에 변수의 값이 0과 다른지 비교하는 조건문을 자주 사용한다.

A값이 0이 아니면 참, A값이 0이면 거짓임을 생각하자.

 

빅 엔디언(Big-endian) 방식

 

메모리에 값을 저장할 때 메모리 주소가 낮은 쪽에서 높은 쪽으로 저장한다.

0x12345678을 4바이트 메모리에 저장할 때 큰 자릿수의 값부터 저장한다.

RISC 기반의 유닉스(Unix)와 유닉스를 모델로 만든 리눅스(Linux)가 이 방식으로 바이트를 정렬한다.

하드웨어 기반과 상관없이 JAVA 언어는 무조건 빅 엔디언 방식 사용한다.

 

 

리틀 엔디언 (Little-endian) 방식

 

0x12345678을 4바이트 메모리에 저장할 때 작은 자릿수의 값부터 저장

CISC 기반의 윈두우 운영체제는 이 방식으로 바이트를 정렬

 

 

형변환 (Casting)

 

자료형이 다른 변수에 대입하기

 

 

형 변환 연산자를 사용해 자료형이 다른 변수에 대입하기

 

 

배열이란?

 

배열은 사용자 정의 데이터 타입이라고 부른다.

C언어가 제공하는 기본 자료형으로는 3바이트, 7바이트 자료형을 사용할 수 없다. 배열을 이용하여 3바이트, 7바이트 자료형을 만들 수 있다. 비정교화된 데이터를 관리할 수 있다. 일반 변수도 지역변수가 될 수 있고 배열도 지역변수가 될 수 있다.

지역변수는 stack 이라는 영역에 올라가는데 1MB가 할당되어 있다. 따라서 int 형일때 2^20 까지 선언할 수 있다.

(단, 1MB가 넘으면 실행되지 않고 프로그램이 죽는다.)

 

배열 선언하고 사용하기

 

배열은 자료형이 같은 변수들을 그룹으로 묶어서 관리할 때 사용한다.

[] (대괄호)를 사용하여 저장 공간을 몇 개 만들 것인지 명시해야 한다.

데이터를 저장할 요소의 개수는 방드시 상수로 작성해야한다.

배열은 그룹으로 묶은 데이터를 하나의 변수로 관리한다.

 

short student [20]; // 2바이트 정수형 데이터 20개를 저장할 수 있는 배열을 student라는 이름으로 선언

#define COUNT 5;

int data [COUNT]; 라고 선언하는것도 가능하다.

 

배열의 요소에 접근하기

 

변수의 개별 요소에 접근하기 위해서는 변수 이름 뒤에 []를 적고 자신이 사용하고 싶은 요소의 색인(Index)를 명시한다.

배열의 색인은 0부터 시작하여 1씩 증가한다.

배열의 요소가 N개라면 색인은 0 ~ N-1까지 사용 가능하다.

 

배열의 특정 요소에 값 대입하기

 

[] 기호를 사용하여 특정 요소의 위치를 명시하여 배열의 항목에 값을 저장한다.

student[1] = 10; // 배열의  두 번째 항목에 10을 저장한다.

 

 

배열의 오류

 

int a, data[5], b; 이렇게 선언을 하면 4byte, 20byte, 4byte가 한 덩어리로 메모리에 올라간다. 지역변수는 한 덩어리로 메모리에 올라간다.

 

 

이와 같이 한 덩어리로 올라 가기 때문에 data[-1]은 a data[5]는 b이고 에러가 나지 않는다.

포인터는 기계어가 제공하고 배열은 컴파일러가 제공하는 문법이다.

C언어는 debug 모드와 release모드가 있다. debug 모드는 프로그램 개발 할때 사용하는 것이고 release모드는 프로글매을 개발 할 때 사용한다. 배열을 제대로 사용하지 못하면 debug모드에서는 실행되는데 release모드에서는 실행 되지 않을 수 있다.

debug모드에서 int a, b;는 실수방지를 위해 40바이트로 메모리에 할당이 된다.

release모드에서 int a, b;는 8바이트로 메모리에 할당된다.

따라서 위의 그림같이 조심해서 생각하지 않으면 debug모드에서는 실행되지만 release모드에서 실행되지 않는 프로그램이 만들어 질 수 있다.

 

배열 요소에 for문으로 값 대입하기

 

배열의 특정 요소에 값을 대입할 때에는 [] 안에 변수 사용이 가능하다.

배열의 요소에 값을 대입하거나 사용할 때 변수를 사용할 수 있다는 것은 반복문과 같은 제어문을 함께 사용할 수 있다는 뜻이다.

 

 

배열 초기화하기

 

배열로 선언한 변수는 자동 초기화 되지 않는다.

배열의 각 요소에 일정한 값을 대입하여 초기화한 후 사용한다.

일반적으로 초기값 0을 사용한다.

 

쉼표를 사용한 배열 초기화 문법

 

배열로 선언한 변수를 {} (중괄호)를 사용하여 일반 변수처럼 초기화 하는 방법이다.

배열의 요소가 많은 경우 0 아닌 다른 값으로 초기화하고 싶다면 반복문을 사용하는 것이 효과적이다.

short student[20] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

short student[20] = {0, };

위 두식은 같은 식이다. 

short data[5] = {3, }; // short data[5] = {3, 0, 0, 0, 0};와 같은 식이다.

 

배열 크기 생략하기

 

배열을 선언할 때 []안의 요소 개수를 생략하고 선언 가능

short data[5] = {1, 2, 1, 2, 1};

short data[ ] = {1, 2, 1, 2, 1};

위 두 식은 같은 식이다. 단, 배열의 특정 요소에 값을 지정할 때에는 { } 사용이 불가능 하다.

short stduent[20];

student[1]={5}; stduent[2]={6,7};   //  잘못된 명령어 이다.

{5}를 명령문으로 인식한다. 명령문이라 반환값 자체가 없어 stuent[1]에 대입될 수 있다. 복합문으로 이해한다.

배열은 중간에 index(색인)값을 바꿀 수 없기 때문에 최대한 큰 index(색인)을 주어야한다는 메모리 단점이 있다.

 

문자열의 길이 정보 표시하기

 

C언어에서 문자를 저장하는 데 가장 적합한 자료형이 char 형이다.

char형 변수를 그룹으로 묶어서 관리하는 char 배열을 사용하여 문자열을 저장한다.

문자의 끝에 NULL(널) 문자 0을 추가로 입력해서 '이 배열에 저장된 정보는 문자열이다.'라고 컴파일러에게 알린다.

char data[6] = {'h', 'a', 'p', 'p', 'y', '0'}; // 문자의 개수는 5개이고 끝에 0을 덧붙여야 하므로 배열의 크기는 6이다.

char data[6] = "happy"; // 문자열의 끝에 NULL이 자동으로 포함된다.

'\0'==0이다. 문자열 내에서 아스키코드를 사용할 방법이 없기 때문에 표현을 해주기 위해서 \를 사용한다.

문자열 함수들은 각 문자가 0인지 알아야 하기 때문에 속도가 가장 느리고 비효율적이다. 따라서 요즘은 0으로 비교하는 것 보다 문자열의 길이를 계산해서 같이 관리하는 것이 효율적이다.

 

배열의 문자열을 저장하고 출력하기

 

printf로 문자열을 출력할 때 %s를 사용한다.

char data[6] = "happy";

char ment[ ] = "C programming~";

printf("%s \n", data);

printf("%s \n", ment);

 

지정된 문자열의 길이 구하기

 

배열에 저장된 문자열의 길이(문자의 개수)를 알기 위해서는 문자열의 끝(0, EOL, End Of Line)을 찾는 코드가 필요하다.

char data[6] = "happy";

int count = 0;

while(data[count] != 0) {    // data의 요소값이 NULL 문자이면 문자열의 끝이라는 뜻이다.

count++; // 문자열의 끝이 아니면 문자 개수를 하나 증가시킨다.

}

 

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

 

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

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

 

strlen = string + length    // 문자열의 길이를 구하는 문자열 표준 함수

strcpy = string + copy    // 문자열을 복사하는 문자열 표준 함수

strcat = string + concatenation    // 문자열 뒤에 다른 문자열을 덧붙이는 문자열 표준 함수

 

*** 오개념 잡기 ***