[C언어] puts,fputs, gets, fgets,

문자열을 출력할때 쓰는 puts, fputs 함수.


puts 함수는 자동으로 줄바꿔줌.

fputs 함수는 아님. 그래서 fputs("\n", stdout); 로 한줄 띄우기.



문자열 입력 할 때 쓰는 gets, fgets 함수.


fgets를 쓰도록 하자. 왜냐하면. gets를 쓰면미리 할당해 놓은 배열보다 큰 길이의 문자열을 입력받으면 오버플로우 발생.


fgets(str, sizeof(str), stdin);



 



문자열을 12345678999 넣으면
123456789 까지만 출력됨.

fgets함수는 입력받을 수 있는 최대 문자열의 길이 n을 초과하는 문자열이 입력되는 경우에는
n-1까지의 문자만 입력 받고, 마지막에 NULL 문자를 삽입해준다.



[C언어] 포인터, const 키워드

const 키워드를 포인터 앞에 붙이면  포인터를 상수화 한다.


포인터 자체를 상수화.

포인터가 가리키는 변수를 상수화.


이 두가지 의미가 있다.



1. 포인터가 가리키는 변수의 상수화.


int a = 10;

const int* p = &a;

*p = 30 ; //안됨.

a = 30;   //가능.


포인터 p가 가리키는 변수의 값을 못 바꾸게 하겠다는 의미.

a자체가 상수화 되는 것이 아니고, 포인터 p를 통해서 변수 a값을 변경하는 것을 막는다.


2. 포인터 상수화


int a = 10;

int b = 20;

int* const p = &a;

p = &b;  // 오류

*p = 30; //된다.


포인터 p가 지니는 주소 값을 변경 할 수 없다는 뜻이다.




따라서, 포인터도 상수화 시키고, 포인터가 가리키는 데이터도 상수화하려면?


const int* const p = &a;



void print(const int* ptr)
{

int *p = ptr;    //에러.

}


ptr은 const 키워드에 의해서 상수화 되어있다.

이는 print 함수 내에서 ptr이 가리키는 변수의 조작을 허용 않겠다는 의미.

따라서, int* 로의 대입이 허용되지 않는다.



[C언어] 문자열 상수, 포인터 배열 함수

문자열 상수


char str1[5] = "abcd";    //문자열 변수

char *str2 = "ABCD";     //문자열 상수


배열 str1은 문자열 전체를 저장.

포인터 str2는 메모리상에 저장되어 있는 문자열 상수 "ABCD"를 단순히 가리키고만 있음.


문자열 상수는 메모리 공간이 할당되면, 문자열 상수의 주소 값을 반환한다.


문자열을 입력받을땐


scanf("%s", str) 로 str앞에 &를 붙이지 않는다.

왜냐하면은 배열 이름 str은 배열의 주소를 나타내므로, & 연산을 할 필요가 없기 때문이다.





int ArrAdder(int* pArr, int n);


int main(void)
{

int arr[10] = ...;

int sumOfArray;


sumOfArray = ArrAdder(arr, sizeof(arr) / sizeof(int) );

}



sizeof(arr) / sizeof(int) ==> 배열 요소의 개수.



int arr[5 ] ==> sizeof(arr) ==> 20 출력됨

int* pArr = arr; ==> sizeof(pArr) ==> 포인터 이기에 int 형인 4 출력됨.


일반적으로 배열을 인자로 전달받는 함수의 경우, 대부분 배열의 길이도 함께 전달받도록 구현해야한다!



int function(int pArr[]){ }

int function(int* pArr){ }


선언 int pArr[] 와 int *pArr은 완전히 같은 것이다.


다만 인자를 배열로 전달하는 것을 좀 더 명확하게 할 수 있도록 int pArr[] 선언을 허용하는 것이다. 즉, 함수의 매개 변수로 선언한때만 가능!


int main(void)
{

int pArr[] ;//안된다! 함수의 매개 변수로 선언한때만 가능!

}


하지만 매개 변수 선언시에도 int *arr와 같은 선언을 주로 사용하자.


[C언어] 재귀적 함수 호출, n!(Factorial 계산)

재귀적 함수 호출


함수 내에서 자기 자신을 다시 호출하는 형태이다.


재귀적 함수 호출은 부담스럽지만 어렵고 복잡한 문제를 쉽게 해결 할 수 있다.

자료구조와 알고리즘에서는 빠질 수 없는 개념.


n! 팩토리얼 계산.


#include <stdio.h>

int f(int n);


int main(void)
{

int val, result;


printf("정수 입력 : ");

scanf("%d", &val);


if(val < 0)
{

printf("0 이상을 입력해야 합니다. \n");

return 1;

}


result = f(val);    //팩토리얼 계산.

printf("%d!의 계산결과 : %d \n", val, result);

return 0;

}


int f(int n)
{

if(n == 0) //n이 0이면 1을 반환
    return 1;

else      // 아니면 n* (n-1)을 반환.

return n*f(n-1);

}

[C언어] static 변수, register 변수

static 변수


특성이 전역변수와 비슷하다.

메모리 공간을 할당받고 초기화가 이루어지면, 프로그램이 종료될 때까지 소멸되지도 않고 초기화도 두 번 다시 일어나지 않는다.

단, 지역내에서만 접근을 허용한다.


void Add(int a, int b)
{

static int val = 0;

val +=a+b;

}


static 변수는 한번만 초기화 되므로, static int val =0 ; 이것은 딱 한번만 실행된다. 두번째 Add 함수 호출 부터는 실행되지 않는다.


프로그램이 실행되는 동안에 계속해서 유지되어야 한다.

그러나, 접근 영역이 한정되어 특정 지역에서만 사용한다면 전역변수를 쓰지말고 static 변수를 사용한다.



register 변수


int a;

register int b; //레지스터 변수 b 선언.


CPU의 '레지스터'라는 메모리 영역에 저장된다. 레지스터는 CPU의 접근이 가장 빠른 메모리 공간이다. 따라서 변수 a보다 b가 빠르게 처리된다.


그러나 regsiter 변수의 선언은 명령이 아니라 요청에 가깝다. 왜냐하면 register라는 선언은 무시될 수도 있기 때문이다.

CPU의 레지스터는 그 크기가 제한되어 있는 메모리 공간이다. 따라서 이 공간에 변수를 할당하는 것이 여의치 않을 경우 이러한 요구는 충분히 무시될 수 있다.


생성과 소멸이 빈번한 변수를 register 변수로 선언하게 되면 많은 성능의 향상을 기대할 수 있다.

그러나 register 변수의 선언과 관련해서 고민할 필요는 없다. 대부분 컴파일러가 알아서 붙여준다.





[C언어] printf, scanf, %e, %E

printf


printf 이름의 맨 끝 f는 formatted(서식화된)을 의미한다. 즉, 출력의 양식을 스스로 결정지어 출력한다는 의미이다.


%e, %E


3.1245e+2 or 2.45e-4


'부동소수점 표현 방식' 이라는 것이며, 흔히 공학용 수지 계산에서 많이 사용되는 방법이다.



double d1 = 1.23e-3; //0.00123

double d2 = 1.23e-4; //0.000123

double d3 = 1.23e-5; //0.0000123


출력되는 필드 폭 지정하기.


%4d  => 필드 폭을 4칸 확보하고, 오른쪽 정렬. /    값/

%-4d => 필드 폭을 4칸 확보하고, 왼쪽 정렬.   /값    /



scanf


실수를 입력받기 위해서는 서식 문자 %f, %le (scanf에 사용할땐 %e가 아니다.) 를 사용.


[C언어] 리터럴(literal) 상수, 심볼릭(Symbolic) 상수

리터럴(literal) 상수


덧셈이라는 연산은 CPU에 의해서 진행이 된다.

CPU는 메인메모리상(RAM)에 존재하는 데이터들만 조작(연산)할 수 있다.


int val = 30 +40


30, 40이라는 정수가 메모리 공간에 상수로서 저장이 된다.

30, 40 처럼 변수와 달리 이름이 없는 상수를 가리켜 '리터럴(literal) 상수'라고 한다.



심볼릭(Symbolic) 상수 


이름을 지니는 상수로 표현하는 방법에는 const 키워드를 이용하는 방식과 매크로를 이용하는 방식 2가지가 있다.


const 키워드 + 자료명 상수


선언과 동시에 초기화 해야만 한다.


int형을 char형으로 바꿀때 일어나는 현상.

char형은 1바이트. int형은 4바이트이다. 이때 char형으로 대입하기 위해 '상위 비트의 손실'이 발생한다.

상위 3바이트를 단순히 버려버린다.





[C언어] sizeof 연산자, double형, unsigned

sizeof 연산자

sizeof 연산자는 단항 연산자로서 피연산자의 메모리 크기를 반환한다.


int val = 10;

printf("%d", sizeof val);

printf("%d", sizeof(int));


피연산자로 자료형의 이름이 올경우에는 괄호를 반드시 넣어줘야한다.

편하게 생각하여 무조건 sizeof() 괄호를 넣어서 사용하도록한다.

잊지 말아야할 것은sizeof는 함수가 아닌 연산자 라는 것이다.


double형


보편적인 실수형 자료형 double형이다.

과거에는 float형이었지만 너무 정밀도가 낮아서(소수 이하 6자리) 정밀도가 높은 double형(소수 이하 15자리)을 보편적으로 사용한다.



double형으로 데이터를 입력받는 경우 서식문자 %f가 아닌 L의 소문자 l 을 덧붙인 %lf이다.

%fdouble형이 아닌 실수형에 사용된다. double형인데 %f값으로 받으면 엉뚱한 값을 받는다.


%d => 정수형

%c => 문자로 출력

%lf => double형

%f  => double형이 아닌 실수형.



unsigned 


기본 자료형 앞에 unsigned를 붙이는 경우 MSB(Most Significant Bit)까지도 데이터의 크기를 표현하는데 사용하므로 데이터의 표현 범위가 양의 값으로 두 배가 된다. 

예) char => -127~128. unsigned char => 0~255 (127 + 128)



MSB(Most Significant Bit) ?

가장 중요한 비트라는 뜻으로 정수를 표현하는데 있어서 가장 왼쪽에 존재 비트이다.

이 비트는 부호를 표현하며 양수라면 '0', 음수라면 '1'을 표시한다. 이 비트 값에 따라서 값의 크기가 전혀달라지므로 가장 중요한 비트이다.


기본 자료형 중에서도 정수형 자료형(char, short, int...) 에만 붙일 수 있다. 실수형 자료형에는 붙일 수 없다.


아스키 코드?

아스키 코드는 범위가 0~127까지이다.


대문자 A => 65. 소문자 a => 97. 대문자가 더 값이 작다. 대문자와 소문자의 값의 차는 32이다.





 

Keystore파일을 이용하여 커맨드창에서 APK 서명하기

Keystore파일을 이용하여 커맨드창에서 APK 서명하기


난독화를 한 후 만들어진 apk가 서명되지 않은 상태여서, 빠르고 쉽게 커맨드를 이용하여 apk 서명하는 방법을 찾아서 포스팅합니다.


먼저 apk에 서명이 되어있는지 여부를 확인합니다. APK가 있는 폴더로 이동하여 커맨드 창을 열고 아래 명령어를 입력.


jarsigner -verify <어플이름>.apk



서명이 안되어있으면 아래와 같은 결과가 표시됩니다.


no manifest.

jar is unsigned. <signatures missing or not parsable>


서명이 된 상태라면


jar verified.


로 표시됩니다.



서명이 되어있지 않은 것을 확인했다면, 이제 서명을 할 차례입니다.


명령어는 


jarsigner -verbose -keystore <keystore파일> <서명되지 않은 apk파일> <서명되어 나올 파일 이름.apk>


ex> jarsigner -verbose -keystore gyu.keystore unsigned_gyu.apk signed_gyu.apk


이대로 signed_gyu.apk를 업로드 하려고하면 "Zip 정렬되지 않은 APK를 업로드했습니다." 라는 경고 문구가 뜨고 업로드가 되지 않습니다.  서명한 apk를 재정렬해야만 합니다.


Android SDK가 깔린 폴더로 이동합니다. Android SDK\tools 폴더에서 커맨드창을 열고,


zipalign -v 4 <정렬안된 서명된 apk> <정렬되어나올 완벽한 apk>


ex>zipalign -v 4 signed_gyu.apk gyu.apk



이제  gyu.apk를 플레이 스토어에 업로드 하면 끝~!










[C++] 선행처리자에 대한 이야기( 매크로 함수 #define, const 상수, 인라인 함수 inline)

컴파일하는 과정


프로그래머가 작성한 소스파일은 가장 먼저 소스파일에 대한 처리를 하는 선행처리기를 거치고, 컴파일 되어 오브젝트 파일이 생성되고, 다시 링커에 의해 실행파일이 된다.



선행처리를 위한 명령에는#define,, #undef, #include, #if, #ifdef, #elif, #else 등

맨 앞에 #기호가 붙는다는 공통점이 있다.


함수 외부에 기술하며, 다른 소스파일들과는 독립적으로 수행된다. 억지로 취소하지 않는 한 그 효과는 지정한 곳부터 끝까지이다. 선행처리에 합당한 적업을 통해 원시코드의 내용을 변경한다.


#include의 경우에는 이 이후에 나오는 파일을 찾아 그 파일에 기술된 모든 내용을 현재 파일의 #include가 기술된 부분에 넣어준다.



매크로 상수 #define 


상수만 기술하며, 프로그램의 명확성을 증대시켜 주는 효과가 있다.


Ex >  #define PI 3.141592 


+ 단점(2018.01.04)


1. 선행 처리자가 상수로 바꾸어 버리기 때문에, 시호 테이블에 들어가지 않음.

따라서 에러메시지엔 3.141592 값인 숫자만 표기되고, 어디서 에러가 발생했는지 모르므로 혼란을 야기함. 


2. 코드 크기가 증가한다.

선행처리자가 상수 값으로 치환하기 때문에 코드 크기가 커진다.


const 상수


#define문 보다 더 쉽게, 안전하게 상수를 만드는 방법!


변수 선언을 초기화와 함께하고 자료형 앞에 const 키워드를 덧붙여서 상수를 정의할 수 있다. 키워드 const를 덧붙인다는 것과 초기값을 반드시 주어야 한다는 것에 주의 해야한다. const 상수는 변수 선언시 준 초기값이 영원히 그 변수의 값이 된다.



인라인 함수 Inline 함수


주로 짧은 명령어로 구성하고! (길면 비효율적) => 실행 속도가 증가합니다! Inline 함수는 매크로 함수와 유사한 기능을 가진 함수이다. 인라인 함수를 호출하면 컴파일할 때 호출하는 부분에 인라인 함수를 대치한다.


사용 방법

inline  자료형 함수이름 (매개변수 리스트)

{
}


함수 머리 부분의 자료형 앞에 inline이라는 예약어만 추가적으로 기술하면 된다.


속도 증가의 이유는?


일반 함수의 경우 함수의 호출이 일어나면 그 함수를 찾아가서 수행을 하고 다시 되돌아와야 한다. 정의된 함수에 프로그램 로직이 들어 있기 때문.

매크로 함수의 경우 치환될 문장이 함수 부분에 대치되므로 코드 양이 많아지기는 하지만 함수를 찾아 가서 수행하고 돌아오는 번거로움이 없다.