반응형

안녕하세요.

구글 애즈를 사용해서 게임 앱을 홍보해보았는데, 그 내용을 적어보려고 합니다.

일단 게임을 만들고 보니, 아무도 다운로드하지 않고 주변 지인들에게 홍보해야 겨우 다운로드 수가 조금씩 증가하기 시작했습니다.

검색을 통해 어떻게 게임을 홍보하는지 알아보았는데, 인터넷 커뮤니티(페이스북, 네이버 카페, 게임관련 사이트)나 오늘 다룰 구글 애즈로 홍보하는 방법이 있었습니다.

다음 유튜브 영상에서 확인했습니다.

 

일단 커뮤니티에서 홍보하려면 좀 시간을 두고 활동하면서 해야할 것 같아서, 그나마 빠르게 홍보할 수 있는 구글 애즈를 사용해보기로 했습니다.

마침 프로모션으로 3만원을 사용하면 10만 원 상당의 광고 크레디트를 제공해준다고 해서 일단 3만 원을 충전했습니다.

구글 애즈에 등록하기 위해서 이곳저곳 검색을 해서 확인했었는데, 쉽게 설명해주는 곳은 찾지 못했고, 공부를 많이 해야 할 것 같습니다. 

그래서 경험이라고 생각하고 간단하게 캠페인을 만들었습니다.

타겟 CPA는 100원, 타겟 국가는 아무래도 게임 자체가 영어를 지원하고, 광고단가가 저렴할 것이라고 예상해서 필리핀으로 설정하였습니다.

하루에 10,000원정도 사용할 수 있도록 하고, 2일 6시간 정도 홍보를 하였습니다.

일단 제가 좀 오해한게 타겟 CPA 100원으로 설정하면 앱 설치할 때마다 100원을 받는 게 아니라, 홍보 후 클릭단가에 따라 요금을 지불하는 것 같습니다.

클릭단가는 클릭할때 비용이고, 설치할지 안 할지는 단가에 영향을 받지 않는 것 같아 보였습니다.

그러니까 홍보이미지나 앱 설명을 잘해놓아야 클릭 후 사용자가 설치를 할 수 있을 것 같습니다.

일단 제가 만든 게임은 틀린그림찾기 게임인데, 필리핀에서 클릭단가는 10원 정도였고, 시간 지나니까 8원 9원 정도로 떨어지기도 했는데 최종적으로 10원 정도였습니다.

18,000원 정도 사용했으며, 노출은 9만 5천, 클릭수는 1천8백 정도에 게임 다운로드는 70 정도 올라갔습니다.

총 통계 자료를 보니, 1번 설치될 때 250원 정도 사용되는 것 같습니다.

이건 게임이나 홍보영상이나 홍보 이미지에 따라 다르니 참고만 하시면 될 것 같습니다.

아무래도 무료인 커뮤니티 홍보라 고해도 커뮤니티에 글 올리고, 홍보글 만드는 것도 시간을 써야 하는 작업이니까 설치단가는 그나마 저렴한 편이었던 거 같습니다.

설치 후 애드몹에서 광고 수익을 확인해보았습니다.

하지만..  광고 수익은 0.02달러였습니다.

단순 계산으로 1달러당 1천 원으로 봤을 때 20원였습니다.

광고의 효과는 거의 없었다고 볼 수 있었습니다.

설치 후 거의 재설치도 없는 것 같고, 홍보 끝난 후 거의 접속하는 유저가 없었습니다.

조금 더 많이 광고를 해서 일정 수준 이상 다운로드 수가 증가한다면 더욱 광고수익을 크겠지만, 게임 자체가 너무 단순해서 유저의 재유입을 기대할 수 없었기 때문에 조금 더 콘텐츠를 보충해서 재광 고를 해야겠습니다.

 

 

반응형
반응형

안녕하세요.

오늘은 오브젝트를 따라다니는 HP UI를 만들어 보도록 하겠습니다.

 

 

오브젝트 생성 및 위치 설정

1. 메인 카메라 위치 설정

2. Cube 오브젝트(움직일 오브젝트) 생성 및 위치는 0, 0, 0으로 설정하고 Material을 추가하여 큐브색을 변경합니다.

3. Slider 오브젝트(HP바) 생성 및 설정

1) Handle Silde Area는 비활성화

2) 배경 및 채울색 설정

 

 

스크립트 추가

Cube에 스크립트를 추가합니다.

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
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
 
public class Mover : MonoBehaviour
{
    private GameObject m_goHpBar;
    private float m_fSpeed = 5.0f;
    void Start()
    {
        m_goHpBar = GameObject.Find("Canvas/Slider");
    }
 
    void Update()
    {
        // 테스트를 위한 키보드 이동 시작
        float fHorizontal = Input.GetAxis("Horizontal");
        float fVertical = Input.GetAxis("Vertical");
 
        transform.Translate(Vector3.right * Time.deltaTime * m_fSpeed * fHorizontal, Space.World);
        transform.Translate(Vector3.up * Time.deltaTime * m_fSpeed * fVertical, Space.World);
        // 테스트를 위한 키보드 이동 끝
 
 
        // 오브젝트에 따른 HP Bar 위치 이동
        m_goHpBar.transform.position = Camera.main.WorldToScreenPoint(transform.position + new Vector3(00.8f, 0));
    }
}
 
cs

 

 

 

반응형
반응형

안녕하세요

오늘은 유니티에서 진동을 울리는 방법에 대해 알아보도록 하겠습니다.

퍼즐게임에서 퍼즐을 잘못찾았거나 여러가지 경고를 띄울 때 주로 진동을 울리는 경우가 많이 있습니다.

이럴때 사용하는 진동을 유니티에서도 호출할 수 있습니다.

 

진동 울리는 함수

Handheld.Vibrate();

진동이 울려야 할 위치에 위의 함수를 호출하면 진동이 1초간 울립니다.

 

진동 세부설정

Handheld.Vibrate() 함수를 이용하면, 울리는 시간을 설정할 수 없고 1초간 진동이 울리는 것만 가능합니다.

1초말고 진동울리는 시간과 울리는 패턴 설정할 수 있습니다.

안드로이드 자바 클래스를 사용합니다.

사용하려면 진동권한이 필요합니다.

진동권한 추가를 위해서 매니페스트 수정이 필요합니다.

C:\Program Files\Unity\Editor\Data\PlaybackEngines\AndroidPlayer\Apk

이 폴더에서 AndroidManifest.xml파일을 해당 프로젝트 폴더의 Asset\Plugins\Android\에 넣습니다.

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
<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.unity3d.player"
    xmlns:tools="http://schemas.android.com/tools"
    android:installLocation="preferExternal">
    <supports-screens
        android:smallScreens="true"
        android:normalScreens="true"
        android:largeScreens="true"
        android:xlargeScreens="true"
        android:anyDensity="true"/>
 
    <application
        android:theme="@style/UnityThemeSelector"
        android:icon="@mipmap/app_icon"
        android:label="@string/app_name">
        <activity android:name="com.unity3d.player.UnityPlayerActivity"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <meta-data android:name="unityplayer.UnityActivity" android:value="true" />
        </activity>
    </application>
    <uses-permission android:name="android.permission.VIBRATE" />
</manifest>
 
 
cs

VIBRATE권한을 맨 밑에 </application>와 </manifest>사이에 넣으면 됩니다.

1
2
<uses-permission android:name="android.permission.VIBRATE" />
 
 
cs

 

다음 클래스를 추가한 후 사용하면 됩니다.

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
using System.Collections;
using UnityEngine;
 
public static class Vibration
{
#if UNITY_ANDROID && !UNITY_EDITOR
    public static AndroidJavaClass AndroidPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
    public static AndroidJavaObject AndroidcurrentActivity = AndroidPlayer.GetStatic<AndroidJavaObject>("currentActivity");
    public static AndroidJavaObject AndroidVibrator = AndroidcurrentActivity.Call<AndroidJavaObject>("getSystemService""vibrator");
#endif
    public static void Vibrate()
    {
#if UNITY_ANDROID && !UNITY_EDITOR
        AndroidVibrator.Call("vibrate");
#else
        Handheld.Vibrate();
#endif
    }
 
    public static void Vibrate(long milliseconds)
    {
#if UNITY_ANDROID && !UNITY_EDITOR
        AndroidVibrator.Call("vibrate", milliseconds);
#else
        Handheld.Vibrate();
#endif
    }
    public static void Vibrate(long[] pattern, int repeat)
    {
 
 
#if UNITY_ANDROID && !UNITY_EDITOR
        AndroidVibrator.Call("vibrate", pattern, repeat);
#else
        Handheld.Vibrate();
#endif
    }
 
    public static void Cancel()
    {
#if UNITY_ANDROID && !UNITY_EDITOR
            AndroidVibrator.Call("cancel");
#endif
    }
 
}
 
cs

 

실제 사용 예제

위 스크립트를 Assets폴더에 추가를 합니다.

빈오브젝트를 생성해서 버튼 이벤트에 사용할 스크립트를 추가합니다.

ButtonEvent 스크립트를 다음과 같이 작성합니다.

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
32
33
34
35
36
37
38
39
40
41
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class ButtonEvent : MonoBehaviour
{
    public void OnClick1()
    {
        Vibration.Vibrate((long)5000);
    }
 
    public void OnClick2()
    {
        long[] pattern = new long[4];
        pattern[0= 1000;
        pattern[1= 200;
        pattern[2= 1000;
        pattern[3= 200;
 
 
        Vibration.Vibrate(pattern, 1);
    }
 
    public void OnClick3()
    {
        long[] pattern = new long[4];
        pattern[0= 1000;
        pattern[1= 5000;
        pattern[2= 2000;
        pattern[3= 1000;
 
 
        Vibration.Vibrate(pattern, -1);
    }
 
    public void OnClick4()
    {
        Vibration.Cancel();
    }
}
 
 
cs

 

1. OnClick1() 함수는 5초동안 진동을 울립니다.

2. OnClick2() 함수는 1초쉬고 0.2초 울리고, 1초 쉬고, 0.2초 울린 후 1초에 한번씩 1초 진동을 반복합니다.

3. OnClick3() 함수는 1초쉬고 5초 울리고, 2초 쉬고, 1초 울린 후 반복되지 않습니다.

4. OnClick4() 함수는 진동 울리는 도중에 진동을 취소합니다.

그 후 버튼을 다음과 같이 4개 추가해서 추가합니다.

버튼에 OnClick1~onClick4를 다음과 같이 넣습니다.

Button에 OnClick1을 넣습니다.

Button (1)에 OnClick2을 넣습니다.

Button (2)에 OnClick3을 넣습니다.

Button (3)에 OnClick4을 넣습니다.

버튼을 누를 때마다 해당되는 이벤트가 실행되는 것을 확인할 수 있습니다.

그리고 검색하다가 Android 8.0(API 레벨 26)이상에서는 다르게 작업을 해야한다고 작업을 해야한다고 찾았는데, 갤럭시 S8(안드로이드 9.0)에서 테스트 했을 때 진동이 안울렸습니다.

혹시나 특정 최신 휴대폰에서 진동이 울리지 않는다면, 다음 웹페이지를 참조하시는 것도 좋을 것 같습니다.

https://gist.github.com/munkbusiness/9e0a7d41bb9c0eb229fd8f2313941564

 

Vibration for Unity3d with Android native Call that supports both the new vibrationEffectClass and the old simple vibrate, with

Vibration for Unity3d with Android native Call that supports both the new vibrationEffectClass and the old simple vibrate, with fallback to Handlheld.Vibrate(). - Vibration.cs

gist.github.com

안드로이드의 vibrate함수 사용은 다음 웹페이지에서 확인할 수 있습니다.

https://developer.android.com/reference/android/os/Vibrator#vibrate(long[],%20int)

 

Vibrator  |  Android 개발자  |  Android Developers

Vibrator public abstract class Vibrator extends Object java.lang.Object    ↳ android.os.Vibrator Class that operates the vibrator on the device. If your process exits, any vibration you started will stop. Summary Public methods abstract void cancel() Turn

developer.android.com

틀린 부분이나 제가 잘못 올린부분은 댓글을 남겨주시면 수정하도록 하겠습니다.

 

반응형
반응형

안녕하세요.

 

오늘은 for문을 이용해서 다양한 형태로 별찍기를 해보겠습니다.

 

for문을 이해하는데 도움이 될 것 같아서 올려봅니다.

 

5개씩 출력되게 별찍기

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
void main()
{
    int i = 0, j = 0;
 
    for ( i = 0; i < 5; i++ )
    {
        for ( j = 0; j < 5; j++ )
            printf("*");
        printf("\n");
    }
}
cs

 

별이 순차적으로 커지게 별찍기

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
void main()
{
    int i = 0, j = 0;
 
    for ( i = 0; i < 5; i++ )
    {
        for ( j = 0; j <= i; j++ )
            printf("*");
        printf("\n");
    }
}
cs

 

순차적으로 작아지게 별찍기

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
void main()
{
    int i = 0, j = 0;
 
    for ( i = 0; i < 5; i++ )
    {
        for ( j = 0; j < 5-i; j++ )
            printf("*");
        printf("\n");
    }
}
cs

 

공백추가해서 별찍기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>
void main()
{
    int i = 0, j = 0, k = 0;
 
    for ( i = 0; i < 5; i++ )
    {
        for ( k = 0; k < i; k++ )
        {
            printf(" ");
        }
        for ( j = 0; j < 5-i; j++ )
            printf("*");
        printf("\n");
    }
}
cs

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>
void main()
{
    int i = 0, j = 0, k = 0;
 
    for (i = 0; i < 5; i++)
    {
        for (k = 1; k < 5-i; k++)
        {
            printf(" ");
        }
        for (j = 0; j < i+1; j++)
            printf("*");
        printf("\n");
    }
}
 
cs

 

역삼각형으로 별찍기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
void main()
{
    int i = 0, j = 0, k = 0;
 
    for ( i = 0; i < 5; i+=2 )
    {
        for ( k = 0; k < i; k+=2 )
        {
            printf(" ");
        }
        for ( j = 0; j < 5-i; j++ )
            printf("*");
        printf("\n");
    }
}
 
cs

 

모래시계모양으로 별찍기

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
#include <stdio.h>
void main()
{
    int i = 0, j = 0, k = 0;
 
    for ( i = 0; i < 5; i+=2 )
    {
        for ( k = 0; k < i; k+=2 )
        {
            printf(" ");
        }
        for ( j = 0; j < 5-i; j++ )
            printf("*");
        printf("\n");
    }
 
    for ( i = 3; i > 0; i-=2 )
    {
        for ( k = 1; k < i; k+=2 )
        {
            printf(" ");
        }
        for ( j = 0; j <= 5-i; j++ )
            printf("*");
        printf("\n");
    }
}
 
cs

 

입력에 따른 모래시계 만들기

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
32
33
34
35
36
37
#include <stdio.h>
void main()
{
    int i = 0, j = 0, k = 0;
    int nNum = 0;
 
    printf("size(odd number:1,3,5,7..) : ");
    scanf("%d"&nNum);
 
    if( nNum % 2 == 0 )
    {
        printf("error : even number\n");
        return;
    }
 
    for ( i = 0; i < nNum; i+=2 )
    {
        for ( k = 0; k < i; k+=2 )
        {
            printf(" ");
        }
        for ( j = 0; j < nNum-i; j++ )
            printf("*");
        printf("\n");
    }
 
    for ( i = nNum-2; i > 0; i-=2 )
    {
        for ( k = 1; k < i; k+=2 )
        {
            printf(" ");
        }
        for ( j = 0; j <= nNum-i; j++ )
            printf("*");
        printf("\n");
    }
}
 
cs

 

나비(리본)모양으로 별찍기

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
32
#include <stdio.h>
void main()
{
    int i = 0, j = 0, k = 0, l = 0, m = 0;
 
    for (i = 0; i < 5; i ++)
    {
        for (j = 0; j <= i; j ++)
             printf("*");
        for (k = 1; k < 5 - i; k++)
            printf(" ");
        for (l = 1; l < 5 - i; l++)
            printf(" ");
        for (m = 0; m <= i; m++)
            printf("*");
        printf("\n");
    }
 
    for (i = 1; i < 5; i++)
    {
        for (j = 0; j < 5 - i; j++)
            printf("*");
        for (k = 1; k <= i; k++)
            printf(" ");
        for (l = 1; l <= i; l++)
            printf(" ");
        for (m = 0; m < 5 - i; m++)
            printf("*");
 
        printf("\n");
    }
}
 
cs
반응형
반응형

안녕하세요.

배열처럼 사용할 변수를 미리 넉넉하게 할당해두고, 사용할 수도 있지만, 

메모리를 얼마나 사용할지 모르는 상황에 있을 때, 미리 너무 많이 선언에 놓으면 메모리 낭비가 일어날 수 도 있습니다.

이럴 때 동적으로 메모리를 할당하여 사용할 수 도 있습니다.

malloc

함수 원형
void* malloc(size_t _Size);

헤더 파일
stdlib.h

리턴값
void* 형은 어떤 타입으로도 변화되므로, 포인터 값만 가진 변수정도로 이해하면 좋을 것 같습니다.
리턴 받은 포인터로 필요한 타입( 예:pCh = (char*)malloc(sizeof(char)*5); )으로 캐스팅한 후 사용하면 됩니다.


설명
필요한 크기를 동적으로 할당하여 사용합니다.

데이터 크기에 맞춰서 할당해줘야 하므로 
"(데이터타입*)malloc(sizeof(데이터타입)*할당크기);"형식으로 할당합니다.

할당 메모리는 반드시 free함수를 통해 메모리 해제를 해야합니다.

 

free


함수 원형
void malloc(void* _Block);

헤더 파일
stdlib.h

리턴값
리턴값은 없습니다.

설명
malloc함수로 동적한 메모리를 해제할 떄 사용합니다.

 

예제

1. malloc과 free 사용 예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
#include <stdlib.h>
 
void main()
{
    int* pPoint;
    pPoint = (int*)malloc(sizeof(int)*5);
 
    pPoint[0= 25;
    pPoint[1= 45;
    pPoint[2= 50;
    pPoint[3= 70;
    pPoint[4= 99;
    
    int i = 0;
    for ( i = 0; i < 5; i++ )
        printf("pPoint[%d] : %d\n", i, pPoint[i]);
 
    free(pPoint);
}
 
cs

결과값

설명

malloc함수를 이용해 int형으로 5개를 할당하였습니다.

배열과 같은 형식을 대괄호로 접근 가능합니다.

free함수를 통해 할당해제를 해야합니다.

 

2. 할당할 사이즈를 입력받아 동적할당하는 예제

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
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
 
void main()
{
    int* pPoint;
 
    int nCount = 0;
 
    printf("malloc size ?? ");
    scanf("%d"&nCount);
 
    pPoint = (int*)malloc(sizeof(int* nCount);
 
    int i = 0;
    for (i = 0; i < nCount; i++)
    {
        printf("input pPoint[%d] : ", i);
        scanf("%d"&pPoint[i]);
    }
 
    for (i = 0; i < nCount; i++)
        printf("Output pPoint[%d] : %d\n", i, pPoint[i]);
 
    free(pPoint);
}
 
cs

결과값

설명

scanf함수를 통해 동적할당 개수를 입력 받은 후 개수 만큼 입력 받은 후 출력을 해줍니다.

반응형
반응형

안녕하세요.

C언어에서 특정 문자열를 검색하는 함수인 strstr에 대해 알아보겠습니다.

 

strstr


함수 원형
char* strstr(const char *_Str, const char *_SubStr);

헤더 파일
string.h

리턴값
_SubStr문자열과 같은 값을 가진 _Str문자열의 포인트값을 리턴해줍니다.
_Str에 _SubStr와 동일한 문자열이 없다면, NULL을 리턴합니다.

설명
문자열의 첫번째 문자부터 마지막 문자까지 검색을 해서 같은 문자열을 찾은 후 처음 찾은 포인터를 리턴합니다.
만약에 찾을 대상 문자열에 같은 값을 가진 문자열이 여러개 있어도 처음 찾은 포인터만 리턴하게 됩니다.


예제

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
#include <string.h>
 
void main()
{
    char arrString[20= "Hello World";
    
    char* pCh1 = strstr(arrString, "llo");
    char* pCh2 = strstr(arrString, "rle");
 
    printf("strstr(arrString, ""llo"") : %s\n", pCh1);
    printf("strstr(arrString, ""rle"") : %s\n", pCh2);
}
 
cs

결과값

문자열 배열 arrString("Hello World")에서

8번째 줄 코드(char* pCh1 = strstr(arrString, "llo");)에서는 "llo"문자열을

strstr함수를 통해 찾는데, "Hello World"의 세번째 문자부터 다섯번째 문자가

동일한 문자열이 된다.

그러므로 리턴값은 세번째 문자 포인터값을 가지게 되므로 "llo World"가 출력이 됩니다.

 

9줄 코드(char* pCh2 = strstr(arrString, "rle");)에서는

"rle"문자열을 "Hello World"문자열에서 찾는데, 비슷하게 맞는 문자열은 있지만, 

정확하 동일한 문자열을 찾을 수 없습니다. 

그러므로 null이 리턴되게 됩니다.

 

반응형
반응형

안녕하세요.

오늘은 C언어에서 문자를 검색하는 함수인 strchr 함수에 대해 알아보도록 하겠습니다.

strchr

함수 원형
char* strchr(const char *_Str, int _Val);

헤더 파일
string.h

리턴값
_Val와 같은 값을 가진 _Str문자열의 포인트값을 리턴해줍니다.
_Str에 _Val와 같은 값이 없다면 NULL을 리턴합니다.


설명
문자열의 첫번째 문자부터 마지막 문자까지 검색을 해서 처음 찾은 포인터를 리턴합니다.
만약에 찾을 대상 문자열에 같은 값을 가진 문자가 여러개 있어도 처음 찾은 포인터만 리턴하게 됩니다.


예제

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
#include <string.h>
 
void main()
{
    char arrString[20= "Hello World";
    char *pCh1 = strchr(arrString, 'o');
    char *pCh2 = strchr(arrString, 'a');
 
    printf("strchr(arrString, 'W') : %s\n", pCh1);
    printf("strchr(arrString, 'a') : %s\n", pCh2);
}
 
cs

코드분석

7번째 줄에서(char *pCh1 = strchr(arrString, 'o');)는 arrString[20] 문자열 "Hello world"값 중 'o'를 찾게되면 "Hello World"의 다섯번째 문자를 포인터를 리턴하게 됩니다.

그로인해서 pCh1은 다섯번째 문자의 포인터값을 받아서 출력을 하게되면 다섯번째 문자부터 '\0'이전 값까지 출력이 됩니다.

 

8번째 줄에서(char *pCh2 = strchr(arrString, 'a');)는 arrString[20]값중 'a'를 가진 값이 없기 때문에 NULL값을 리턴하게 됩니다.

 

간단한 응용

간단하게 문자열에 특정 문자가 몇개가 있는지 확인하는 프로그램을 만들어보겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>
#include <string.h>
 
void main()
{
    char arrString[20= "Hello World";
    int nCount = 0;
    char* pCh = arrString;
 
    while (pCh)
    {
        pCh = strchr(pCh, 'o');
        if (pCh)
        {
            pCh++;
            nCount++;
        }
    }
 
    printf("find count : %d", nCount);
}
 
cs

코드분석

8번째 줄(char* pCh = arrString;)에서 arrString의 시작 주소를 포인터인 pCh로 저장합니다.

12번째 줄(pCh = strchr(pCh, 'o');)에서 strchr함수를 이용해서 'o'문자 찾습니다.

찾은 후 그 위치를 pCh에 저장합니다.

그리고 찾은 위치의 포인터에 1을 더해서 다음 포인터를 저장합니다.

찾았기 때문에 nCount를 1증가시킵니다.

 while문에 pCh값이 null이 아니기 때문에 반복문으로 다시 한번 더 strchr함수를 이용해서 'o'를 찾습니다.

찾은 후 다시 pCh에 값을 저장합니다.

pCh와 nCount를 1씩 증가시킨 후 다시 while문으로 반복하여 'o'문자 찾습니다.

이제 더이상 'o'문자가 없기 때문에 strchr함수에서 null을 리턴하게 되면서 while문을 빠져나오게 됩니다.

반응형
반응형

안녕하세요.

오늘은 C언어에서 문자열의 길이를 알아내는 함수인 strlen 함수에 대해 알아보도록 하겠습니다.

 

strlen

함수 원형
size_t strcat(const char *_Str);

헤더 파일
string.h

리턴값
_Str문자열의 길이가 리턴됩니다.

설명
문자열의 길이가 리턴됩니다.
문자열의 크기로 혼동될 수 있는데, 길이 입니다.
문자열의 데이터 중 '\0'값 이전값까지 문자열 길이를 리턴합니다.

예제

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
#include <string.h>
 
void main()
{
    char arrString1[10= "Hello";
    char arrString2[10= "Worl\0d!!";
    
    printf("arrString1 len : %d\n", strlen(arrString1));
    printf("arrString2 len : %d\n", strlen(arrString2));
}
 
cs

 

 

 

strlen는 해당 문자열의 크기가 아니라 길이를 리턴합니다.

arrString1[10]은 크기가 10이지만 길이는 "Hello"이렇게 5문자가 됩니다.

간혹 혼란이 많이 생기는 부분입니다.

참고로 문자열 배열의 크기를 알아내는 함수는 sizeof()입니다.

 

arrString2 문자열의 경우에는 "worl\0d!!\0"을 데이터로 갖고 있습니다.

strlen함수를 이용하여 길이를 확인하면 4가 리턴됩니다.

함수자체내에서 문자를 하나씩 '\0'(NULL)값을 체크하면서 카운트를 한 후

'\0'일 경우에는 해당 카운트를 리턴해주는 것으로 보입니다.

 

strlen 응용

 strcat함수와 같이 응용하는 코드를 한번 만들어보겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#define _CRT_SECURE_NO_WARNINGS        // vs2017 이후 버전은 strcat함수 실행시 보안 에러발생으로 인해 추가합니다.
#include <stdio.h>
#include <string.h>
 
void main()
{
    char arrString1[20= "Hello";
    char arrString2[20= "";
 
    scanf("%s", arrString2);
    while (getchar() != '\n');
 
    int nLength = strlen(arrString1) + strlen(arrString2) ;
 
    if (sizeof(arrString1) > nLength)
    {
        strcat(arrString1, arrString2);
        printf("arrString1 : %s\n", arrString1);
    }
    else
    {
        printf("Error over size \n");
    }
}
cs

"12345678901234" 입력 시 다음과 같이 출력이 됩니다.

arrString1을 크기가 20으로 되어있어서, "Hello"(5)와 "12345678901234"(14)를 합치더라도 크기가 넘치지 않습니다.

다음 "123456789012345" 입력 시에는 다음과 같이 출력되게 됩니다.

"Hello"(5)와 "123456789012345"(15)이므로 '\0'까지 포함하게되면 크기가 넘치므로,

else문의 "Error over size"를 호출하게 됩니다.

반응형
반응형

안녕하세요.

오늘은 C언어에서 문자열을 붙이는 함수인 strcat와 strncat 함수에 대해 알아보도록 하겠습니다.

strcat

함수 원형
char* strcat(char *_Destination, const char *_Source);

헤더 파일
string.h

리턴값
_Destination의 포인터값이 리턴됩니다.

설명
특정 문자열을 붙입니다.
첫번째 매개변수인 _Destination문자열에 두번째 매개변수인 _Source문자열을 넣습니다.
두 문자열을 합친 크기가 _Destination의 크기보다 작아야합니다.

예제

1
2
3
4
5
6
7
8
9
10
11
12
#define _CRT_SECURE_NO_WARNINGS        // vs2017 이후 버전은 strcat함수 실행시 보안 에러발생으로 인해 추가합니다.
#include <stdio.h>
#include <string.h>
void main()
{
    char arrString1[20= "Hello";
    char arrString2[20= "World!!";
 
    strcat(arrString1, arrString2);
 
    printf("%s\n", arrString1);
}
 
cs

arrString1의 \0(NULL)값 위치에 arrString2가 붙게됩니다.

 

strncat

함수 원형
int strncmp( char *_Destination, const char *_Source, size_t count);

헤더 파일
string.h

리턴값
_Destination의 포인터값이 리턴됩니다.

설명
특정 문자열을 특정 크기만큼 붙입니다.
첫번째 매개변수인 _Destination문자열에 두번째 매개변수인 _Source문자열 count만큼 붙입니다.
count는 _Destination의 크기보다 같거나 작아야합니다.

예제

1
2
3
4
5
6
7
8
9
10
11
12
#define _CRT_SECURE_NO_WARNINGS        // vs2017 이후 버전은 strncat함수 실행시 보안 에러발생으로 인해 추가합니다.
#include <stdio.h>
#include <string.h>
 
void main()
{
    char arrString1[20= "Hello";
    char arrString2[20= "World!!";
 
    strncat(arrString1, arrString2, 5);
    printf("%s\n", arrString1);
}
 
cs

arrString1의 \0(NULL)값 위치에 arrString2의 문자를 5개(world)까지 붙여 넣습니다.

그리고 끝에는 \0(NULL)값이 붙습니다.

 

반응형
반응형

안녕하세요.

오늘은 문자열을 숫자로 변경하는 함수에 대해 알아보도록 하겠습니다.

atoi, atol

함수 원형
int atoi(const char* _String);
int atol(const char* _String);

헤더 파일
stdlib.h

설명
문자열(char*)을 정수(int)로 변환하기 위해 사용됩니다.

리턴값
_String 문자열을 정수로 리턴됩니다.

정수로 변환될 수 없는 문자인 경우에는 0이 리턴됩니다. ex) "AA"
정수 + 정수로 변환될 수 없는 문자일 경우 정수로 리턴됩니다.(ex) "78a" -> 78, "78.2"->78
_String값이 정수최대값 보다 크면, INT_MAX값(2147483647)을 리턴해주고 정수최소(-2147483648)값보다 작으면, INT_MIN값을 리턴합니다.

 

예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>
#include <stdlib.h>>
 
void main()
{
    int nReturn1 = atoi("78");
    int nReturn2 = atoi("78a");
    int nReturn3 = atoi("a78");
    int nReturn4 = atoi("AA");
    int nReturn5 = atoi("123456789012345678");
    int nReturn6 = atoi("-123456789012345678");
 
    printf("atoi(""78"") return value : %d\n", nReturn1);
    printf("atoi(""78a"") return value : %d\n", nReturn2);
    printf("atoi(""a78"") return value : %d\n", nReturn3);
    printf("atoi(""AA"") return value : %d\n", nReturn4);
    printf("atoi(""123456789012345678"") return value : %d\n", nReturn5);
    printf("atoi(""-123456789012345678"") return value : %d\n", nReturn6);
}
 
cs

결과값

 

atof

함수 원형
double atof(const char* _String);

헤더 파일
stdlib.h

설명
문자열(char*)을 실수(double)로 변환하기 위해 사용됩니다.

리턴값
_String 문자열을 실수로 리턴됩니다.

실수로 변환될 수 없는 문자인 경우에는 0.0이 리턴됩니다. ex) "AA"
실수 + 실수로 변환될 수 없는 문자일 경우 정수로 리턴됩니다. ex)"78.5a"
부동소수점e,E로 표현 가능합니다. ex) "1232323E20"

예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
#include <stdlib.h>>
 
void main()
{
    double dbReturn1 = atof("78.5");
    double dbReturn2 = atof("78.5a");
    double dbReturn3 = atof("a78");
    double dbReturn4 = atof("AA");
    double dbReturn5 = atof("1232323E20");
 
 
    printf("atoi(""78"") return value : %lf\n", dbReturn1);
    printf("atoi(""78a"") return value : %lf\n", dbReturn2);
    printf("atoi(""a78"") return value : %lf\n", dbReturn3);
    printf("atoi(""AA"") return value : %lf\n", dbReturn4);
    printf("atoi(""123456789012345678"") return value : %E\n", dbReturn5);
}
 
cs

 

결과값

반응형
반응형

안녕하세요.

오늘은 C언어에서 문자열을 비교할 수 있는 함수인 strcmp와 strncmp 함수에 대해 알아보도록 하겠습니다.

strcmp

함수 원형
int strcmp( const char *string1, const char *string2);

헤더 파일
string.h

설명
두 문자열을 비교합니다.
string1과 string2 두 문자열을 비교합니다.

리턴값
리턴값이 -1 일 때 -> 두 문자열을 비교하여, 틀린 첫번째 문자가 string1이 더 작을 때 -1을 리턴합니다.
리턴값이 0 일 때 -> 두 문자열이 같습니다.
리턴값이 1 일 때 -> 두 문자열을 비교하여, 틀린 첫번째 문자가 string1이 더 클 때 1을 리턴합니다.

예제

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>
#include <string.h>
 
void main()
{
    char arrString1[20= "world!!";
    char arrString2[20= "worlc!!";
    char arrString3[20= "worlf!!";
    char arrString4[20= "world!!";
 
    int nReturn1 = strcmp(arrString1, arrString2);
    int nReturn2 = strcmp(arrString1, arrString3);
    int nReturn3 = strcmp(arrString1, arrString4);
 
    
    printf("strcmp(%s, %s) return : %d\n", arrString1, arrString2, nReturn1);
    printf("strcmp(%s, %s) return : %d\n", arrString1, arrString3, nReturn2);
    printf("strcmp(%s, %s) return : %d\n", arrString1, arrString4, nReturn3);
}
 
cs

 

10번째 줄은 "world!!"와 "worlc!!"를 비교합니다. "worl"까지는 같다가 'd'와 'c'가 다른데

'd'가 'c'가 아스키코드상의 10진수 상수로 봤을 때에는 68과 67이기 때문에 d가 더 큽니다.

매개변수 string1과 string2중에 string1이 더 크면 1이 리턴되기 때문에 strcmp(arrString1, arrString2)에서는 1이 리턴됩니다.

 

 

11번째 줄은 "world!!"와 "worlf!!"를 비교합니다. 여기도 "worl"까지는 같다가 'd'와 'f'가 다릅니다.

'd'와 'f'는 아스키코드상의 10진수 상수로 봤을 때, 68과 70이기 때문에 d가 작습니다.

매개변수 string1과 string2중에 string1이 더 작으면 -1이 리턴되기 때문에 strcmp(arrString1, arrString3)는 -1이 리턴됩니다.

 

 

12번째 줄은 두 값이 같기 때문에 0이 리턴됩니다.

 

 

strncmp

함수 원형
int strncmp( const char *string1, const char *string2, size_t count);

헤더 파일
string.h

설명
지정한 사이즈 만큼 두 문자열을 비교합니다.
string1과 string2 두 문자열을 count만큼 비교합니다.

리턴값
리턴값이 -1 일 때 -> 두 문자열을 count까지 비교하여, 틀린 첫번째 문자가 string1이 더 작을 때 -1을 리턴합니다.
리턴값이 0 일 때 -> 두 문자열이 count까지의 문자열이 같습니다.
리턴값이 1 일 때 -> 두 문자열을 count까지 비교하여, 틀린 첫번째 문자가 string1이 더 클 때 1을 리턴합니다.

예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>
#include <string.h>
 
void main()
{
    char arrString1[20= "world!!";
    char arrString2[20= "worlc!!";
    char arrString3[20= "worlf!!";
    char arrString4[20= "worldd!!";
 
    int nReturn1 = strncmp(arrString1, arrString2, 5);
    int nReturn2 = strncmp(arrString1, arrString3, 5);
    int nReturn3 = strncmp(arrString1, arrString4, 5);
 
 
    printf("strncmp(%s, %s, 5) return : %d\n", arrString1, arrString2, nReturn1);
    printf("strncmp(%s, %s, 5) return : %d\n", arrString1, arrString3, nReturn2);
    printf("strncmp(%s, %s, 5) return : %d\n", arrString1, arrString4, nReturn3);
}
 
cs

11번째 줄(strncmp(arrString1, arrString2, 5))에서는 "world!!"와 "worlc!!"의 5개 문자까지 비교합니다.

그러므로 "!!"는 빠지고 "world"와 "worlc"만 비교하게 됩니다.

"worl"까지는 서로 같기 때문에 "d"와 "c"로 리턴 값이 결정되는데, 아스키 코드로 봤을 때는 'd'가 더 큰 값을 가집니다.

매개변수 string1과 string2중 string1의 값이 더크면 1을 리턴하게 되는데, 

strncmp(arrString1, arrString2, 5)에서는 arrString1값이 더 크기 때문에 1을 리턴하게 됩니다.

12번째 줄에서는 "world!!"와 "worlf!!"의 5개 문자까지 비교합니다.

그러므로 "!!"는 빠지고 "world"와 "worlf"만 비교하게 됩니다.

"worl"까지는 서로 같기 때문에 "d"와 "f"로 리턴 값이 결정되는데, 아스키 코드로 봤을 때는 'd'가 더 작은 값을 가집니다.

매개변수 string1과 string2중 string1의 값이 더 작으면 -1을 리턴하게 되는데, 

strncmp(arrString1, arrString3, 5)에서는 arrString1값이 더 작기 때문에 -1을 리턴하게 됩니다.

13번째 줄에서는 "world!!"와 "worldd!!"의 5개 문자까지 비교합니다.

문자열 전체로 봤을 때는 다른 문자열이지만, 5개 문자까지만 비교하기 때문에, 각각 "!!"와 "d!!"는 비교 대상에서 제외가 됩니다.

그러므로 둘은 똑같이 문자열로 비교되어 strncmp(arrString1, arrString4, 5)은 0이 리턴됩니다.

반응형
반응형

안녕하세요.

오늘은 문자열을 복사하는 함수인 strcpy와 strncpy에 대해 알아보도록 하겠습니다.

 

strcpy

함수 원형 
char * strcpy (char *_Dest, const char *_Source);


헤더 파일
string.h


설명  
문자열을 복사를 합니다. 
복사할 문자열(_Source) 변수 크기는 복사될 문자열(_Dest) 변수보다 작거나 같아야 합니다.(종료 null문자 포함)

복사할 문자열(_Source)의 '\0'까지 복사됩니다.


반환 값
_Dest 포인터 값이 반환됩니다.

예제

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
#include <string.h>
 
void main()
{
    char arrString[20= "Hello world!!";
    char arrDestString[20= "TEST";
    strcpy(arrDestString, arrString);
 
    printf("arrString : %s\n", arrString);
    printf("arrDestString : %s\n", arrDestString);
}
 
cs

 

다음과 같이 널까지 그대로 스트링 복사가 됩니다.

 

strncpy

함수 원형 
char * strncpy (char *_Dest, const char *_Source, size_t _Count);

헤더 파일
string.h

설명  
문자열을 _Count만큼 복사를 합니다. 
지정한 크기만큼만 복사합니다.

_Count크기는 _Dest의 데이터 크기보다 작거나 같아야합니다.

반환 값
_Dest 포인터 값이 반환됩니다.

예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
#include <string.h>
 
void main()
{
    char arrString[20= "Hello world!!";
    char arrDestString[20= "TEST";
    
    strncpy(arrDestString, arrString, 2);
 
    printf("arrString : %s\n", arrString);
    printf("arrDestString : %s\n", arrDestString);
}
 
 
cs

 

arrString의 앞에 두글자(H,e)만 복사가 되게 됩니다. 

근데 이렇게 하면 문제가 생길 수 있습니다.

만약에 6번쨰줄에 arrDestString가 초기값이 없이, 

char arrDestString[20];

이렇게만 선언되어 있는 상태에서 strncpy가 된다면 어떻게 될까요??

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
 
void main()
{
    char arrString[20= "Hello world!!";
    char arrDestString[20];
 
    strncpy(arrDestString, arrString, 2);
 
    printf("arrString : %s\n", arrString);
    printf("arrDestString : %s\n", arrDestString);
}
 
cs

결과값은 다음과 같이 됩니다.

원하는 결과는 "He"만 복사되어야하는데, "He"가 복사가 되었지만, 먼가 이상한 깨진 글자가 나오고 Hello world!!가 나오네요..

문제는 He를 복사하고 '\0'(null) 문자끝을 나타내는 널이 없기 때문에 출력할 때 이런 문제가 발생하는 겁니다.

다음과 같이 코드를 수정할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
 
void main()
{
    char arrString[20= "Hello world!!";
    char arrDestString[20];
 
    strncpy(arrDestString, arrString, 2);
 
    arrDestString[2= '\0';
 
    printf("arrString : %s\n", arrString);
    printf("arrDestString : %s\n", arrDestString);
}
 
cs

10번줄에 "arrDestString[2= '\0';" 코드를 추가하였습니다.

결과값은 다음과 같이 원하던대로 "He"만 출력되게 됩니다.

반응형
반응형

안녕하세요.

오늘은 C언어의 구조체에 대해 알아보도록 하겠습니다.

 

구조체

여러 변수들을 하나로 뭉쳐 관리가 편하게 접근할 수 있게 하는 것이 구조체입니다.

형식

struct 구조체명
{
    데이터타입 변수명1;
    데이터타입 변수명2;
           :
           :
} 구조체변수명;

예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
#include <string.h>
#pragma warning(disable: 4996) // VS2019 일떄 필요합니다.
void main()
{
    struct Student
    {
        char sName[10];
        int nAge;
        char sAddress[32];
    }student;
    
    strcpy(student.sName,"AAAAA");
    student.nAge = 10;
    strcpy(student.sAddress,"Seoul, Republic of Korea");
 
    printf("student.sName : %s\n", student.sName);
    printf("student.nAge : %d\n", student.nAge);
    printf("student.sAddress : %s\n", student.sAddress);
}
 
cs

구조체의 필요성

만약에 다음과 같은 학생 정보에 대한 데이터가 있는 코드가 있습니다.

char sName[5][10];
int nAge[5];
char sAddress[5][32];

구조체를 사용하지 않아도, 배열로 데이터를 관리할 수 있습니다.
프로그램을 유지보수하게 되어 학생정보가 아닌 선생님정보가 추가해야하거나
교직원 정보를 추가해야한다면 다음과 같이 코드를 만들어야 할 것 입니다.

char sStudentName[5][10];
int nStudentAge[5];
char sStudentAddress[5][32];
char sTeacherName[5][10];
int nTeacherAge[5];
char sTeacherAddress[5][32];
char sSchoolstaffName[5][10];
int nSchoolstaffAge[5];
char sSchoolstaffAddress[5][32];

이렇게 되면 가독성이 현저히 떨어지기 때문에 구조체로 관리하는게 조금 더 수월하게 관리할 수 있을 것 입니다.

 

typedef

보통 구조체를 정의하고 사용하려면 다음과 같이 코드를 작성해야합니다.

struct Student
{
    char sName[10];
    int nAge;
    char sAddress[32];
};

struct Student student;

struct가 구조체란 뜻이 되므로 struct를 구조체이름과 같이 붙여야 구조체를 선언할 수 있습니다. 

typedef를 사용하면 struct를 붙이지 않고 구조체를 선언할 수 있습니다. 

다음과 같이 정의합니다.

typedef struct Student
{
    char sName[10];
    int nAge;
    char sAddress[32];
}STUDENT;

STUDENT student;

이때 STUDENT은 구조체 데이터가 아니라 struct Student를 대신하는 이름이 됩니다.

 

구조체 멤버 참조

구조체 멤버 참조는 "."(도트)연산자를 이용해서 참조합니다.

 

구조체 포인터

포인터 변수를 이용해서 구조체를 포인터로 접근할 수 있습니다.

포인터 변수를 참조할 때에는 "->"(에로우)연산자를 이용해서 참조합니다.

다음과 같이 참조합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>
#include <string.h>
#pragma warning(disable: 4996// VS2019 일떄 필요합니다.
 
void main()
{
    typedef struct Student
    {
        char sName[10];
        int nAge;
        char sAddress[32];
    }STUDENT;
 
    STUDENT student;
    STUDENT* pStudent = &student;
    strcpy(pStudent->sName, "AAAAA");
    student.nAge = 10;
    strcpy(student.sAddress, "Seoul, Republic of Korea");
 
    printf("student.sName : %s\n", pStudent->sName);
    printf("student.nAge : %d\n", pStudent->nAge);
    printf("student.sAddress : %s\n", pStudent->sAddress);
}
 
cs

pStudent->sName 대신 (*pStudent).sName를 사용할 수도 있습니다.

 

자기참조 구조체

구조체 멤버변수는 어떠한 타입도 가능하다. 다른 구조체 타입도 가능하다.

자기 자신은 포인트 형태로 가질 수 있다.

typedef struct Student
{
    char sName[10];
    int nAge;
    char sAddress[32];
    struct Student* stu;
}STUDENT;

 

구조체의 메모리 배치 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
#include <string.h>
 
void main()
{
    typedef struct Player
    {
        char sName[3];
        int nJob;
        char chType;
        int nAge;
        short shPoint;
    }PLAYER;
 
    PLAYER student;
    printf("student size : %d\n"sizeof(PLAYER));
}
 
cs

다음과 같이 구조체의 사이즈를 확인해보면 20이 나옵니다.

데이터 타입으로 계산하면 sName(3) + nJob(4) + chType(1) + nAge(4) + shPoint(2) = 14가 나와야하는데 이상합니다.

구조체 변수의 메모리 배치는 4의 배수 단위로 배치됨으로 인해 

sName(4) + nJob(4) + chType(4) + nAge(4) + shPoint(4) = 20 으로 계산이 됩니다.

그러므로 다음과 같이 수정해야 구조체 사이즈를 줄일 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
#include <string.h>
 
void main()
{
    typedef struct Player
    {
        char sName[3];
        char chType;
        short shPoint;
        int Job;
        int nAge; 
    }PLAYER;
 
    PLAYER student;
    printf("student size : %d\n"sizeof(PLAYER));
    
}
 
cs

이렇게 구현하면 sName(3) + nJob(1) + shPoint(4) + chType(4) + nAge(4) = 16 됩니다.

작은 사이즈의 변수타입부터 넣고 큰 사이즈 변수를 넣는게 사이즈를 줄일 수 있는 방법입니다.

반응형
반응형

안녕하세요.

오늘은 C언어의 함수에 대해 알아보도록 하겠습니다.

함수

함수(Function)를 뜻을 영어사전에서 찾아보면, 기능이라는 뜻이 됩니다.

C언어에서도 기능을 따로 분리해서 코딩을 할 수 있습니다.

우리가 자주 사용하는 printf가 대표적인 예가 될 수 있습니다.

출력하는 기능을 이용하고 싶은데 printf에 들어있는 코드들을 모두 main함수에 넣을 수는 없기 때문입니다.

형식

반환자료형 함수명(매개변수1, 매개변수2)
{
    구문;
    return 반환값;
}

반환할 자료형(int, float등)을 정하고 매개변수에 값을 넣어서 함수에 전달해줍니다.

함수가 종료되기 전에 return으로 값을 반환합니다.

반환자료형이 void라면 return 값이 필요없습니다.

예제

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
 
void printA(int nNum)
{
    printf("printA : %d\n", nNum);
}
 
void main()
{
    int nNum = 5;
    printA(nNum);
}
cs

printA라는 함수를 만들었습니다.
매개변수에 nNum값을 넘겨주면 "printA : 5"가 출력이됩니다.

함수는 main함수보다 윗줄에 코딩하거나 아니면 다음과 같이 선언을 하고 main함수 아래에 정의할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
 
void printA( int nNum );
void main()
{
    int nNum = 5;
    printA(nNum);
}
 
void printA( int nNum )
{
    printf("printA : %d\n", nNum);
}
cs

 

매개변수 전달

- 매개변수로 값 전달

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
 
int Plus(int nNum1, int nNum2)
{
    return nNum1 + nNum2;
}
 
void main()
{
    int nNum1 = 5;
    int nNum2 = 8;
 
    printf("Plus(%d, %d) : %d", nNum1, nNum2, Plus(nNum1, nNum2));
}
 
cs

Plus함수에 5,8값을 매개변수로 전달해서 덧셈한 후 리턴합니다.

- 매개변수로 주소 전달

매개변수로 값을 전달하고 함수안에서 값을 변경해봅시다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
 
int Plus(int nNum1, int nNum2)
{
    nNum1 = 10;
    return nNum1 + nNum2;
}
 
void main()
{
    int nNum1 = 5;
    int nNum2 = 8;
 
    printf("Plus(%d, %d) : %d", nNum1, nNum2, Plus(nNum1, nNum2));
}
 
cs

Plus함수내에서 매개변수를 변경을 하면 덧셈연산 후 리턴값은 변경 되지만, nNum1값은 변경한 10이 아닌 그대로 5입니다.

함수내에서 값을 변경하면 매개변수 값도 변경되게 하려면 어떻게 하면 될까요??

주소값을 매개변수로 전달하면 됩니다.

주소를 나타내는 "&"을 붙여서 매개변수를 전달합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
 
int Plus(int* nNum1, int* nNum2)
{
    *nNum1 = 10;
    return *nNum1 + *nNum2;
}
 
void main()
{
    int nNum1 = 5;
    int nNum2 = 8;
 
    printf("Plus(%d, %d) : %d", nNum1, nNum2, Plus(&nNum1, &nNum2));
}
 
cs

포인터 변수로 주소값으로 매개변수 값을 전달하면 nNum1 값을 5에서 10으로 변경하면 값이 변경되는 것을 확인할 수 있습니다.

반응형
반응형

안녕하세요.

오늘은 포인터에 대해 알아보도록 하겠습니다.

 

포인터

단순히 포인터라는 단어의 뜻만 보면, 무언가를 가리키는 것 정도의 의미가 되는데,

C언어에는 주소 값을 가리키기 위한 형식을 뜻하게 됩니다.

메모리 공간의 주소값을 가리킬 수 있기 때문에 동적 메모리 할당에 많은 이점을 가질 수 있게 됩니다.

형식

데이터타입* 포인터 변수명;

포인터 변수명 = &변수;

*포인터 변수 = 변수;

- 데이터 타입* 포인터 변수명;
데이터 타입에 "*"을 붙이면 포인터 변수가 됩니다.
메모리 공간은 타입에 상관없이 4바이트를 차지하게 됩니다.

- 포인터 변수명 = &변수;
변수에 주소라는 의미인 "&"를 변수 앞에 넣어서 포인터 변수에 주소 값을 대입할 수 있습니다.

- *포인터 변수 = 변수;
포인터 변수를 선언할 때는 "*"가 포인터 변수 타입이라는 것을 나타내지만 대입할 때에는 가리키는 값이라는 코드가 됩니다.
포인터 변수에 일반 변수 값을 대입하기 위해서는 포인트 변수 앞에 "*"를 넣어 변수를 대입합니다.

예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
 
void main()
{
    int* p;
    int nNum = 5;
    p = &nNum;                    // nNum의 주소값을 p에 저장합니다.
    printf("*p = %d\n"*p);    // p의 가르키는 값을 출력합니다.
    printf("nNum = %d\n", nNum);// nNum 값을 출력합니다.
    printf("==================\n");
    *= 10;                    // p가 가르키는 값 10으로 변경합니다.
    printf("*p = %d\n"*p);    // p의 가르키는 값을 출력합니다.
    printf("nNum = %d\n", nNum);// nNum 값을 출력합니다.
    printf("==================\n");
    nNum = 15;
    printf("*p = %d\n"*p);    // p의 가르키는 값을 출력합니다.
    printf("nNum = %d\n", nNum);// nNum 값을 출력합니다.
}
 
cs

 

배열과 포인터

배열에 인덱스를 적지 않고 쓴다면 포인터변수와 마찬가지로 사용할 수 있게됩니다.

예제

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
 
void main()
{
    int arrNum[5= {1,2,3,4,5};
    
    int i;
    for ( i = 0; i < 5; i++ )
        printf("%d\n"*(arrNum+i));
}
cs

코딩 팁

보통은 포인터변수 초기값을 null(널)값으로 설정합니다.

짧은 코드에서는 상관이없지만, 코드가 많아지면 포인터 변수에 주소값을 대입하는걸 깜빡하게 될 수 있어서 체크하는 코드를 넣어야합니다.

다음과 같이 사용합니다.

1
2
3
int* pNum = null; 
if(pNum != null) 
    *pNum = 5;
cs

 

주소 값 변화를 확인하는 방법(VS 2019)

1. F5키 또는 메뉴 - 디버그 - 디버깅 시작을 누릅니다.

2. 메뉴 - 디버그 - 창 - 메모리 - 메모리 로 메모리 창을 엽니다.

다음과 같은 창이 생깁니다.

변수에 "&"를 앞에 넣어서(예를들면 "&nNum")를 주소에 넣고 엔터를 누릅니다.

그럼 해당 변수에 해당되는 주소로 이동합니다.

디버깅하면서 한스탭씩 넘어가는 것(F10)을 확인 합니다.

변수값이 변하면 주소에 해당하는 변수가 변경되는 것을 확인할 수 있습니다.

반응형

+ Recent posts