Skip to content

Latest commit

 

History

History
1005 lines (831 loc) · 25.7 KB

README.md

File metadata and controls

1005 lines (831 loc) · 25.7 KB

The final destination of programming

<List>

※ All codes include the following top lines. :

// C
#include <stdio.h>
// CPP
#include <iostream>

using namespace std;
  • A comparison between the K&R style and ANSI C style function declaration methods

  • What is K&R C? → [Wikipedia] C (programming language) > History > K&R C

    According to ChatGPT
    • Pros:

      • Conciseness: The K&R style reduces the length of the function declaration, making it more concise.
    • Cons:

      • Readability: Without parameter names, it can be difficult to understand the purpose of each parameter.
      • Lack of Type Safety: Since only data types are mentioned, there's no type checking for function arguments.
      • Maintenance: If parameter order or types change, you need to update both the declaration and definition.
    • Conclusion:

      • While the K&R style was used in early C development due to limitations of the time, the ANSI C style has become the recommended practice. It improves code readability, provides better type safety, and enhances maintainability. The ANSI C style also aligns with modern coding standards and best practices, making it the preferred choice for most developers today.
  • Example

    Codes : KnrFunctionSyntax.c
    int add(a, b)                           // K&R 스타일 함수 선언: 매개변수 이름을 생략하고 데이터 타입만 표시
        int a, b;                           // 실제 매개변수 이름과 데이터 타입은 별도로 기술
    {
        return a + b;
    }
    int add2(int a, int b)                  // ANSI C 스타일 함수 선언: 매개변수와 데이터 타입을 함께 명시
    {
        return a + b;
    }
    int main()
    {
        int result = add(5, 3);              // K&R 스타일 함수 호출
        int result2 = add2(5, 3);            // ANSI C 스타일 함수 호출
    
        printf("Result  (K&R) : %d\n", result);
        printf("Result2 (ANSI): %d\n", result2);
    
        return 0;
    }
    Output

    Surprisingly, the K&R style code has been compiled successfully even in recent compilation environments. The above code was compiled using MinGW.org GCC-6.3.0-1 and executed without any issues.

    Result  (K&R) : 8
    Result2 (ANSI): 8
  • Can determine where to compile or not with the preprocessors #ifdef ~ #endif

  • It seems very useful! I love it!

  • References :

  • ※ When the macro fileio is on, Ahnlab V3 Lite recognizes a.exe as a malware!

    Codes : ConditionalCompile.c
    int main()
    {
        char txt[] = "I am your father.\n";
    
        #ifdef fileio
            char fileName[] = "ConditionalCompile.txt";
    
            FILE* pf = fopen(fileName, "w");       // w : make a new empty file
            fprintf(pf, txt);
            fclose(pf);
    
            printf("%s has been generated.\n", fileName);
        #else
            printf("%s", txt);
        #endif
    
        return 0;
    }
    Codes : ConditionalCompile.cpp
    #include <iostream>
    #include <fstream>
    #define endl '\n'
    
    using namespace std;
    int main()
    {
        string txt = "I am your father.";
    
        #ifdef fileio
            ofstream ofs;
            string fileName = "ConditionalCompile.txt";
            ofs.open(fileName, ios::out);           // ios::out : make a new empty file
            ofs << txt << endl;
            ofs.close();
            cout << fileName << " has been generated." << endl;
        #else
            cout << txt << endl;
        #endif
    
        return 0;
    }
    Commands : ConditionalCompile_c.bat

    The couple of files have the same results.

    :: #ifdef fileio
    gcc -Dfileio conditionalcompile.c
    a
    
    :: #else
    gcc conditionalcompile.c
    a

    ConditionalCompile.txt has been generated.
    I am your father.

    Commands : ConditionalCompile_cpp.bat
    :: #ifdef fileio
    g++ -Dfileio conditionalcompile.cpp
    a
    
    :: #else
    g++ conditionalcompile.cpp
    a

    ConditionalCompile.txt has been generated.
    I am your father.

    Results : ConditionalCompile.txt
    I am your father.
    
  • A practice of file input/ouput in C/C++

  • Further discussion : how to read Korean string from external file

    Codes : FileIO.c
    int main()
    {
        // Write file
        FILE* pf1 = fopen("FileIO.txt", "w");       // w : make a new empty file
        fprintf(pf1, "My wife is crazy.\n");
        fprintf(pf1, "Really crazy.\n");
        fclose(pf1);
    
        // Read file
        FILE* pf2 = fopen("FileIO.txt", "r");       // r : read-only
        char txt[__INT16_MAX__];
        fread(txt, 1, __INT16_MAX__, pf2);
        printf("%s", txt);
        fclose(pf2);
    
        return 0;
    }
    Codes : FileIO.cpp
    #include <iostream>
    #include <fstream>
    #define endl '\n'
    
    using namespace std;
    int main()
    {
        // Write file
        ofstream ofs;
        ofs.open("FileIO.txt", ios::out);           // ios::out : make a new empty file
        ofs << "My wife is crazy." << endl;
        ofs << "Really crazy." << endl;
        ofs.close();
    
        // Read file
        ifstream ifs;
        string line;
        ifs.open("FileIO.txt", ios::in);            // ios::in : read-only
        while(getline(ifs, line)) cout << line << endl;
        ifs.close();
    
        return 0;
    }
    Results : FileIO.txt
    My wife is crazy.
    Really crazy.
    
  • Generate many assembly(.s) files with various optimization options in GCC

  • But I've just realized that I'm not ready yet to read their assembly codes ……

  • However, I've found at least that the generally known properties of the optimization options are not fixed absolutely.
    (For example, Os is known as smaller code size but it sometimes returns rather larger one.)

  • References :
    · https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
    · https://wiki.kldp.org/wiki.php/GccOptimizationOptions
    · https://www.rapidtables.com/code/linux/gcc/gcc-o.html

    Codes : OptimizePractice.c
    void operate(int i, int* p)
    {
        if (i % 2 != 0) (*p)++;
    }
    int main()
    {
        int num = 0;
        int* p = &num;
    
        for (int i = 0; i < 10; i++) operate(i, p);
    
        printf("%d\n", num);
    
        return 0;
    }

    5

    Codes : OptimizePractice.bat (Old)
    gcc -O0 -S OptimizePractice.c -o OptimizePractice_O0.s
    gcc -O1 -S OptimizePractice.c -o OptimizePractice_O1.s
    gcc -O2 -S OptimizePractice.c -o OptimizePractice_O2.s
    gcc -O3 -S OptimizePractice.c -o OptimizePractice_O3.s
    gcc -Os -S OptimizePractice.c -o OptimizePractice_Os.s
    gcc -Ofast -S OptimizePractice.c -o OptimizePractice_Ofast.s
    Codes : OptimizePractice.bat (New)
    @echo off
    
    set name=OptimizePractice
    set options=O0 O1 O2 O3 Os Ofast
    @REM There should be no space on the both side of "="
    
    for %%i in (%options%) do (
        @REM echo %%i
        gcc -%%i -S %name%.c -o %name%_%%i.s
    )
  • I wrote the below codes in GCJ 2022 Round 1B - Controlled Inflation, but there's some struggle with printf()'s format %d %ld %lld.
    (All the variables are declared as long long type.)

    // test
    // printf("min : %lld, max : %lld, dist : %lld, sum1 : %lld, sum2 : %lld\n", min, max, dist, sum1, sum2);
  • I will never miss the criminal!

    Codes : printf.c & printf.cpp

    The codes except each of the headers are the same.

    int main()
    {
        char text[] = "%d %ld %lld\n";
        printf(text, __SCHAR_MAX__, __SCHAR_MAX__, __SCHAR_MAX__);
        printf(text, __INT8_MAX__, __INT8_MAX__, __INT8_MAX__);
        printf(text, __SHRT_MAX__, __SHRT_MAX__, __SHRT_MAX__);
        printf(text, __INT16_MAX__, __INT16_MAX__, __INT16_MAX__);
        printf(text, __INT_MAX__, __INT_MAX__, __INT_MAX__);
        printf(text, __LONG_MAX__, __LONG_MAX__, __LONG_MAX__);
        printf(text, __INT32_MAX__, __INT32_MAX__, __INT32_MAX__);
        printf(text, __LONG_LONG_MAX__, __LONG_LONG_MAX__, __LONG_LONG_MAX__);
        printf(text, __INT64_MAX__, __INT64_MAX__, __INT64_MAX__);
    
        return 0;
    }
    Results
    127 127 8458399796925825151
    127 127 8458399796925825151
    32767 32767 8458399796925857791
    32767 32767 8458399796925857791
    2147483647 2147483647 8458399799073308671
    2147483647 2147483647 8458399799073308671
    2147483647 2147483647 8458399799073308671
    -1 2147483647 9223372036854775807
    -1 2147483647 9223372036854775807
    
  • Implications

    • %d and %ld don't make trouble with reading char or short, but %lld is something special.
    • Make sure int == long == int32 in the current standard environment
    • -1 seems interesting. __LONG_LONG_MAX__(== __INT64_MAX__) is 0 111 …… 1111, but %d reads only partial digits from it.
      And the partial number 1 111 …… 1111 indicates -1 as 2's complement.
  • I tried this code with Binary Search 0 (2022.02.11) about the same time,
    but couldn't find why the traversal results are wrong.

  • There was a crazy mistake …… It stole my two months!

    Codes : BinarySearch.c
    #include <stdio.h>
    #include <stdlib.h>                             // malloc()
    typedef struct _tNode                           // It makes using struct easier to declare it with typedef
    {
        int value;
        struct _tNode* left;                        // Node* left : why does it not work?
        struct _tNode* right;                       // should be declared as a pointer
    } Node;
    Node* insert(Node* root, int value)             // The location of '*' doesn't matter
    {
        if (root == NULL)
        {
            Node* root = malloc(sizeof(Node));      // malloc : instead of `new` in C++
            root->value = value;
            root->left = NULL;
            root->right = NULL;
    
            return root;
        }
        else
        {
            if (root->value > value) root->left = insert(root->left, value);
            else root->right = insert(root->right, value);
        }
    
        return root;
    }
    
    Node* delete(Node* root, int value) 
    {
        if (root == NULL) return root;
    
        if (root->value > value) root->left = delete(root->left, value);
        else if (root->value < value) root->right = delete(root->right, value);
        else
        {
            // ing~~~
        }
    
        return root;
    }

    delete() is still imcomplete.

    void preOrder(Node* root)
    {
        if (root == NULL) return;
    
        printf("%d ", root->value);
        preOrder(root->left);
        preOrder(root->right);
    }
    
    void inOrder(Node* root)
    {
        if (root == NULL) return;
    
        inOrder(root->left);
        printf("%d ", root->value);
        inOrder(root->right);
    }
    
    void postOrder(Node* root)
    {
        if (root == NULL) return;
    
        postOrder(root->left);
        postOrder(root->right);
        printf("%d ", root->value);
    }

    I wrote all the inside function names as preOrder() …… crazy~~~

    int main()
    {
        Node* root = NULL;
    
        int arr[6] = {6, 3, 4, 7, 13, 10};
        int len = sizeof(arr) / sizeof(int);
        for (int i = 0; i < len; i++) root = insert(root, arr[i]);
    
        printf("Preorder traversal : ");
        preOrder(root);
        putchar('\n');
    
        printf("Inorder traversal : ");
        inOrder(root);
        putchar('\n');
    
        printf("Postorder traversal : ");
        postOrder(root);
        putchar('\n');
    
        return 0;
    }
    Results
    Preorder traversal : 6 3 4 7 13 10
    Inorder traversal : 3 4 6 7 10 13
    Postorder traversal : 4 3 10 13 7 6
    
  • hope binary_search() in C++ would be a free lunch ……
    but it just returns only true or false depending on the element's presence.

  • Of course, this function seems very powerful for sorted data.

    Codes : BinarySearch.cpp
    #include <iostream>
    #include <vector>
    #include <algorithm>
    int main()
    {
        vector<int> vec = {2, 4, 6, 8, 10, 12};                     // should be sorted
        vector<int> vec2 = {3, 6, 9, 12};
    
        for (auto v : vec2)
        {
            // binary_search() : a function to just return true or false if the value exists
            bool ans = binary_search(vec.begin(), vec.end(), v);
            cout << v << ' ' << ans << endl;
        }
    
        return 0;
    }
    Results
    3 0
    6 1
    9 0
    12 1
    
  • Some extreme(?) experiments about ++ and -- operators

    Codes : IncDecOperator.c
    int main()
    {
        int a = 1, b = 1, c = 1, d = 1, e = 1, f = 1;
    
        a++;
        --b;
        // no problem
    
        c = ++c;
        d = d++;
        // gcc - no problem
        // clang - warning: multiple unsequenced modifications to 'c' [-Wunsequenced]
    
        // e = ++e--;
        // ++e--;
        // f++--++;
        // f++++++;
        // gcc - error: lvalue required as increment operand
        // clang - error: expression is not assignable
    
        printf("Good-bye %d %d %d %d\n", a, b, c, d);
    
        return 0;
    }
    Results
    Good-bye 2 0 2 1
    
  • The way to prevent variable declaration from garbage value

    Codes : PreventGarbageValue.cpp
    int main()
    {
        int garbage;
        int noGarbage{};
    
        cout << garbage << endl;
        cout << noGarbage << endl;
    
        return 0;
    }
    Results
    2686816
    0
    
  • STL Practice : Container Deque and its adaptors Stack and Queue

    • Especially Deque is something greater than vector and list
    • Prior Queue that is also one of the container adaptor from Deque and consists of heap will be continued ……
  • Reference ☞ 코딩 테스트를 위한 자료 구조와 알고리즘 with C++ (길벗, 2020)

    Codes : Containers_Deque.cpp
    #include <deque>
    void print(deque<int> deq)
    {
        for (auto it = deq.begin(); it != deq.end(); it++) cout << *it << ' ';
        cout << endl;
    }
    int main()
    {
        deque<int> deq {1, 2, 3, 4, 5};
        print(deq);
    
        deq.push_front(0);
        print(deq);
    
        deq.push_back(6);
        print(deq);
    
        deq.insert(deq.begin() + 2, 10);
        print(deq);
    
        deq.pop_back();
        print(deq);
    
        deq.pop_front();
        print(deq);
    
        deq.erase(deq.begin() + 1);
        print(deq);
    
        deq.erase(deq.begin() + 3, deq.end());
        print(deq);
    
        // emplace()?
        // emplace_front()?
        // emplace_back()?
    
        return 0;
    }

    1 2 3 4 5
    0 1 2 3 4 5
    0 1 2 3 4 5 6
    0 1 10 2 3 4 5 6
    0 1 10 2 3 4 5
    1 10 2 3 4 5
    1 2 3 4 5
    1 2 3

    Codes : Containers_Stack.cpp
    #include <stack>
    void print(stack<int> stk)
    {
        if (stk.empty()) cout << "The stack is empty." << endl;
        else
        {
            while (!stk.empty())
            {
                cout << stk.top() << ' ';
                stk.pop();
            }
            cout << endl;
        }
    }
    int main()
    {
        stack<int> stk ({1, 2, 3});     // check the different way to declare with initial elements from deque and so on
        print(stk);
    
        stk.push(4);
        print(stk);
    
        stk.push(5);
        print(stk);
    
        stk.pop();
        stk.pop();
        print(stk);
    
        stk.pop();
        stk.pop();
        stk.pop();
        print(stk);
    
        // Any other methods?
    
        return 0;
    }

    3 2 1
    4 3 2 1
    5 4 3 2 1
    3 2 1
    The stack is empty.

    Codes : Containers_Queue.cpp
    #include <queue>
    void print(queue<int> q)
    {
        if (q.empty()) cout << "The que is empty." << endl;
        else
        {
            while (!q.empty())
            {
                cout << q.front() << ' ';
                q.pop();
            }
            cout << endl;
        }
    }
    int main()
    {
        queue<int> q ({1, 2, 3});   // don't forget ()!
        print(q);
    
        q.push(4);
        print(q);
    
        q.push(5);
        print(q);
    
        q.pop();
        q.pop();
        print(q);
    
        q.pop();
        q.pop();
        q.pop();
        print(q);
    
        return 0;
    }

    1 2 3
    1 2 3 4
    1 2 3 4 5
    3 4 5
    The que is empty.

  • Significantly advanced code using template from the previous StackOverflow.cpp

  • I am so proud!

    Codes : Template.cpp
    template <class T>
    // void next (T a) cout << a++ << endl;       // can't write in a line without {}
    void next (T a)
    {
        if (typeid(a) == typeid((char) 'a') || typeid(a) == typeid((unsigned char) 'a'))
        {
            cout << typeid(a).name() << " : " << (int) a << " + 1 = " << (int) ++a << " (converted to ASCII value)" << endl;    
        } else
        {
            cout << typeid(a).name() << " : " << a << " + 1 = " << ++a << endl;
        }
        // there will be more alternatives like type_info and so on ……
    }
    int main()
    {
        next((char) CHAR_MAX);
        next((unsigned char) UCHAR_MAX);
        next((short) SHRT_MAX);
        next((unsigned short) USHRT_MAX);
        next((int) INT_MAX);
        next((unsigned int) UINT_MAX);
        next((bool) 1);                     // warning: use of an operand of type 'bool' in 'operator++' is deprecated
    
        return 0;
    }
    Results

    c : 127 + 1 = -128 (converted to ASCII value)
    h : 255 + 1 = 0 (converted to ASCII value)
    s : 32767 + 1 = -32768
    t : 65535 + 1 = 0
    i : 2147483647 + 1 = -2147483648
    j : 4294967295 + 1 = 0
    b : 1 + 1 = 1

  • "Let's conquer the stack overflow problem!"

  • …… a stupid conquerer who didn't know template and generic function said.

  • Can he learn them or still stay in beginner's swamps? To be continued ……

    Codes : StackOverflow.cpp
    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        // char : -128 to 127 (-2^7 to 2^7 - 1)
        char chr1 = 126;
        char chr2 = chr1 + 1;
        char chr3 = chr2 + 1;
        cout << "char (" << sizeof(char) << ") : " << (short)chr1 << " + 1 = " << (short)chr2 << endl;          // 127
        cout << "char (" << sizeof(char) << ") : " << (short)chr2 << " + 1 = " << (short)chr3 << endl << endl;  // -128
    
        // unsigned char : 0 to 255 (0 to 2^8 - 1)
        unsigned char uChr1 = 254;
        unsigned char uChr2 = uChr1 + 1;
        unsigned char uChr3 = uChr2 + 1;
        cout << "unsigned char (" << sizeof(unsigned char) << ") : " << (short)uChr1 << " + 1 = " << (short)uChr2 << endl;          // 255
        cout << "unsigned char (" << sizeof(unsigned char) << ") : " << (short)uChr2 << " + 1 = " << (short)uChr3  << endl << endl; // 0
    
        // short : -32768 to 32767 (-2^15 to 2^15 - 1)
        short shrt1 = 32766;
        short shrt2 = shrt1 + 1;
        short shrt3 = shrt2 + 1;
        cout << "short (" << sizeof(short) << ") : " << shrt1 << " + 1 = " << shrt2 << endl;            // 32767
        cout << "short (" << sizeof(short) << ") : " << shrt2 << " + 1 = " << shrt3 << endl << endl;    // -32768
    
        // unsigned short : 0 to 65535 (0 to 2^16-1)
        unsigned short uShrt1 = 65534;
        unsigned short uShrt2 = uShrt1 + 1;
        unsigned short uShrt3 = uShrt2 + 1;
        cout << "unsigned short (" << sizeof(unsigned short) << ") : " << uShrt1 << " + 1 = " << uShrt2 << endl;            // 65535
        cout << "unsigned short (" << sizeof(unsigned short) << ") : " << uShrt2 << " + 1 = " << uShrt3 << endl << endl;    // 0
    
        // int : -214748368 to 214748367 (-2^31 to 2^31 - 1)
        int int1 = 2147483646;
        int int2 = int1 + 1;
        int int3 = int2 + 1;
        cout << "int (" << sizeof(int) << ") : " << int1 << " + 1 = " << int2 << endl;          // 2147483647
        cout << "int (" << sizeof(int) << ") : " << int2 << " + 1 = " << int3 << endl << endl;  // -2147483648
        
        // unsigned int : 0 to 4294967295 (0 to 2^32 -1)
        unsigned int uIint1 = 4294967294;
        unsigned int uIint2 = uIint1 + 1;
        unsigned int uIint3 = uIint2 + 1;
        cout << "unsigned int (" << sizeof(unsigned int) << ") : " << uIint1 << " + 1 = " << uIint2 << endl;            // 4294967295
        cout << "unsigned int (" << sizeof(unsigned int) << ") : " << uIint2 << " + 1 = " << uIint3 << endl << endl;    // 0
    
        // bool : 0 to 1
        bool bl1 = false;
        bool bl2 = bl1 + 1;
        bool bl3 = bl2 + 1;
        cout << "bool (" << sizeof(bool) << ") : " << bl1 << " + 1 = " << bl2 << endl;          // 1
        cout << "bool (" << sizeof(bool) << ") : " << bl2 << " + 1 = " << (bool)(bl3) << endl;  // 1
    
        return 0;
    }
    Results

    char (1) : 126 + 1 = 127
    char (1) : 127 + 1 = -128

    unsigned char (1) : 254 + 1 = 255
    unsigned char (1) : 255 + 1 = 0

    short (2) : 32766 + 1 = 32767
    short (2) : 32767 + 1 = -32768

    unsigned short (2) : 65534 + 1 = 65535
    unsigned short (2) : 65535 + 1 = 0

    int (4) : 2147483646 + 1 = 2147483647
    int (4) : 2147483647 + 1 = -2147483648

    unsigned int (4) : 4294967294 + 1 = 4294967295
    unsigned int (4) : 4294967295 + 1 = 0

    bool (1) : 0 + 1 = 1
    bool (1) : 1 + 1 = 1

  • My first run of C/C++ code in Visual Studio Code

    • Environmental setting was harder than coding
    • Find how to complie and run in cosole (rather easier than VS Code menu)
    • gcc (for C) and g++ (for C++) seem not so different to each other
    Codes : IamYourFather_c.c
    #include <stdio.h>
    #include <windows.h>    // for using system()
    
    int main()
    {
        printf("I am your father.\n");
        // system("pause");
        return 0;
    }
    Command Lines to Run IamYourFather_c.c
    gcc --help
    gcc -S IamYourFather_c.c
    gcc IamYourFather_c.c -o IamYourFather_c.exe
    
    .\IamYourFather_c
    

    I am your father.

    Codes : IamYourFather_cpp.cpp
    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        cout << "I am your father." << endl;
        // system("pause");
        return 0;
    }
    Command Lines to Run IamYourFather_cpp.cpp
    g++ --help
    g++ -S IamYourFather_cpp.cpp
    g++ IamYourFather_cpp.cpp -o IamYourFather_cpp.exe
    
    .\IamYourFather_cpp
    

    I am your father.