레이블이 C language인 게시물을 표시합니다. 모든 게시물 표시
레이블이 C language인 게시물을 표시합니다. 모든 게시물 표시

2017년 4월 28일 금요일

C언어 배열/주소 개념 정리 arr+1, arr[0]+1,&arr[0]+1, &arr+1, &arr[0][0]+1 , 그리고 배열명의 두 가지 의미

포인터를 제대로 잡고가기 위해서는 배열의 정확한 개념이해가 필수적이다.
배열은 주소(address) 와 굉장히 연관이 있기에 배열 개념을 제대로 잡으면, 포인터가 좀더 쉬워질 수 있다.

먼저 2차원  int 배열을 선언 하였다고 가정하고 값이 아래와 같다고 생각하자 .

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

문제를 내겠다. 문제를 전부 맞춘다면, 배열의 개념에대해 정확히 알고 있는 것이므로, 이 글을 생략하거나,
가볍게 읽고 다시 복습 하는 개념으로 읽으면 도움이 될 것이다.

arr의 주소가 1000 이라고 가정하자.
(앞의 4자리가 귀찮고, 16진수가 불편하니 10진수로 답을 적고 문제를 내겠음.)

printf("%p", arr)    ==>   1000  이라고 가정하면
=========================
1. arr = ?
2. arr[0] = ?
3. &arr = ?
4. &arr[0] = ?
5. &arr[0][0] = ?
=========================
위 다섯 개 답은 무엇일까 ?




모두 1000 이다. 그런데 무엇이 차이가 있을까? 같은 주소 1000을 가리키는데 왜 이렇게 표현 방법이 많을까. 헷갈 릴 수 있다.

아래 문제를 풀면 왜 다 다른지 알수 있다.

========================
6.  arr+1 = ?
7.  arr[0] + 1 =?
8.  &arr + 1 = ?
9.  &arr[0] + 1  =?
10. &arr[0][0] + 1 = ?
11. arr[0][0] +1 = ?
12. sizeof(arr)
13. sizeof(arr[0])
14. sizeof(arr[0][0])
15. sizeof(&arr)
16. sizeof(&arr[0])
17. sizeof(&arr[0][0])
========================






6.  1012 , 7.  1004,  8.   1024,    9.   1012,    10.   1004,    11.    2
12.  24,   13.   12,   14.   4     15.     4,    16.    4,    17.   4

이다.

여기까지 당연하게 쉽게 쉽게 푼다면, 배열의 개념과 주소의 개념을 정확히 알고 있는 것이라고 할 수 있다.
그럼 이 글을 스킵하거나, 가볍게 복습 겸 읽으면 된다.


배열의 이름 (배열명) 이 의미하는 것은 두가지 이다. ((*매우 중요))
1. 배열 전체
2. 배열의 첫번 째 인자의 시작 주소이다.

1번이 적용되는 가장 큰 경우는 sizeof(arr)의 경우이다.  int arr[2][3] 으로 선언 되어있으므로,
int가 4byte이고, int형태가 2행 3열로 되어있는 것이므로 4byte * 2 * 3  = 24byte 로
24 라는 결과 값을 얻게 될 것이다.
(int의 데이터 값은 cpu의 bit에 따라 값을 달리 할 수 있으므로, 참고한다. 많이 쓰는 일반적인 경우가
4byte 임.)

1. arr = ?
2. arr[0] = ?
3. &arr = ?
4. &arr[0] = ?
5. &arr[0][0] = ?

앞서 보았던 문제의 값이 다 1000이다.
그런데 이것이 의미하는 것이 조금 씩 다른 것이다.
1부터 보면, 배열명이 의미하는 두번째 의미가 적용된다. '배열의 첫번 째 인자의 시작 주소' 이다.
배열이라는 개념이 시작주소부터 한칸씩 이동하는 개념인데 +1, +2 라는 개념을 보기에 앞서,
 이 개념을 1차원 배열로 접근해보자.
1차원 배열에서 는 int arr2[3] = {7,8,9} 라고 할 때,  7, 8, 9 라는 데이터에  arr2[0], arr[1], arr[2] 로 접근할 수 있고, 이것의 주소의 접근에는 &arr2[0], &arr2[1], &arr2[2] 로 접근 할 수 있다.
이 1차원 배열에서  sizeof(arr2) 라고하면, 배열명의 첫 번 째 의미인 배열전체를 의미하게되어, 12가 나올 것이고,  arr2를 단순히 출력하라고 한다면, 이것은 arr2의 시작주소를 출력 할 것이다. arr2의 시작주소가 2000 이였다고 가정해보자.  arr2 + 1 을 출력하면 몇이 나올까?
 답은 2004가 나올 것이다. 여기선 배열명의 두 번 째 의미인, '배열의 첫번 째 인자의 시작주소' 를 의미한다. 이 말이 무슨 의민지 정확히 이해가 안갈 수 있는데, 정확히 똑같은 값을 의미하는 것이 무엇이냐면
arr2  == &arr2[0] 이다. 즉,  arr2[0] (7을 가지고 있는 int ) 의 주소 2000을 가리킨다. 4byte 범위의 시작주소 2000이라는 것이다. 그래서 arr2+1 은 2004이다.
그럼 &arr2+1 은 무엇이 나올 것인가?
답은 2012이다. 그런데 이것은 헷갈릴 수 있다. arr2라는 arr2[3] 의 배열명인 arr2가 배열 전체를 의미한다며? 라고 반문 할 수 있는데, 주소를 접근하는 개념에서 배열명은 첫번 째 인자의 시작 주소라는 것을 머리속에 깊이 새겨놔야한다. 접근하고자 한다면 접근할 수 있지만, 배열이 12범위를 차지하는데 그범위를 넘어선 영역을 왜 접근하겠나? .. 라는 생각을 하면, 수긍이 갈 것이다. 일반적으로 접근할리가 없기에 &arr이라는 문자를 사용해야 &arr이 주소 개념에서 12 byte를 차지한다. 그래서 &arr + 1 은 2000 + 12 인 2012가 된다.

 1차원 배열은 여기까지 이야기하고 정리를 하겠다.

-----------------------------------------------------------------------------------
              2000       2004     2008        (주소)  
 int arr2 =       {  7           8            9 }

arr2 == 2000 ( arr2[0] 의시작주소 인 2000 (4byte의미))
 따라서 arr2 + 1 == 2004

arr2[0] == 7   (배열의 인자인 arr2[0] 자체는 그 값을 의미)
 따라서 arr2 + 1 == 8  (여기서 8은 다음인자 8을 가리키는 것이아니라 단순히 값에 1을 더한 8임)

&arr2 == 2000 (arr2 배열전체의 시작주소인 2000 (12byte의미))
 따라서 &arr2 + 1 == 2012  (이것이 배열을 벗어나는 의미이므로 사실상 다른영역에 대한 접근임)

&arr2[0]  == 2000 ( 배열의 인자인 arr2[0] 의 주소 arr2[0] 은 4byte의 int형태)
 따라서 &arr2[0] + 1 == 2004  == &arr2[1]

-----------------------------------------------------------------------------------


이제 2차원 배열을 봐보자.

int arr[2][3]
1000            1004         1008
       {       1             2               3       }
1012             1016          1020
       {       4            5               6       }

이렇게 나타낼 수 있다. 그리고 위에 주소들은 각각 인자의 시작주소라고 인지하자.
글로 풀어 쓰면
&arr[0][0] == 1000 ,  &arr[0][1] == 1004 ,  &arr[0][2] == 1008
&arr[1][0] == 1012    ,  &arr[1][1] ==  1016  ,  &arr[1][2] == 1020
이다.

2차원 배열을 다른 생각으로 접근해보자. arr은 arr[0], arr[1] 이라는 두개의 인자를 가진 배열이다.
그리고 arr[0] 는 1 ,2 ,3 int형 (4byte)를 3개 가지고 있는 12byte 짜리 형태인것이다.
다시 말해 arr은  int [3] 형태의 인자를 두개 가지고 있는 1차원 배열이다. 라고 생각할 수 있다.
그렇게 접근하면 위의 1차원 배열과 같이 쉽게 이해 할 수 있다.
arr 이라는 값을 출력하게 되면 , 그것은 arr배열 {arr[0], arr[1]} 두 인자를 가진 인자의 첫번 째 인자의 값.
즉 arr[0] (12byte)의 주소 인 1000이다 . 그래서 arr+ 1 은 1012 라는 값을 갖는다.
그리고 arr[0] 라고 그 값을 출력하면 역시나 1000이 뜨는데 arr[0]라는 것은 {1, 2, 3} 인자를 가진 배열의 배열 명 이라고 할 수 있다. 그래서 arr[0] 라는 것은 첫번 째 인자인 1 (4byte), 즉 arr[0][0] 의 주소인
&arr[0][0] 로써의 1000이라는 결과 값을 갖는다. arr[0]+1 은 그래서 1004 라는 값을 갖는다.
그리고 최하위인 arr[0][0] 는 주소가 아닌 1 이라는 값 이다.

문제를 하나 하나 짚어보자.

6.  arr+1
arr 은 배열 arr의 첫번 째인자인 arr[0] 의 주소 즉 arr[0]+1 은 12byte의 arr[0]의 다음인 1012를 의미

7.  arr[0] + 1
arr[0]는 {1, 2, 3} 의 배열명임. 즉 arr[0]의 첫번째 인자는 arr[0][0]인 1이고 , 이것은 int형으로
+1 한 결과는 1004가 됨.

8.  &arr + 1
주소개념에서 &를 붙인 &arr은 (24byte)의 시작주소인 1000이다. 그래서 &arr+1 을 하게되면 1024가 된다.

9.  &arr[0] + 1
arr[0]라는 {1,2,3}의 배열명에 &을 붙이면 그 배열 전체인 12byte를 의미해서 +1 을하면 1012가 된다.

10. &arr[0][0] + 1
&arr[0][0] 은 2차원배열에서 1을 값으로 갖는 int 형의 주소이다. 이 경우는 일반적으로 많이 쓰므로 +1 의 결과가 1004 라는 것을 알 것이다.

11. arr[0][0] +1
arr[0][0]은  arr 2차원 배열 의  1이라는 값이다. 거기에 +1을 했다는 것은 1이라는 값에 +1을 해서 2가 된 값이다. arr[0][1] 이 절대 아님..

12. sizeof(arr)
arr은 배열명의 첫번 째 의미로써 작용되고, 24byte 24 의 결과가 나온다.
13. sizeof(arr[0])
arr[0]는 1,2,3을 포함하는 첫번째 행이고, int 형 3개를 포함하는 배열로 12가 나온다.
14. sizeof(arr[0][0])
sizeof(int)와 같은 의미고, 정확히는 sizeof(1)을 한 것이다. int 형의  크기 4 가 나온다.
15. sizeof(&arr)
&가 붙은건 무조건 주소이다. 주소 (포인터) 의 크기는 4이다.
16. sizeof(&arr[0])
&가 붙은건 무조건 주소이다. 주소 (포인터) 의 크기는 4이다.
17. sizeof(&arr[0][0])
&가 붙은건 무조건 주소이다. 주소 (포인터) 의 크기는 4이다.











2016년 2월 16일 화요일

[Embedded Academy with IoT] C language Chapter 1, 2 and Orientation [Day 1]

It was yesterday. but it isn't. 
I have lectured C language for Embedded S/W. It will be during 2 weeks. 
Us book is [THIS IS C] in English (이것이 C언어다.in Korean).
The author teaches us with the book in MDS Academy in Guro Digital Center. We learned Chapter 1 and 2.
I know this education class's goal is to make Embedded employers. 

I will lecture until next week. It's maybe hard to review the book myself.
 

2015년 1월 6일 화요일

[C언어] 함수의 네가지 기본형태에 대한 이해


 Add(), ShowAddResult(), ReadNum(), HowToUseThisProg()
각각 반환과 인자전달의 유무가 다른 네개 형태의 사용법에 대한 코딩이다.
이렇게 작성하면 반환 값? 인자전달? 이라는 의문이 들 수도 있는데,

 인자란 함수 사용시에 사용하는 값, 반환 값은 일반적으로 함수내의 결과 값을 의미한다고 할 수 있다. 
 다른 말로하면, Add함수에서 int(정수) 형태의 num1과 num2 의 값을 받아들여 그것으로 함수가 갖는 계산을 한다고 할 수 있다. 물론 함수마다 어떤 계산일지는 다르겠지만,
 Add 에 한해서는 num1+num2의 계산이다. return num1+num2; 라고 되어있는데, 더하기와 동시에 그 값을 반환; 즉, Result =Add(int num1,int num2); 라고할 때 Result 값은 num1, num2 의 합이 되는 것이다. 더 쉽게 Result= Add(3,4); 라고 하면 Result 값에 3과 4의 합; 7을 Result에 대입하는 것이다.

 반환 값이 없는 경우에는 대표적인 경우가 ShowAddResult()처럼 함수내의 printf()함수가 있는 경우이다. printf()자체가 모니터로 반환한다는 의미로 볼 수 있다. (*깊이 들어가면 printf()함수는 글자열의 길이를 반환값으로 갖는 함수이다. 그 말은 즉, ShowAddResult()를 반환이 가능한 함수로 만들고 return printf(); 할 경우 문자열의 길이 값을 반환 하게도 만들 수 있다는 의미이다.) 괄호안의 말은 깊이 이해하지 않아도 되며, 이 문제를 쓴 저자는 함수를 간단히 설명하기 위해 사용한 것이므로, 인자만 받아서 반환하지 않는 함수로 사용할 수 있구나... 하고 이해하면 된다.

 세번 째의 ReadNum() 함수를 보면, 반환 값만 있다. ReadNum(); 이라고 선언한 것이 scanf("%d",&num); 을 간단히 하기위한 장치라고 할 수 있다. 물론 ReadNum()으로만 선언만 하면 결과 값을 컴퓨터에서만 가질 뿐 이걸 이용하기 위해서는 그림과 같이 num1=ReadNum(); 식으로 사용하면 ReadNum() scanf로 입력받은 값을 num1에 저장한다.

 마지막으로, HowToUseThisProg() 함수는 인자(입력)도 반환(출력)도 없다. 무엇인가 기본적으로 모니터상으로 보여주고 싶은 문구가 있을경우 printf("블라블라블라 \n"); 의 형태로 사용할 수도 있지만, HowToUseThisProg(); 선언만으로 같은 결과를 도출할 수 있다니 얼마나 간편하겠는가. (문자의 길이부터) 물론 함수선언이 차지하는 공간이 있긴 할테지..

 예제를 거의 가져온데다가 내 생각을 덧붙인 것 뿐이지만, C언어에서는 함수가 시작이고 끝이고 심지어 int main() 메인 함수또한 함수인 모든 함수 형태이므로 함수는 정말정말정말 중요해서, 블로그 글에 게시한다. 항상 4가지가 있다는 것을 기억하자.
 1. 인자와 반환 값이 있는경우        example)    Add()
 2. 인자는 있고 반환값이 없는경우                   ShowAddResult()
 3. 인자는 없고 반환값이 있는경우                   ReadNum()
 4. 인자도 반환값도 없는경우                          HowToUseThisProg()

References  <열혈C프로그래밍> -윤성우 저 오렌지미디어  214page SmartAddFunc.c




[C언어] if ~else if 문의 switch case 문 변화

문제는 
if(n>=0 && n<10) printf("0이상 10미만\n");
else if(n>=10 && n<20) printf("10이상 20미만\n");
else if(n>=20 && n<30) printf("20이상 30미만\n");
else printf("30이상\n");

의 형태의 if...else if 문을 억지로 switch case문으로 바꿔보라는 이야기 였다.
case 문의 특성상 범위조절이 아닌 값을 의미하므로 나의 경우는 위의 그림과 같이 일일히 자연수 case 를 전부 넣었지만 솔루션은 이 방법이 아니였다. 
 물론 나의 코드 작성 방법에도 문제가 있는데, 입력받은 값이 (물론 정수로 선언하긴 하였지만) float형태(소수형태) 일 경우 가 성립하지 않을 수 있다는 것이다.

 솔루션에서는 switch(n/10)으로 10으로 나누어 문제를 해결했다.
10으로 나눌경우 정수형 선언이기에 나머지가 떨어져 나가므로, 
복잡하게 안하고, 주석처럼 case 0: case 1: case 2: default: 만으로 해결 할 수 있게 된다.

참조한 책은 200p 문제 08-3 윤성우 저자의 <열혈 C프로그래밍> 오렌지미디어. 이다.
정말 C프로그래밍 책에서 추천할 만 하며, 생각해볼 수 있게 잘쓰여진 좋은 책이다. 2학년때 사서 현재까지 붙잡고 있지만, 열심히 하자는 마음가짐에 C기초를 단단히 잡고 싶어 다시 시작 하였다. 
 굉장히 빠른 스피드로 진행해 나가다가, 이문제에서 막혀서 블로그에 글을 올린다. 나중에도 기억하고 싶어서.


2014년 12월 29일 월요일

C언어_How to Pop Up 'Hello World' as C language on Macbook with Xcode. (맥북에서 C언어로 'Hello World' 띄우기)

*If you want to learn programming language which is C language, You have to install compiler on Macbook. (My development environment is macbook air 2009 mid.)
The method which is easy is what you install 'Xcode'. 
1. You can download Xcode on 'App store'.
(앱스토어에서 Xcode를 다운로드 합니다.)

2. run Xcode. (Xcode를 실행합니다.)








This is icon of Xcode.(이것이 Xcode 아이콘 입니다.)

3. (Click) Create a new Xcode project (를 클릭합니다.)


















4. OS X - Application - Command Line Tool -Next (순서대로 클릭)













5. Decide project name and organization name. You can use defaults except project name. Language have to C
(프로젝트 이름을 정한다. Language는 C 여야 하며, 나머지는 default 값을 해도 된다.)












6. Decide location of your project, then click Create.
(프로젝트가 위치할 폴더를 정하고 Create 버튼을 누른다.)















7. There is example code. Red box is running button which runs compiler. 
(이렇게 예제 프로그램이 작성되어 있으며, 빨간상자를 누르면 컴파일 및 실행을 할 수 있습니다.)



8. There is the other method 'Product - Run' to run. 
(Product-Run, 혹은 Command+R은 컴파일 및 실행하는 또다른 방법입니다.)


9. If a result is 'Hello World!', There is correct. 
(아래에 Hello World!라는 결과가 나오면 옳게 된 것입니다.)