OpenCV 픽셀 접근 속도 테스트

픽셀단위에 접근하여 연산할 때 가장 어떤 방법이 가장 빠른가?

결론 :

  • 순차처리
    • atFunc : 2.0873msec.
    • dataPtr : 1.4164msec.
    • ptrFunc : 1.1877msec.
    • ptr++ : 0.2126msec.
  • 병렬처리
    • parallel_for dataPtr : 0.393msec.
    • parallel_for ptr: 0.2211msec.
    • parallel_for Optimize: 0.0557msec.
```cpp

#include <iostream>
#include <stdio.h>
#include "opencv2/opencv.hpp"
#include <ppl.h>

int main()
{
    //화면을 표시할 윈도우 설정
    std::string wndName = "Color Test";
    namedWindow(wndName, cv::WINDOW_NORMAL);
    cv::setWindowTitle(wndName, "Color Test");

    //mnms이미지 불러오기
    cv::Mat OriginImg = cv::imread("../images/mnms.png",cv::IMREAD_GRAYSCALE);
    cv::Mat TestImg = OriginImg;

    //원본 이미지 출력
    cv::imshow(wndName, OriginImg);
    cv::waitKey(0);
    cv::destroyWindow(wndName);

    //이미지의 모든 픽셀을 순회할 때 소요된 시간을 측정해본다.

    //시작,종료 시간을 기록하기 위한 timer
    cv::TickMeter tm;

#pragma region atFunc
    tm.reset();
    tm.start();
    for (int y = 0; y < TestImg.rows; ++y)
    {
        for (int x = 0; x < TestImg.cols; ++x)
        {
            uchar val = TestImg.at<uchar>(y, x);
            TestImg.at<uchar>(y, x) = val + 1;
        }
    }
    tm.stop();
    std::cout << "atFunc : " << tm.getTimeMilli() << "msec." << std::endl;
#pragma endregion

#pragma region dataPtr
    tm.reset();
    tm.start();

    uchar* pTestImg = TestImg.data;
    for (int y = 0; y < TestImg.rows; ++y)
    {
        for (int x = 0; x < TestImg.cols; ++x)
        {
            uchar val = pTestImg[TestImg.rows * y + x];
            pTestImg[x] = val + 1;
        }
    }
    tm.stop();
    std::cout << "dataPtr : " << tm.getTimeMilli() << "msec." << std::endl;
#pragma endregion

#pragma region ptr
    tm.reset();
    tm.start();

    for (int y = 0; y < TestImg.rows; ++y)
    {
        //Test이미지의 행의 시작 주소를 가져옴
        uchar* pImg = TestImg.ptr<uchar>(y);

        //행의 시작에서 하나씩 증분하여 한 행의 끝까지 데이터 탐색
        for (int x = 0; x < TestImg.cols; ++x)
        {
            uchar val = pImg[x];
            pImg[x] = val + 1;
        }
    }
    tm.stop();
    std::cout << "ptrFunc : " << tm.getTimeMilli() << "msec." << std::endl;
#pragma endregion

#pragma region ptr++
    tm.reset();
    tm.start();

    for (int y = 0; y < TestImg.rows; ++y)
    {
        //Test이미지의 행의 시작 주소를 가져옴
        uchar* pSrc = TestImg.ptr<uchar>(y);

        //Test이미지의 행의 마지막 주소를 가져옴
        uchar* pSrc_end = pSrc + TestImg.cols;

        //한행의 끝이 나올때까지 반복
        for (; pSrc < pSrc_end;)
        {
            uchar val = *pSrc;
            //후치 연산자로 val값 업데이트 후 포인터 위치변경
            *pSrc++ = val + 1;
        }
    }  
    tm.stop();
    std::cout << "ptr++ : " << tm.getTimeMilli() << "msec." << std::endl;
#pragma endregion

#pragma region parallel_for dataPtr
    tm.reset();
    tm.start();
    uchar* pSrc = TestImg.data;
    Concurrency::parallel_for(int(0), TestImg.rows, [&](int y)
    {
        for (int x = 0; x < TestImg.cols; ++x) {
            uchar val = pSrc[TestImg.cols * y + x];
            pSrc[TestImg.cols * y + x] = val + 1;
        }
    });
    tm.stop();
    std::cout << "parallel_for dataPtr : " << tm.getTimeMilli() << "msec." << std::endl;
#pragma endregion

#pragma region parallel_for ptr
    tm.reset();
    tm.start();
    Concurrency::parallel_for(int(0), TestImg.rows, [&](int y)
    {
        uchar* pSrc = TestImg.ptr<uchar>(y);
        for (int x = 0; x < TestImg.cols; ++x) {
            uchar val = pSrc[x];
            pSrc[x] = val + 1;
        }
    });
    tm.stop();
    std::cout << "parallel_for ptr: " << tm.getTimeMilli() << "msec." << std::endl;
#pragma endregion

#pragma region parallel_for ptr++
    tm.reset();
    tm.start();
    concurrency::parallel_for(int(0), TestImg.rows, [&](int y)
    {
        uchar* pSrc = TestImg.ptr<uchar>(y);
        uchar* pSrc_end = pSrc + TestImg.cols;
        for (; pSrc < pSrc_end;) {
            uchar val = *pSrc;
            *pSrc++ = val + 1;
        }
    });
    tm.stop();
    std::cout << "parallel_for Optimize: " << tm.getTimeMilli() << "msec." << std::endl;
#pragma endregion

    return 0;
}
```

OpenCV 기본 세팅 Setting

OpenCV를 Visual Studio에서 사용하기 위한 기본 Setting 과정

※opencv 설치 경로 : C:\

※opencv 버전 : opencv-4.8.0-windows

  1. 아래와 같이 새 프로젝트를 생성한다.

  1. 아래와 같이 소스파일 폴더 아래 Main.cpp 파일을 하나 생성한다.

  1. OpenCV_Vision 프로젝트의 속성으로 들어간 후 구성(C): 모든구성, 플랫폼(P) : x64 로 설정

  1. opencv가 설치된 경로를 추가한다. 공통설정4-3. 디버깅항목에 환경에 DLL경로를 입력 PATH = C:\opencv\build\x64\vc16\bin;%PATH%4-4. 구성-Debug 추가종속성에 opencv_world480d.lib 입력
  2. 4-2. 링커의 추가 라이브러리 디렉터리에 C:\OpenCV\build\x64\vc16\lib 입력 : 링커를 포함시킴
  3. 4-1. C/C++의 추가 포함 디렉터리에 C:\opencv\build\include 입력 : 헤더파일을 포함하는 것
  1. OpenCV_Vision 프로젝트의 속성으로 들어간 후 구성(C): Debug, 플랫폼(P) : x64 로 설정
  2. 5-1. 추가 종속성 항목에 opencv_world480d.lib 입력
  1. OpenCV_Vision 프로젝트의 속성으로 들어간 후 구성(C): Release, 플랫폼(P) : x64 로 설정
  2. 6-1. 추가 종속성 항목에 opencv_world480.lib 입력
  3. 정상적으로 세팅이 되었는지 샘플코드 입력 후 빌드/실행하여 확인한다.7-3. 샘플코드
  4. /** @file videocapture_basic.cpp @brief A very basic sample for using VideoCapture and VideoWriter @author PkLab.net @date Aug 24, 2016 */ #include <opencv2/core.hpp> #include <opencv2/videoio.hpp> #include <opencv2/highgui.hpp> #include <iostream> #include <stdio.h> using namespace cv; using namespace std; int main(int, char**) { Mat frame; //--- INITIALIZE VIDEOCAPTURE VideoCapture cap; // open the default camera using default API // cap.open(0); // OR advance usage: select any API backend int deviceID = 0; // 0 = open default camera int apiID = cv::CAP_ANY; // 0 = autodetect default API // open selected camera using selected API cap.open(deviceID, apiID); // check if we succeeded if (!cap.isOpened()) { cerr << "ERROR! Unable to open camera\n"; return -1; } //--- GRAB AND WRITE LOOP cout << "Start grabbing" << endl << "Press any key to terminate" << endl; for (;;) { // wait for a new frame from camera and store it into 'frame' cap.read(frame); // check if we succeeded if (frame.empty()) { cerr << "ERROR! blank frame grabbed\n"; break; } // show live and wait for a key with timeout long enough to show images imshow("Live", frame); if (waitKey(5) >= 0) break; } // the camera will be deinitialized automatically in VideoCapture destructor return 0; }
  5. 7-2. 활성상태를 Release, x64로 설정 후 빌드
  6. 7-1. 활성상태를 Debug, x64로 설정 후 빌드

'OpenCV' 카테고리의 다른 글

OpenCV 픽셀 접근 속도 테스트  (0) 2024.05.11

Landmarks PJT - 보기 생성 및 결합

섹션 1. 새 프로젝트 생성 및 캔버스 탐색


SwiftUI 인터페이스와 Swift 언어를 통해 Landmarks 프로젝트를 만든다.

Landmarks 프로젝트를 처음 생성하면 **LandmarksApp.swift**

Content View.swift 파일이 생성되는 것을 알 수 있다.

 

**LandmarksApp.swift**

import SwiftUI // SwiftUI 인터페이스를 사용하겠다.

@main // 랜드마크라는 앱을 실행시키면 시작되는 프로그램의 진입점이다. 
struct LandmarksApp: App // 랜드마크앱은 App의 앱구조를 가진다.
{ 
    var body: some Scene // 몸체는 몇개의 씬으로 구성되는데 
        {
        WindowGroup // 그룹내의 뷰 코드를 실행하게 된다.
                {
            ContentView() // 컨텐츠 뷰 코드를 실행해라.
        }
    }
}

 

 

**ContentView.swift**

import SwiftUI // SwiftUI 인터페이스를 사용하겠다.

struct ContentView: View // 윈도우 그룹에서 띄울 컨텐츠
{
    var body: some View // 컨텐츠의 몸체
        {
        Text("Hello, world!") // 헬로우 월드를 띄워라 
            .padding() // 패딩 좌우간격을 줘라
    }
}

struct ContentView_Previews: PreviewProvider // 미리보기를 사용
{
    static var previews: some View // 프리뷰의 몸체 
        {
        ContentView() // 미리보기에 띄울 컨텐츠
    }
}

미리보기 화면이 아래와 같이 나온다.

 

섹션 2. 텍스트 사용자 정의


미리보기 화면에서 커맨드 키를 누르고 Helloworld를 클릭하면 아래와 같은 화면이 나오는데 Show SwiftUI Inspector를 클릭한다.

화면에 표시할 텍스트를 바꿀 수 있고, 폰트관련 설정, 패딩, 외곽선등을 설정할 수 있다.

해당 창에서 설정을 수정하면 자동으로 코드에 반영된다.

역으로 코드상에서도 동일하게 수정하면 코드에 반영이 된다.

실행 결과는 아래와 같다.

 

 

**ContentView.swift**

import SwiftUI // SwiftUI 인터페이스를 사용하겠다.

struct ContentView: View // 윈도우 그룹에서 띄울 컨텐츠
{
    var body: some View // 컨텐츠의 몸체
        {
            Text("Turtle Rock") // 헬로우 월드를 띄워라
                **.font(.title)   // 폰트는 타이틀 폰트를 사용해라 
                .foregroundColor(Color.green)   // 폰트 색상은 그린
                .multilineTextAlignment(.center) // 가운데 정렬
                .padding() // 패딩 좌우간격을 줘라**
    }
}

struct ContentView_Previews: PreviewProvider // 미리보기를 사용
{
    static var previews: some View // 프리뷰의 몸체
        {
        ContentView() // 미리보기에 띄울 컨텐츠
    }
}

섹션3. 스택으로 보기 결합하기


한 묶음의 텍스트를 세로 방향으로 쌓고 싶을 때 : VStack

**ContentView.swift**

import SwiftUI // SwiftUI 인터페이스를 사용하겠다.

struct ContentView: View // 윈도우 그룹에서 띄울 컨텐츠
{
    var body: some View // 컨텐츠의 몸체
        {
            **VStack** // 텍스트를 세로방향으로 쌓는다.
            {
                Text("Turtle Rock") // 보여줄 텍스트 : 터틀락
                    .font(.title) // 타이틀 폰트를 사용한다.

                Text("Joshua Tree National Park") // 보여줄 텍스트
                    .font(.subheadline) // 폰트

                Text("California") // 보여줄 텍스트
                    .font(.subheadline) // 폰트

            }
    }
}

struct ContentView_Previews: PreviewProvider // 미리보기를 사용
{
    static var previews: some View // 프리뷰의 몸체
        {
        ContentView() // 미리보기에 띄울 컨텐츠
    }
}

한 묶음의 텍스트를 가로 방향으로 쌓고 싶을 때 : HStack

**ContentView.swift**

import SwiftUI // SwiftUI 인터페이스를 사용하겠다.

struct ContentView: View // 윈도우 그룹에서 띄울 컨텐츠
{
    var body: some View // 컨텐츠의 몸체
        {
            **HStack** // 텍스트를 세로방향으로 쌓는다.
            {
                Text("Turtle Rock") // 보여줄 텍스트 : 터틀락
                    .font(.title) // 타이틀 폰트를 사용한다.

                Text("Joshua Tree National Park") // 보여줄 텍스트
                    .font(.subheadline) // 폰트

                Text("California") // 보여줄 텍스트
                    .font(.subheadline) // 폰트

            }
    }
}

struct ContentView_Previews: PreviewProvider // 미리보기를 사용
{
    static var previews: some View // 프리뷰의 몸체
        {
        ContentView() // 미리보기에 띄울 컨텐츠
    }
}

 

VStack 과 HStack 을 모두 사용하여 이쁘게 만들어 보자.

import SwiftUI // SwiftUI 인터페이스를 사용하겠다.

struct ContentView: View // 윈도우 그룹에서 띄울 컨텐츠
{
    var body: some View // 컨텐츠의 몸체
        {
            VStack(alignment: .leading) // 텍스트를 세로방향으로 쌓는다.(좌로 정렬)
            {
                Text("Turtle Rock") // 보여줄 텍스트 : 터틀락
                    .font(.title) // 타이틀 폰트를 사용한다.

                HStack
                {
                    Text("Joshua Tree National Park") // 보여줄 텍스트
                        .font(.subheadline) // 폰트

                    Spacer() // 공원과 주 사이에 공간을 채워넣음

                    Text("California") // 보여줄 텍스트
                        .font(.subheadline) // 폰트
                }
            }
            .padding() // 공원과 주를 분리할 때 너무 화면 끝으로 가버려서 약간의 공간을 줌
    }
}

struct ContentView_Previews: PreviewProvider // 미리보기를 사용
{
    static var previews: some View // 프리뷰의 몸체
        {
        ContentView() // 미리보기에 띄울 컨텐츠
    }
}

섹션4. 사용자 정의 이미지 보기 생성


Assets에 이미지를 드래그앤 드랍으로 추가한다.

CircleImage.swift 라는 새로운 SwiftUI를 만든다.

이미지를 불러오고 원형으로 자르고 각종 이펙트를 넣는다.

import SwiftUI

struct CircleImage: View
{
    var body: some View
    {
        Image("turtlerock") // 터틀락 이미지를 불러온다.
            .clipShape(Circle()) // 이미지를 원형으로 자른다.
            .overlay // 이미지에 덮어씌운다.
            {
                Circle() // 원을 덮어씌운다.
                    .stroke(.gray, lineWidth: 4) 
                                        // 속이 빈 원을 만드는데, 선 색깔과 두께를 설정한다.

                    // 흰색 테두리를 설정하려면 아래 코드 사용
                    // .stroke(.white, lineWidth: 4)

            }
            .shadow(radius: 7)
    }
}

struct CircleImage_Previews: PreviewProvider
{
    static var previews: some View
    {
        CircleImage()
    }
}

섹션5. 다른 프레임 워크에서 SwiftUI 보기 사용


아까 만들었던 원에 지도를 배치하려면 SwiftUI로 MapView.swift 파일을 생성하고 아래 코드의 주석을 참조한다.

**MapView.swift**

import SwiftUI
import MapKit   // 맵 킷을 불러온다.

struct MapView: View
{
    @State private var region = MKCoordinateRegion(
        center: CLLocationCoordinate2D(latitude: 37.5030042, longitude: 127.0507571),
        span: MKCoordinateSpan(latitudeDelta: 0.2, longitudeDelta: 0.2)
    )
    // **@State**는 해당 View 외부로는 사용할 수가 없고 private 형태로 내부에서만 사용
        //
    // **region**은 지도에 대한 정보를 저장하는 private 상태변수
    //
    // **MKCoordinateRegion**은 Map에서 보여줄 원하는 좌표를 담을 매개변수, 
        // struct로 특정 경도와 위도를 중심으로 둘러싼 사각형 모양의 지역범위를 표시
        //
    // **CLLocationCoordinate2D**은 지정된 위치와 관련된 위도 및 경도 데이터
        //
    // **MKCoordinateSpan**은 척도를 나타냄
        // 
    var body: some View
    {
        Map(coordinateRegion: $region)
        // 앞서 선언한 상태변수 region을 **바인딩**(참조)으로 Map에 넣는다.
    }
}

struct MapView_Previews: PreviewProvider {
    static var previews: some View {
        MapView()
    }
}

섹션6. 상세도 작성


지금까지 작성한 컨텐츠들을 보기좋게 아래와 같이 배치

 

**Contentview.swift**

import SwiftUIimport SwiftUI // SwiftUI 인터페이스를 사용하겠다.

struct ContentView: View // 윈도우 그룹에서 띄울 컨텐츠
{
    var body: some View // 컨텐츠의 몸체
        {
            VStack// 텍스트를 세로방향으로 쌓는다.(좌로 정렬)
            {
                MapView()
                    .ignoresSafeArea( edges : .top )
                    .frame(height:300)

                CircleImage()
                    .offset(y:-130)
                    .padding(.bottom,-130)

                VStack (alignment: .leading)
                {
                    Text("Turtle Rock") // 보여줄 텍스트 : 터틀락
                        .font(.title) // 타이틀 폰트를 사용한다.

                    HStack
                    {
                        Text("Joshua Tree National Park") // 보여줄 텍스트
                        Spacer() // 공원과 주 사이에 공간을 채워넣음
                        Text("California") // 보여줄 텍스트
                    }
                        .font(.subheadline) // HStack으로 묶여있는 애들을 서브라인 폰트로 설정한다.
                        .foregroundColor(.secondary) // 글자색을 옅은 회색으로 설정한다.

                    Divider() // 구분선을 추가한다.

                    Text("About Turtle Rock")
                        .font(.title2)
                    Text("Descriptive text goes here.")
                }
                    .padding() // 보기좋게 하기 위해 VStack 으로 쌓은 놈들에 패딩을 준다.

                Spacer() // 지금까지 작성한 컨텐츠를 최상단으로 끌어올린다.
            }
    }
}

struct ContentView_Previews: PreviewProvider // 미리보기를 사용
{
    static var previews: some View // 프리뷰의 몸체
        {
        ContentView() // 미리보기에 띄울 컨텐츠
    }
}

  • 포인터 : 어느 대상을 가리키기 위한 주소를 저장하는 데이터 타입
    • 포인터가 가리키는 대상은 포인터에 *연산을 통하여 접근
#include <stdio.h>

int main(void)
{
    int a = 10;
    int *p = &a; //int 자료형을 가리키는 포인터 = a의 주소

    printf("0x%p\n",&a); //a의 주소
    printf("0x%p\n",p);  //포인터가 가리키는 주소
    printf("%d\n",a);    //a의 값
    printf("%d\n",*p);   //포인터가 가리키는 대상의 값
  printf("%d\n", sizeof(p)); //포인터의 사이즈
  printf("%d\n", sizeof(*p));//포인터가 가리키는 대상의 사이즈
}
  • 포인터는 가리키는 대상 타입에 맞게 선언되어야 한다.
#include <stdio.h>

int main (void)
{
    char a = 'A';
  char *p = &a;

  double f = 3.14;
  double *q = &f;

  printf("%d\n", sizeof(*p)); //포인터가 가리키는 대상의 사이즈
  printf("%c\n", *p); //포인터가 가리키는 대상의 값
  printf("0x%p", p); //포인터가 가리키는 주소
  printf("0x%p", p + 1); //포인터가 가리키는 주소 + 1 : char크기(1바이트)만큼 주소 이동
    printf("0x%p", q); //포인터가 가리키는 주소
  printf("0x%p", q + 1); //포인터가 가리키는 주소 + 8 : double크기(8바이트)만큼 주소 이동

}
  • 함수에서 전달받은 변수 내용을 변경하려면 포인터로 변수의 주소를 받아야 한다.
#include <stdio.h>

//Call By Value
void f1 (int b)
{
    b = 100;
    printf("%d\n",b);
} 

//Call By Address
void f2 (int *p) //a를 가리키기 위한 포인터를 인자로 선언
{
    *p = 100; //포인터가 가리키는 대상의 값을 100으로 변경
    printf("%d\n",*p); //포인터가 가리키는 대상의 값을 출력
}

int main (void)
{
    int a = 10;

    f1(a); //Call By Value
    printf("%d\n",a);

    f2(&a);//Call By Address - a의 주소를 넘김
    printf("%d\n",a);
}
  • %s 포맷 지시자와 문자열
#include <stdio.h>

int main (void)
{
    char a[] = "Hello"; //배열은 포인터임
    char *p = "Hello"; //인쇄할 문자열의 첫번째 주소 대입

    //%s는 인쇄할 문자열의 첫 글자의 주소를 받음
    printf("%s\n", "Hello");
    printf("%s\n", &a[0]); //문자열의 첫번째 인자의 주소 
    printf("%s\n", a); //문자열
    printf("%s\n", p); //문자열의 주소

  printf("%s\n", "Hello"+1); //문자열의 주소를 이동시킴 -> ello 출력
    printf("%s\n", a + 1); //문자열 주소 이동 -> ello 출력
  printf("%s\n", p + 1); //포인터가 가리키는 주소 이동 -> ello 출력
}
  • 문자열 분석
#include <stdio.h>

char *func(char *q) // 반환형 : char * , 인자 : char *
{
    printf("%s\n", q);
    printf("%c\n", q[0]);
    printf("%c\n", q[1]);
    printf("0x%p\n", q);
    printf("0x%p\n", q+1);
    printf("0x%p\n", *q);
    printf("0x%p\n", *(q+1));

    return q + 2;
}

void main(void)
{
    char *p = "Hello"; //문자열은 char 배열이다.

    printf("%s\n", "Hello"); //Hello 출력
    printf("0x%p\n", "Hello");//Hello의 시작 주소 출력
    printf("0x%p\n", "Hello" + 1);//Hello 주소 + 1Byte 주소 출력
    printf("%c\n", "Hello"[0]); //Hello의 문자열의 첫번째 글자 H 출력
    printf("%c\n", "hello"[1]); //hello의 문자열의 두번째 글자 e 출력
    printf("%c\n", *"Hello"); //문자열은 포인터이므로 문자열의 첫번째 대상 H를 출력
    printf("%c\n", *("Hello" + 1));//문자열은 포인터이므로 포인터를 1Byte만큼 이동시킨 후 첫번째 인자 e출력
    printf("%s\n", func("Hello")); //문자열을 반환받는 func함수에 포인터(주소) 전달 후 llo 반환받음
}
  • *p++, *++p 의 동작
    • ++, — 연산자가 주소에 사용되면 주소가 가리키는 크기만큼 증가, 감소한다.
    • *++p : 먼저 포인터 p를 증가시키고 그 주소의 내용을 꺼내온다.
    • *p++ : p주소에서 먼저 내용을 꺼내고 포인터 p를 증가시킨다.
#include <stdio.h>

void main(void)
{
    int cnt = 0;
    char *p = "Embedded"; //문자열의 첫번째 글자를 가리키는 포인터

    while (*p) //*p가 \0(null 포인터)이 될 때 까지 
    {
        if (*p++ == 'd') cnt++; //문자열을 가리키는 포인터의 주소를 한칸씩 이동시키며 d가 있으면 1씩 증가
    }

    printf("%d\n", cnt);
}
#include <stdio.h>

void main(void)
{
    int cnt = 0, i = 0;
    char *p = "Embedded";

    while (p[i]) //E로 시작하는 포인터가 0(NULL Pointer)을 만날때 까지 반복
    {
        if (p[i++] == 'd') cnt++; //포인터를 한칸씩 이동시키며 cnt 증가
    }

    printf("%d\n", cnt);
}
  • 문자열 복사 함수
    • 문자열 복사 함수의 동작분석
#include <stdio.h>

void str_copy1(char * d, char * s) //주소를 받을 수 있도록 함수인자로 포인터 선언
{
    int i;

    for (i = 0; ; i++)
    {
        d[i] = s[i];
        if (d[i] == '\0') return; // \0(NULL PTR)을 만나면 탈출
    }
}

void str_copy2(char * d, char * s)
{
    while (*d++ = *s++); // 0이되면 탈출
}

void main(void)
{
    char a[5], b[5]; //문자열 배열 선언
    char c[5] = "ABCD"; //문자열 배열에 ABCD\0 대입

    str_copy1(a, c); //문자열 배열의 첫번째 인자의 주소 전달
    str_copy2(b, c);
    printf("%s %s %s\n", a, b, c);
}
  • 문자열 길이 측정 함수
    • 문자열 길이를 측정하는 함수 설계
#include <stdio.h>

unsigned int str_length(char * d)
{
    // 코드 작성
    int cnt = 0;
    for (int i = 0; ;i++)
    {
        if(d[i] == 0) //널문자 검사 우선 수행
        {
            return cnt;
        }
        else
        {
            cnt++;
        }
    }
}

void main(void)
{
    char a[] = "Willtek";

    printf("%d\n", sizeof(a)); // \0 을 포함하여 출력
    printf("%d\n", str_length(a)); // \0을 제외하여 출력
}
  • 문자열 연결 함수
    • 두개의 문자열을 하나로 이어주는 함수 설계
#include <stdio.h>

void str_add(char * d, char * s) //전달받은 a와 b를 합친다.
{
    for(int i = 0; ; i++)
    {
        if(d[i] == 0) // "Willtek\0"에서 \0을 만나면 해당 자리부터 " Corp."을 이어씀
        {
            for (int j = 0; ; j++)
            {
                if(s[j] == 0)
                {
                    return;
                }
                else
                {
                    d[i+j] = s[j];
                }    
            }
        }
    }
}

void main(void)
{
    char a[15] = "Willtek";
    char b[15] = " Corp.";

    str_add(a, b); //a와 b의 첫번째 주소를 전달

    printf("%s\n", a);
}
  • 문자열 비교 함수
    • 두개의 문자열의 크기를 비교하는 함수를 설계
    • 두 문자열 a,b중에서 a가 크면 1, b가 크면 -1, 같으면 0 리턴
#include <stdio.h>

int str_comp(char *a, char *b)
{
    // 코드 작성
    int result = 0;
    for (int i = 0;; i++)
    {
        if (a[i] > b[i]) // a가 크면
            return result = 1;
        else if (a[i] < b[i]) // b가 크면
            return result = -1;
        else if ((a[i] == b[i])&&(a[i]==0)) //널문자가 나타날 때까지 함수를 탈출 못하면 문자열이 모두 같다
            return result = 0;
    }

}

void main(void)
{
    printf("%d\n", str_comp("ABC", "BC"));
    printf("%d\n", str_comp("ABC", "AC"));
    printf("%d\n", str_comp("ABC", "AB"));
    printf("%d\n", str_comp("abc", "ABC"));
    printf("%d\n", str_comp("ab", " "));
    printf("%d\n", str_comp("A", "AB"));
}
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>

int main(void)
{
	double a, b, c;

	scanf("%lf", &a);
	scanf("%lf", &b);
	scanf("%lf", &c);

	printf("%.3lf\n", a);
	printf("%.3lf\n", b);
	printf("%.3lf\n", c);

	return 0;
}
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(void)
{
	double a, b;
	char c;

	scanf("%lf %lf %c", &a, &b, &c);

	//아래 방법은 에러발생
	//scanf("%lf", &a);
	//scanf("%lf", &b);
	//scanf(" %c", &c); - char 입력받을 때 띄어쓰기 필요

	printf("%.2lf\n", a);
	printf("%.2lf\n", b);
	printf("%c\n", c);

	return 0;
}
#include<stdio.h>

int main(void)
{
	int a, b;
	scanf("%d %d", &a, &b);
	printf("%d * %d = %d\n", a, b, a*b);
	printf("%d / %d = %d", a, b, a/b);
	return 0;
}
#include<stdio.h>

int main(void)
{
	int height;
	printf("height = ");
	scanf("%d",&height);
	printf("Your height is %dcm.", height);

	return 0;
}
#include <stdio.h>

int main(void)
{
	float YardToCm, inchToCm;
	YardToCm = 91.44;
	inchToCm = 2.54;

	float yard, inch;
	yard = 2.1;
	inch = 10.5;

	printf("%4.1fyd = %5.1fcm\n", yard, yard*YardToCm);
	printf("%4.1fin = %5.1fcm", inch, inch*inchToCm);

	return 0;
}
#include<stdio.h>

int main(void)
{
	int weight;
	float gravity;
	weight = 49;
	gravity = 0.2683;

	printf("%d * %.6f = %.6f", weight, gravity, weight * gravity);
	return 0;
}

+ Recent posts