-
처음으로 배우는 C프로그래밍을 보고 공부한 내용
함수와 모듈화가 필요한 이유
- 시간이 지날수록 인간의 생산성과 밀접하게 관련해 있는 SW가 전체 프로젝트의 주비용으로 자리매김하고 있음
- 하드웨어는 제조 기술의 발전과 관련이 있기때문에 가격이 급락함 ex.마이크로칩이 10년사이에 500달러에서 1달러로 저렴해짐
- 실제 개발보단 유지보수가 오래걸리고 비용도 큼
프로그램이 쉽게 유지 되기 위해선
- 프로그램을 얼마나 쉽게 읽을 수 있고, 이해할 수 있는지에 달림
- 함수 내부 구조를 잘 구성해서 모듈화를 잘하면 유지보수 때 아주 좋음
변수의 유효 범위(Scope)
- 함수는 아래 그림과 같은 닫힌 상자로 표현할 수 있음 ( 다른 함수들이 못보게 숨겨져있다는 캡슐화같은 사실을 강조 )
- 범위에 따라 지역변수와 전역변수로 나뉘어짐
- 아래 사진을 보면 firstnum은 scope가 전역이고 secnum은 지역, 결과를 보면 차이점을 알 수 있음
12345678910111213141516171819202122232425262728293031#include <stdio.h>int firstnum;void valfum();int main(){int secnum;firstnum = 10;secnum=20;printf("\nFrom main() : firstnum = %d",firstnum);printf("\nFrom main() : secnum= %d",firstnum);valfun();printf("\nFrom main() again : firstnum = %d",firstnum);printf("\nFrom main() again : secnum= %d",firstnum);return 0;}void valfun(){int secnum;secnum=30;printf("\nFrom valfun() : firstnum = %d",firstnum);printf("\nFrom valfun() : secnum= %d",firstnum);firstnum=40;}cs [ 실행 결과 ]
- 전역 변수는 프로그래머가 함수에 의해 제공되는 일반적인 안전장치를 '넘어서게' 함
- 일반적으로 매우 제한적이고 잘 정의된 상황을 제외하고는 전역 변수를 사용하는 것은 나쁜 습관!
변수의 기억 장소 부류
- 변수는 지역,전역처럼 공간 차원에 추가로 시간 차원을 갖음
- 메모리가 변수를 위해 예약된 시간의 길이를 나타내며 기억 장소 부류( storage class )에 의해 결정 되고 이는 총 4개로 나뉘어져 변수 앞에 선언
- auto (default) : 따로 선언하지 않으면 auto
- static (전역 정적) : 실행시 메모리에 한번 올라감 , 한 소스파일에서만 사용할 수 있게 함
- extern (전역 외부) : 전역 변수의 유효 범위를 전역 변수가 선언된 하나의 소스파일에서 다른 소스 파일까지 확장 시키는것이 목적
- register
- 지역 변수 기억 장소 부류
- 아래 코드를 보면 testauto()함수를 호출 할때마다 num 변수가 0으로 계속해서 초기화 하고있으며 이걸 실행 시간 초기화(run-time initialization)이라고 함
12345678910111213141516171819202122#include <stdio.h>void testauto();int main(){int count;for(count =1; count <=3; count++)testauto;return 0;}void testauto(){int num= 0;printf("The value of the automatic variable num is %d\n",num);num++;}cs - int num을 아래와 같이 static으로 변경하면 아래와 같이 초기화 되지 않음
static int num= 0;
- 정적 변수는 함수 밖에 선언하느냐 함수 안에 선언하느냐로 외부,내부로 또 나뉠 수 있음
-내부 : 지역변수 처럼 쓰는데 값이 변경되는것을 원하지 않을 때
123456789101112131415161718192021void sub_func();int main(void) {sub_func();sub_func();sub_func();return 0;}void sub_func() {static int count = 0;int total = 0;count++;total++;printf("count = %d, total = %d\n", count, total);}-외부 : 한 파일내에 존재하는 함수끼리 같은 변수가 필요할 때
12345678910111213141516171819202122void sub_func();static int count = 0;int main(void) {sub_func();sub_func();sub_func();return 0;}void sub_func() {int total = 0;count++;total++;printf("count = %d, total = %d\n", count, total);}cs - extern,register 모두 위와 같은 결과
- register를 제외한 나머지는 컴퓨터의 메모리 영역에 예약되고 register는 cpu에 직접 위치한 고속 기억 장소인 register에 저장
- 일반적으로 컴퓨터 운영 체제처럼 컴퓨터의 동작과 직접 상호작용하는 특수 목적의 프로그램만 register변수를 사용하며 그외에는 거의 사용X
- register변수를 지원하지 않거나 저장 범위를 초과하면 자동적으로 auto 기억 장소 부류로 전환
- register 변수는 메모리가 아니라 cpu에 존재하기 때문에 주소 연산자 &을 사용하지 못함
- register는 고속 연산에 사용된다 아래는 그 예제
12345678910111213141516171819int main(void){//register int i;int i;clock_t startTime, endTime, result;startTime=clock();for ( i=0; i<=MAX; i++)printf("%d\n",i);endTime=clock();result = endTime - startTime;//printf("register class : %1f초\n",(double)result/1000);printf("auto class : %1f초\n",(double)result/1000);return 0;}cs 1차
2차
3차(...?)
4차(...??????????????) 뭘까...흠
- 프로그램은 아래와 같이 여러 파일로 구성 될 수 있다. 이때 extern을 사용하면 다른 파일에서도 해당 변수를 사용할 수 있음
- extern은 새로운 메모리를 할당 받는게 아니라 단순히 이미 존재하는 전역 변수들의 유효 범위만을 확장하는 것
- extern을 추가하면 여기서도 그 변수를 사용하겠다~ 하는 식으로 확장을 시켜주는 것
- main()에서 사용할 수 없음
- extern 선언문에서 초기화 할 수 없음
extern file_02부분 잘못됬다 ㅠㅠ 원래 아래것
12345float interest;Extern int price;int func3(){...}int func4(){...}cs 참조에 의한 전달
- 값에 의한 전달(pass by value) : 함수를 호출하고 값을 전달하는 방식
- C의 독특한 장점 : 서로 다른 함수들 사이에서 어떤 변수나 전달인자가 같은 이름으로 선언 되었어도, 서로 개별적인것으로 작성되었다고 인정
- 참조에 의한 전달(pass by reference) : 함수로 주소를 전달 하는 방식 , 주소 연산자 & 이용
ex. &num : num의 주소
123456789101112131415#include <stdio.h>int main(){int num;num=22;printf("num = %d\n",num);printf("The address of num is %u\n",&num);return 0;}cs - 포인터 변수 : 주소를 저장할 수 있는 변수 ex. messAddr = &message
- 간접 연산자 * : 포인터에 저장된 주소가 가리키고 있는 변수 ex. *messAddr은 messAddr에 저장된 주소가 가르키고 있는 변수 , messAddr이 가리키고 있는 변수
-포인터가 가지고 있는 주소로 가면 실제 변수의 값이 존재 (아래사진처럼) , 이렇게 하면 저장 된 주소가 가르키는 변수의 저장공간(데이터형)을 알 수 있음
- 앞에 변수형을 지정하면 해당 주소의 value 값을 말하는 것
- *변수의 크기는 모두 같으며 (int형이든 char형이든 ...) 컴파일러에 따라만 다르다 ** os bit수가 아니라 컴파일러 설정에 따라 달라지는것임!!
컴파일러 종류 (bit)
변수의 크기 (byte)
64
8
32
4
16
2
12345678910111213141516171819int main(){int *milesAddr;int miles;miles = 22;milesAddr = &miles;printf("The address stored in milesAddr is %u\n",milesAddr);printf("The value pointed to by milesAddr is %d\n\n",*milesAddr);*milesAddr = 158;printf("The value in miles is now %d\n",miles);return 0;}cs 함수에서의 주소 전달
- 포인터 변수만을 파라미터로 갖을 수 있는 함수를 정의하여 값이 전달되는 것을 확인
12345678910111213141516171819int main(){void newval(float *);float testval;printf("\nEnter a number :");scanf("%f",&testval);printf("The address that will be passed is %u\n\n", &testval);newval(&testval);return 0;}void newval(float *xnum){printf("The address received is %u\n",xnum);printf("The value pointed to by xnum is : %5.2f \n",*xnum);}cs - 포인터 변수를 이용하여 해당 주소의 있는 value 값을 변경할 수 있음
1234567891011121314151617181920212223int main(){void newval(float *);float testval;printf("\nEnter a number: ");scanf("%f", &testval);printf("\nFrom main(): The value in testval is : %5.2f \n",testval);newval(&testval);printf("\nFrom main(): The value in testval has been changed to : %5.2f \n", testval);return 0;}void newval(float *xnum){printf("\nFrom newval(): The value pointed to by xnum is : %5.2f \n", *xnum);*xnum = *xnum +20.2;}cs 12345678910111213141516171819202122int main(){void calc(float,float,float,float *,float *);float firstnum,secnum,thirdnum,sum,product;printf("Enter three numbers: ");scanf("%f %f %f", &firstnum, &secnum, &thirdnum);calc(firstnum,secnum,thirdnum,&sum,&product);printf("\nThe sum of the entered numbers is : %6.2f",sum);printf("\nThe product of the entered numbers is : %6.2f",product);return 0;}void calc(float num1,float num2,float num3,float *sumaddr,float *prodaddr){*sumaddr = num1+num2+num3;*prodaddr = num1 * num2 * num3;}cs 재귀
- C에서는 함수가 호출될 때마다, 인자와 지역 변수들을 위해 새로운 메모리를 할당하기 때문에 자기 자신을 호출하는 것이 가능 -> self referential 또는 recursive
- 자기 자신을 호출할때 direct recursion(직접 재귀)
- A가 B를 호출하고 B가 다시 A를 호출하면 infirect or mutual recursion(간접,상호재귀)
- 예를 들어 팩토리얼 4는 4*3*2*1 인데 이것을 슈도코드와 코드로 작성하면 아래와 같음
If n =0
factorial =1
else
factorial = n*factorial(n-1)
12345678910111213141516171819int main(){int n,result;int factorial(int);printf("\nEnter a number :");scanf("%d", &n);result = factorial(n);printf("\nThe factorial of %d is %d\n",n,result);return 0;}int factorial(int n){if(n==0)return (1);elsereturn (n * factorial(n-1));}- 아래는 함수를 호출할 때 생성되는 스택의 내용으로, 스택은 데이터를 빠르게 저장하고 가져오기 위해서 사용되는 메모리의 일부 영역
- LIFO구조로 밑에서부터 위로 쌓임 1,2,3은 순서가 아니라 변수 n의 값
일반 프로그래밍 및 컴파일러 오류
프로그래밍 오류
- 전역,지역변수의 이름을 같게 선언하는 것
- 포인터를 무분별하게 사용하는 것
- 함수의 파라미터를 포인터로 선언하고 파라미터를 넘길때 주소 연산자를 적지 않는 것
- 재귀 함수를 정의 할때 함수의 종료 조건을 기술 하지 않는 것
'2018년 > C, Java, FileSystem' 카테고리의 다른 글
[File System] ::트라이(trie) (0) 2018.01.22 [File System] ::B* tree, B+ tree (0) 2018.01.22 [File System] ::B Tree (0) 2018.01.22 [File System] :: 화일의 기본개념 (0) 2018.01.15 [C] :: 배열, 주소, 포인터 (0) 2018.01.08