달력

52024  이전 다음

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

문제 : 길이 10인 배열을 선언, 숫자 입력하게 하여 아래처럼 나오게 하라.

 

풀이 : 함수의 인자로서 포인터 사용법, 배열과 포인터의 주소 접근법을 알면 풀 수 있다.

함수호출 및 종료조건도 잘 적어야 한다.

아래 메인에서는 배열입력 및 함수호출, 메뉴 종료조건을 다루고 있다.

 

 

아래 코드는 메인 함수 아래에 있는 짝수출력, 홀수출력 함수이다. 기본적으로 두 함수의 구조는 동일하다. 유일한 차이점은 호출대상이 짝수이냐, 홀수이냐며 코드상에서 숫자%2의 값이 0이냐 1이냐의 차이만 있다. 그러므로 둘 중 하나의 함수만 이해하면 된다. 홀수출력 함수만 살펴보겠다.

핵심은 배열의 각 원소에 접근하여 그 값이 조건식 (숫자%2==1)을 만족할 때에만 출력하게 하면 된다.

다만 동일한 조건식을 두 개 쓴 이유는 쉼표의 출력 때문이다.

 

 

이상으로 배열의 홀수출력, 짝수출력, 주소 포인터에 대해 알아보았다.

Posted by C언어 보이
|
  1. 아래에 정의된 함수에서 인자에 const를 쓴 이유는??

: 출력함수이므로 값을 변경할 일이 없다. 따라서 const를 쓴 것이다.

 

  1. 아래 showdata함수에서 지적할 만한 점은?

     

    : 출력함수인데 값 변경을 한다는 것이다. 값 변경 금지를 위해 ptr 포인터에 const를 붙였는데, 이를 ptr 포인터 값을 rptr에 대입한다고 해서 ptr의 속성까지 전달되는 아니다. 출력결과를 통해 이를 확인할 수 있다. 포인터 상수에 대한 문제이다.

     

    이상으로 const 선언에 대한 문제를 풀어보았다.

Posted by C언어 보이
|
  1. 인자의 제곱근 구하는 함수를 만들어라. 하나는 값 참조, 하나는 주소 참조의 형태로.

    : 함수의 사용법과 포인터의 정의를 알면 풀 수 있다.

 

 

  1. Swap3(&num1,&num2,&num3)의 형태로 함수를 만들고, num1값->num2에. Num2->num3, num3->num1에 되도록 하라.

: 일반적인 스왑함수이며, 단지 인자가 3개이며 포인터를 쓰면 된다.

이상으로 값 참조와 주소 참조에 관한 문제를 풀어보았다.

Posted by C언어 보이
|

이전부터 printf 인자에는 변수명(a),

scanf 인자에는 변수의 주소(&a)가 들어간 이유가 궁금했었다.

 

by Rajiv's View. all right reserved

 

 

함수와 포인터를 공부하면서 나름의 추리를 해 보았다.

아래 코드를 보자.

즉, newvalue함수는 메인에 있는 a의 주소가 필요없다. 다만 그 값만 필요하므로, 값 참조만 하면 된다. 따라서 호출 시 인자가 변수이름 이다.

printf함수 역시 a의 '값'만 출력하면 되므로 a의 주소는 필요가 없다. 따라서 호출시 인자가 변수이름 이다.

 

반대로, change함수는 a에 값을 대입하고자 한다. 따라서 인자로 &a의 주소가 필요하다.

마찬가지 이유로 scanf 함수 역시 인자로 &a의 주소가 필요하다.

 

 

 

 

 

 

Posted by C언어 보이
|

Type형 포인터에 +1하면, 포인터 변수값은 1*(type형 크기) 만큼 증가한다는 것은 잘 알 것이다.

그런데 포인터 값을 그냥 딱 1만 증가시킬 방법은 없을까??

있다.

포인터값->int형 변수에 대입->int형 변수를 1 증가->이 변수값을 다시 포인터에 대입.

그럼 *(포인터)하면 그 값은?? 출력된다.

*(원래 포인터)하면, 주소(포인터값)로부터 4바이트(형 크기)만큼 메모리 영역의 2진수를 읽는다.

참고로 값 예측은 메모리구조와 보수법을 알면 된다.

코드는 아래와 같다.

 

포인터 연산, 주소 1씩 증가시키기에 대하여 알아보았다.

 

 

Posted by C언어 보이
|

 

Temp를 사용한 일반적인 스왑 함수 대신에 다른 형태로 구현해 보았다.

결론부터 말하자면 최적화 측면에서 의미가 없다 (오히려 안 좋다).

일단 구현방법부터 살펴보자.

스왑함수에서 inum2의 값을 inum1으로 바꾼다 (*p2=n1).

Inum2의 기존 값은?? Inum2에서는 지워지지만, 이 것이 스왑함수의 매겨변수 n2에 들어있다.

따라서 이 n2의 값을 inum1에 넣어주면 된다. 다만 n2의 지역변수 이므로 swap의 반환형으로 전달하면 된다.

즉, n2의 값을 받은 swap의 반환형이 temp의 역할을 하는 셈이다.

얼핏 보면,

  1. 변수 하나를 덜 쓰는 것(temp) 처럼 보이지만, 인자가 하나 더 생겼으므로 (*p2) 사용하는 변수의 개수가 같다.
  2. 대입연산을 덜 하는 것 처럼 보이지만 오히려 더 한다.

    즉, Temp 초기화(선언 및 대입) 대신에 매개변수 p2초기화 (p2의 선언 및 &inum2를 대입)한다.

    또 이 p2의 값을 함수의 반환형에 대입 (int swap()=n2) 하므로 대입연산이 최소 4회 이루어진다.

     

 

이상으로 스왑함수의 다른 형태에 대해 알아보았다.

 

 

Posted by C언어 보이
|

Apple,banana,tomato라는 문자열들의 각 글자를 caStr에 넣어 출력을 하는 것이다.

아래 코드에서는 일일이 수동대입을 하고 있다. 개 노가다다ㅜㅜ

성실함은 인생을 불행하게 함으로. 아래 노가다 코드를 반복문으로 바꾸어 보자.

 

 

간단히 요약하면, '과일이름'이라는 문자열의 주소를 배열로 만들었다. 즉, 포인터 배열을 활용하였다.

* 포인터 배열을 쓰지 않고 하는 것이 훨씬 쉽다. 다만, 나름데로의 장점 (과일의 개수변동, 과일명칭 길이 변동 등에 대한 코드 수정이 용이)이 있어 이와 같이 하였다. 님이 초심자이거나 코드가 더러워서 어렵게 보인다면…apple문자 넣는 반복문, banana용 반복문, tomato용 반복문 등을 따로 따로 만들기를 강추!!!!! 하는 바이다. 그리고 fruit[]같은 과일 배열 (과일이름이 원소. 즉, 포인터 배열)을 안 써도 된다.).

다시 말하지만, 아래 코드는 해석하기 어려우므로 임산부나 초심자는 이쯤에서 포기해라 (이리 말해주면 승부욕 발동될 걸 잘 안다 ㅋ).

 

상세한 풀이는 아래와 같다.

  1. 특징 : Fruit[]이라는 배열에 과일명칭 문자열의 주소(cpApple,cpBanana,cpTomato)를 원소로 삽입한다.

    향후 과일이 추가될 때에는, 이 배열의 원소만 추가시키면 된다.

  2. 기본설명 : fruit[1]+fruitcharnum(0)은 "apple"의 'a'의 주소. fruit[1]+fruitcharnum(1) 은 "apple"의 'p'의 주소이다.
  3. 변수사용

    Straddrnow: 아래 반복문에서 casstr[]배열에 원소를 지정하기 위해서이다.castr[straddrnow]='글자' 식으로 쓴다.

    Fruitnow: 아래 반복문에서 caStr에 대입할 과일을 지정하는 수이다. Fruitnowp=fruit[fruitnowp]+fruitcharnum;

                                 castr[straddrnow]=*fuitnowp; 식으로 쓴다.

    Fruitnum : 과일의 개수. fruit[]배열의 길이가 자동으로 구해진다.

 

  1. 반복문
    1. if실행식 (문자대입식) : 맨 처음 fruitnow=0, fruitcharnow=0이다. 따라서, 'Fruitnowp=fruit[fruitnow]+fruitcharnum'에서 fruit[fruitnowp]가 fruit[1]의 된다. Fruit[1]은 "banana"의 주소(즉,'b'의 주소)이므로, if문 안에서 castr[0]에는 *(fruit[1]의 주소="banana"의 주소='b'의 주소)가 들어간다.
    2. 문자대입 조건 : if문은 ' *fruitnowp가 null 아닐 때'를 조건으로 한다. apple에서 e뒤에는 null 들이 있다. 따라서 e를 넣고 난 후에 다음 반복문 수행시에는 e다음의 널이 와서, else문을 수행하게 된다.
    3. Else 실행식 (대상과일 변경, 초기화): e다음에 널이 왔다는 것은 과일이름 하나를 다 넣었다는 것이다. 따라서 다음 과일로 넘어가기 위해 fuitnow++해주고 fruitcharnum=0을 해준다. 그러면, 반복문을 다음 수행할 때에는 if문을 수행하여 fruitnowp=fruit[fruitnowp=1]+fruitcharnum(=0)'이 된다. fruit[1]+fruitcharnum(0)은 "apple"의 'a'의 주소. fruit[1]+fruitcharnum(1) 은 "apple"의 'p'의 주소이다.

 

 

자, 이번에는 중간에 pineapple을 추가해 보자. 아래 그림에서와 같이 기존코드의 선언부에 pineapple문자열 포인터 추가, fruite 배열에 이를 추가. 하면 끝이다. 삽입 코드를 별도로 길게 작성할 필요가 없다!단,,, 워닝이 x라 많다..bb

  1. 출력 형태에 따라 이상한 버그 혹은 메시지가 뜬다 : "startup initialized natural state" 뭐 이런 메시지가 들어 있다.

 

프로그래밍을 처음 배우는 사람은 어려워 보일 수 있다. 하지만 차근차근 하다 보면, 감이 잡히게 될 거이다. 이상으로 과일이름 출력을 문자열,배열,포인터 배열, 반복문을 사용하여 해 보았다. 변수명 등은 댓글로 물어보고.

도움이 되었다 싶으시면 손가락을 꾹 눌러줄래??ㅎㅎ

Posted by C언어 보이
|

자기자신을 호출하는 함수로서, 종료조건(return 0 등)이 있어야 탈출할 수 있다.

하지만 과도한 사용은 cpu를 잡아먹게 된다. 일반적인 반복문의 경우보다 훨씬 심각하다.

아마도 재기된 지역변수 모두를 기억해야 하는 것이 그 이유로 보인다.

재귀함수, recursive 에 대해서 알아보았다.

Posted by C언어 보이
|
  1. 코드 영역 : 함수 및 상수가 저장 됌. main함수가 있는 곳이다. 프로그램의 실행명령이 있는 곳. 나머지 4영역들은 프로그램의 데이터가 있는 곳이다. RO (Read Only) 영역이라고도 하는데, 그 이유는 프로그램 실행 시에 데이터가 있는 영역의 값만 변경되고, 코드영역 자체의 값은 변경되지 않기 때문이다.
  • 함수의 메모리 주소는 있으나 상수의 메모리 주소는 없다
  1. 데이터 영역: 전역변수 중에 초기화가 된 변수들이 있는 곳이다. 전역변수 inum=1; Static int num=1;
  2. BSS 영역: 전역변수 중에 초기화가 안 된 변수들이 있는 곳이다. 전역변수 inum; Static int num;

주소를 출력해 보면 2번과 3번의 주소가 인접해 있으나 다른 영역임을 알 수 있다. 임베디드 에서는 심볼 0으로 초기화 되어 있다 하여 ZI (zero initialization)이라 부른다.

  1. 힙 영역: 동적할당 (추후 상세 설명)
  2. 스택 영역: 지역변수 (추후 상세 설명)

 

프로그램 실행명령 (아이콘 더블클릭) -> 코드 영역, 데이터 영역, BSS 영역들이 메모리에 복사되어 순차적으로 처리된다.

이 영역들의 데이타는 컴파일 단계에서 생성된다.

반면 힙 영역과 스택 영역들의 데이타는 실행과정에서 생성된다.

 

  • Static 변수 : 소속된 함수 내에서만 접근 가능하나, 그 외는 전역변수의 속성을 가진다. 즉, 이전 접근에서 변경한 값이 그대로 유지된다 (아래 코드에서 static 변수 inum1++ 참고).

 

이상으로 20140324 01 메모리 구조, 메모리 주소, 코드영역, 데이터영역, BSS 영역, 전역변수, static 변수에 대하여 알아보았다.

 

 

Posted by C언어 보이
|

 

  1. 반환형 : 'return (반환할 값)' 으로 쓴다. 아래 add 함수에서는 함수의 지역변수인 result의 값을 반환하고 있다('return result').

    즉, add(10,20)호출-> 'result =30=10+20'대입 -> return 30을 하여 add(10,20)에 30이 전달 됨 -> 이 것이 inum에 들어감.

    이 들어간 값이 int형이므로 함수 선언을 애추에 int add(int,int)라고 한 것이다. 앞에 int는 반환형, 괄호안에 있는 인자는 인자형(?).

    말자의 형이 아니라 인자의 형이란 뜻이다. 어차피 당신만 보는 글일텐데 좀 웃어달라. 성의를 생각해서.

  1. 함수의 지역 변수 : 위 add 함수에서 result가 지역변수이다. add함수에 들어와서야 선언되므로, 빠져나가면 없어진다. 즉, 밖을 나가는 순간 존재자치도 인지하지 못한다. 어렵게 말해서, 메모리 영역이 소멸된다. 다시 함수를 들어오면?? 처음 본 아이로 인식해서 다시 선언, 값 대입 된다.

    위의 showgood()함수 처럼 지역변수가 없는 함수도 있다. 왜?? 'good~'을 출력하는데에는 어떠한 변수도 필요치 않으므로 선언을 안 한 것이다.

 

  1. 지역변수의 특수한 경우 : 아래 반복문에도 지역변수가 존재한다. 바로 a. 이 아이도 반복문이 루프를 한 번 돌아서 다시 들어오면 처음 본 아이로 인지한다. 즉 중괄호를 빠져나간 즉시 지역변수인 a가 소멸되는 것이다.

 

이상으로 함수의 지역변수, 함수의 반환형에 대해 알아보았다.

Posted by C언어 보이
|