2013. 5. 21. 23:53

bubble sort / file open source code

#include "bubbleSort.h"

bubbleSort::bubbleSort(void)
{
}

bubbleSort::~bubbleSort(void)
{
}

int bubbleSort::startSort(int* arr_list, int size)
{
 int i, j, temp;
 for(i = 0 ; i < size ; i++){
  for(j = 0 ; j < size - 1 ; j++){
   if(arr_list[j] > arr_list[j+1])
   {
    temp = arr_list[j+1];
    arr_list[j+1] = arr_list[j];
    arr_list[j] = temp;
   }
  }
 }
 return 0;
}

int bubbleSort::fileopenTest()
{
 FILE* fileTest;
 FILE* fileOutput;
 int temp1, temp2, temp3;
 char c_temp1, c_temp2;

 fileTest = fopen("test1.txt", "rt");
 if(fileTest == NULL)
 {
  printf("file open error");
 }

 fileOutput = fopen("test2.txt", "wt");
 if(fileOutput == NULL)
 {
  printf("file open error2");
 }

 fscanf(fileTest, "%d\n", &temp1);
 printf("%d\n", temp1);

 for(int i = 0 ; i < 2 ; i++ )
 {
  fscanf(fileTest, "%c%c\n", &c_temp1, &c_temp2);
  fprintf(fileOutput, "(%c-%c)\n", c_temp1, c_temp2);
  fscanf(fileTest, "%d %d %d\n", &temp1, &temp2, &temp3);
  fprintf(fileOutput, "(%d)\n", temp1 + temp2 + temp3);
 }

 fclose(fileOutput);
 fclose(fileTest);

 return 0;
}

int main()
{
 int arr[10] = {123,456,2367,324,67,3213,545,12,4,997};
 bubbleSort sort;

 sort.startSort(arr, 10);

 for(int i = 0 ; i < 10 ; i++)
 {
  printf("%d ", arr[i] );
 }
 printf("\n");

 sort.fileopenTest();

 system("pause");
 return 0;
}

 

2013. 3. 23. 00:51

클래스간 Callback Sample Source

클래스간 Callback Sample Source

Callback.zip

2009. 6. 3. 17:48

구조체를 파일에 읽거나 쓸 때 알고 쓰자.

보통 구조체를 통해 파일을 읽고 쓸 수 있는 것은 알 것이다.
fwrite(&somestruct, sizeof (somestruct), 1, fp);
형식으로 쓰면 되는데 만약 구조체가 포인터( char*타입의 문자열이나 다른 구조체를 가리키고 있는 포인터)
포함하고 있다면 파일내의 데이터는 단지 주소값만 저장되기 때문에
fread가 이루어진다 해도 주소값만 저장되지 주소값이 가르키고 있는 값은 저장되지 않는다.
밑의 코드 예를 보자.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define FILENAME1 "test1.txt"


typedef struct TmpData{

 int f;
 char arr[100];
 char* pArr;

}sTmpData;

typedef struct FileData{

 int a;
 int c;
 char b;
 sTmpData e;

}sData;


int WriteStFile(sData* in);
int ReadStFile(sData* out);


int main()
{
 sData WriteData = {2,33,'d'};
 sData ReadData;
 memset(&ReadData, 0, sizeof(ReadData) );

 // init WriteData
 WriteData.e.f = 100;
 strcpy( WriteData.e.arr, "aaa");
 WriteData.e.pArr = (char*)malloc( sizeof( WriteData.e.arr ) );
 strcpy( WriteData.e.pArr, "bbb");

 // Write File
 WriteStFile(&WriteData);

 // Read Structure Data from File
 ReadData.e.pArr = (char*)malloc( sizeof( WriteData.e.pArr ) );
 ReadStFile(&ReadData);

 // print
 printf("%d %d %c %d %s", ReadData.a, ReadData.c, ReadData.b, ReadData.e.f, ReadData.e.pArr);

 free( WriteData.e.pArr );
 
 system("pause");

 return 0;
}

int WriteStFile(sData *in)
{
 FILE* pFile = NULL;
 pFile = fopen( FILENAME1, "wb" );

 fwrite(in, sizeof(sData) , 1, pFile);

 fclose(pFile);

 return 0;
}

int ReadStFile(sData *out)
{
 FILE* pFile = NULL;
 pFile = fopen( FILENAME1, "rb" );

 fread(out, sizeof(sData) , 1, pFile);

 fclose(pFile);

 return 0;
}

실행은 하면 다음과 같은 결과가 뜬다.


위에 예상 결과와 달리 bbb라는 문자열이 잘 출력되고 있다. 무엇이 문제일까?
바로 WriteData 라는 구조체 변수에서 할당되었던 값을 의미하는 것이다.
즉 ReadData.e.pArr 가 가르키는 주소값과 WriteData.e.pArr 가 가르키는 주소값이 같기 때문에
아무 이상없이 출력되는 것이다. 혹 이것을 보고 bbb라는 문자열 또한 다른 메모리로 복사된 것으로
착각하기 쉽다.

위 코드에서 생성된 파일을 가지고 다음 코드를 주석처리한 다음 다시 실행해보자.

WriteData.e.pArr = (char*)malloc( sizeof( WriteData.e.arr ) );
strcpy( WriteData.e.pArr, "bbb");

결과를 보면


메모리에 값이 없거나 쓰레기 값, 또는 다른 곳에서 쓰고 있는 값을 가지고 올 수도 있는 것이다.

또한 많이 하는 실수는 메모리 해제에 있다.
같은 메모리를 가르키고 있는 상태를 그대로 쓴다면 메모리 해제에 있어 다음과 같은 실수를 저지를 수 있다.

 free( WriteData.e.pArr );
 free( ReadData.e.pArr );


즉 같은 메모리 주소를 가지고 두번 메모리 해제를 하기 때문에 힙 에러가 나는 것이다.

마지막으로 데이터 파일의 이식성을 위해서는 fopen()시 b 플러그를 사용하는 것이 좋다.
2009. 4. 29. 11:59

Flexible array member

표준(c90/c95)의 엄격한 해석에 따라 유용하게 사용할 수 있는 편범이 올바르지 않은 것으로 결론나자.
C99는 해당 편법을 정당하게 지원할 수 있는  flexible array member라는 기술을 새로 추가하였다.
즉 배열이 구조체나 공용체의 마지막 요소인 경우에 한해 선언 시에 그 크기를 명시하지 않고
나중에 할당받을 수 있도록 배려한 것이다. - 출처 : C언어 펀더멘탈 -

#include <stdio.h>
#include "stdlib.h"

struct A {
    int a;
    int b[];
};
   
int main()
{
    const int N = 10;
    int i;
   
    struct A* p = (A*)malloc(sizeof(struct A) + sizeof(int) * (N - 1));
   
    p->a = 100;
    for (i = 0; i < N; i++)
    {
        p->b[i] = i;
    }
       
    printf("%d %d %d\n", p->a, p->b[0], p->b[N-1]);
    for( int loop = 0 ; loop < N + 1 ; loop++ )
    {
           printf("%d %d\n", p->a, p->b[loop]);
    }   
    system("pause");
    //free(p);
   
    return 0;  
}   

2009. 4. 15. 11:29

초기화 - char a[]와 char *p의 초기화 차이점

int main()
{
    char a[] = "string literal";
    a[2] = 66;
   
    char *p = "string literal";
    //p[2] = 66; // 에러 발생
   
    printf("%s\n",a);
    printf("%s",p);
    system("pause");
    return 0;  
}  

char a[] = "string literal";
이 경우는 배열의 초기값으로 쓰이는 것을 의미하며 배열의 각 요소들인 문자들에 대입되는 초기값을 나타낸다.
이 경우가 아니면 문자열은 이름이 없는 정적(static)인 배열에 저장되고 읽기 전송의 속성을 가진다.
char *p = "string literal"; 에서는 읽기 전용이므로 포인터 p를 가지고 문자열을 수정할 수 없다.

2009. 4. 15. 11:10

Namespace 규칙 및 Reserved 상태

ANSI C89에 따르면 Namespace  에 대한 다음과 같은 규칙이 있다.

1. 밑줄 문자로 시작하고, 두 번째 문자가 밑줄이거나 대문자인 모든 이름은( 모든 scope와 모든 namespace에서)
   항상 reserved 상태이다.

2. 밑줄로 시작하는 모든 이름은 file scope에서 ordinary identifer ( 즉, 함수, 변수 typedef, enumeration constant
   등 )를 위해 reserve되어 있다.

3. 어떤 표준 헤더 파일을 포함했을 때, 그 헤더 파일에서 제공하는 모든 매크로 이름은 reserve디어 있다.

4. (함수 이름처럼) External linkage( global, non-static )를 가지는 모든 표준 라이브러리 identifier들은 
   External linkage를 위한 identifier로 reserve되어 있다.

5. 표준 헤더 파일에 정의되어 있는, file scope를 가지는 typedef와 tag이름은 그 헤더 파일을 포함 시켰을 경우,
  ( 같은 namespace를 지나는 )file scope에서 모두 reserve되어 있다.


scope : 영역이라는 의미로 C언어에서는 4개의 scope가 존재한다. funtion, file, block, prototype.
           prototype scope는 함수 prototype선언에서 파라메터 리스트 안에서 적용되는 것이다.
 


정리하자면

1.2 밑줄로 시작하는 이름을 쓰지 말라.
3   표준 매크로와 같은 이름을 쓰지말라.
4   표준 라이브러리에 있는 모든 변수 및 함수 이름과 다음 표에서 나온 이름을 쓰지 말라.

                  - Header Future directions patterns -
<ctype.h> is[a-z]*, to[a-z]* (function)
<errno.h> E[0-9]*, E[A-Z]* (macros)
<locale.h> LC_[A-Z]* (macros)
<math.h> cosf, sinf, sqrtf, etc.
              cosl, sinl, sqrtl, etc. (all functions)
<signal.h> SIG[A-Z]*, SIG_[A-Z]* (macros)
<stdlib.h> str[a-z]* (functions)
<string.h> mem[a-z]*, str[a-z]*, wcs[a-z]* (function)

5   표준에서 제공하는 typedef나 tag이름을 새로 정의하는 이름에 쓰지 말라.

2009. 4. 14. 14:36

default argument promotion

 기본 인자 진급( default argument promotion )은 함수 호출이 원형 선언의 지배를 받지 않거나 원형선언이
보이더라도 가변 인자를 갖는 경우, 인자에 적용되는 일정한 변환 규칙이다.
 1. int 보다 작은 정수 타입은 int형으로 변환.
 2. float형은 double형으로 변환.
 3. 나머지 인자는 그대로 전달.

즉 함수의 리턴 타입과 모든 파라메터 타입은 int, double형으로 쓴다는 의미이다.

원형 선언은 인자와 매개변수의 데이터형이 무엇이든지 간에 대입에 의한 암시적 변환이 허락되는 관계라면
마치 매개변수로의 대입이 일어나는 것처럼 적절한 변환 과정으로 수행해준다. 따라서 그만큼 인자와 매개변수의
데이터형에 관심을 덜 써도 프로그램은 정의된 행동을 보장받는다.

하지만 비원형 선언( 오래된 형식의 선언 방법 - 설명1 참조 )아래에서 이루어지는 함수 호출이나 원형선언이라도
가변 인자를 갖는 경우에는, 인자와 매개변수의 데이터형이 상충되지 않도록 보장하는 것은 어디까지나 
프로그래머의 책임이다. 
따라서 default argument promotion의 진정한 존재 이유사 기존 구현의 하위 호환성을 유지하는 것이라 하지라도
분명 비원형 함수 호출에서 프로그래머는 더 적은 수의 데이터형만 걱정하면 되므로 프로그래머의 부담을 덜어주는 긍적적인 역활을 한다고 볼 수도 있다.( 호환성 측면에서의 인자값 부담 )


< 설명 1 >
1)

int func(x)
float x;
{ ...

표준화 이전의 비원형함수 정의 방법이다. 소괄호안에는 파라메터의 변수명이 나오고 아래 따로 선언이 된 방식이다. 만일 선언이 되지 않는 경우 자동으로 int로 간주하게 된다.

2)

extern int func();

여기서 짚고 갈 점은 ()는 매개변수가 없다는 것이 아니라 매개변수에 대한 검사를 수행하지 않는 다는 의미이다.
즉 비원형 함수이며 매개변수가 없음을 의미하는 원형 선언은

extern int func(void);

이다.

다시 정리하자면

func(10, 20); 
func(10); 

위의 두 함수는
extern int func()와 같은 함수를 뜻한다는 것이다.

<의문점>

옜날 형식의 함수와 요즘 함수를 섞어서 썼을 때

extern int func(float);

int func(x)
float x;
{ ...

이렇게 쓰면 에러가 나므로

extern int func(double);

또는

int func(float x) { ... }
 
요렇게 써야 할 것이다.
만일

extern int func();

int func(x)
float x;
{ ...

이렇게 쓴다면?? 안되남??

2009. 4. 10. 15:30

함수 포인터, 포인터 배열과 typedef 기초 예시

#include <iostream>
#include <stdlib.h>

using namespace std;

int func();
int func2();

int main(int argc, char** argv)
{
    int (*aa)();           // 1. 함수 포인터
    typedef int (*qq)();   // 2. 함수 포인터 정의 : int를 리턴하는 함수에 대한 포인터
    typedef int (*ee)[5];  // 3. 5개의 int형 데이터를 저장하는 배열의 포인터를 정의
    int arr[5] ={1,2,3,4};
    int (*arrs[2])();      // 4. 함수 포인터를 저장하는 포인터 배열
    typedef int(*arrs2[2])(); // 5. 함수포인터를 저장하는 포인터 배열의 정의
         
    qq ww;      // 2 변수 선언         
    aa = func;  // 1 주소대입
    aa();       // 1 실행
    ww = func;  // 2 주소대입
    ww();       // 2 실행
    ee rr;      // 3 변수 선언
    rr = &arr;  // 3 주소대입
    for(int i = 0 ; i < 5 ; i++)
    {
         cout<<(*rr)[i]<<endl;  
    }   
   
    arrs2 arrs1;      // 5
    arrs[0] = func;   // 4
    arrs[1] = func2;  // 4
    arrs1[0] = func;  // 5
    arrs1[1] = func2; // 5
   
    arrs[0]();        // 4
    arrs1[1]();       // 5
   
    system("pause");
    return 0;
}   


int func()
{
    cout<<"haha"<<endl;
    return 0;
}   

int func2()
{
    cout<<"hoho"<<endl;
    return 0;  
}   

2009. 4. 10. 13:31

구조체와 typedef의 관계

typedef struct {
int afield;
BPTR bpointer;
} * APTR;
typedef struct {
int bfield;
APTR apointer;
} * BPTR;

BPTR, APTR에 대한 typedef문제이다. 구조체는 자기 자신에 대한 포인터를 포함할 수 있기 때문에

struct a {
int afield;
struct b *bpointer;
};
struct b {
int bfield;
struct a *apointer;
};

요런 식으로 바꾸어 주면 된다. 아직 struct b를 모르지만 컴파일러는 imcomplete 구조체로 보고 허용을 해준다.
또한 때때로 struct b;  먼저 선언해 주는 것이 필요하다.
만일 BPTR, APTR를 이용하고 싶다면

typedef struct a *APTR;
typedef struct b *BPTR;

struct a {
int afield;
BPTR bpointer;
};
struct b {
int bfield;
APTR apointer;
};

요렇게 쓰면 된다.
2009. 4. 10. 13:19

Typedef과 #define(매크로)의 차이

아주 간단한 차이만 설명하겠습니다.

typedef char *String_t;
#define String_d char *

String_t s1, s2;
String_d s3, s4;

s1, s2, s3는 char*형이지만 s4는 char형입니다.

일반적으로 char *s3, s4와 같은 의미로 보고 생각하시면 됩니다.

typedef는 스코프 규칙을 잘 따르는 장점이 있고, 매크로는 #ifdef를 쓸 수 있다는 장점이 있습니다.
잘 판단해서 이용해야 겠죠? ㅎㅎ