Learning C Language: Part Eight

Three Essential Elements of a Function

Functionality, Parameters, Return Value.

1. Function Exercises

1. Define four functions to implement the operations of two integers: +, -, *, /

my_add

my_sub

my_mul

my_div

After writing, test the functionality yourself.

#include <stdio.h>
int my_add(int x, int y);
int my_sub(int x, int y);
int my_mul(int x, int y);
double my_div(int x, int y);
void test();
int main(int argc, const char *argv[]) {
    test();
    return 0;
}
void test() {
    printf("%d\n", my_add(10, 20));
    printf("%d\n", my_sub(10, 20));
    printf("%d\n", my_mul(10, 20));
    printf("%f\n", my_div(10, 20));
}
int my_add(int x, int y) {
    int temp = x + y;
    return temp;
}
int my_sub(int x, int y) {
    return x - y;
}
int my_mul(int x, int y) {
    return x * y;
}
double my_div(int x, int y) {
    return (double)x / (double)y;
}

2. Global and Local Variables

#include <stdio.h>
// Lifetime: When the corresponding memory space is allocated and when it is reclaimed
// Scope: In what range it can be used
// The so-called global is the part not enclosed by any {}
// Variables defined globally are called global variables, defined in the static area
// Lifetime: Until the end of the program
// Scope: The entire file  Note, regardless of which function modifies the global variable,
//         all other functions accessing this variable will see the change
// Global variables, if not initialized, will default to 0
int value;
// Global
void test() {
    value = 10;
    // The so-called local refers to the part enclosed by {}
    // Variables defined locally are called local variables
    // Lifetime: Until the current {} ends
    // Scope: Current {}
    int value2 = 520; // Local
    printf("test:value2 = %d\n", value2);
}
int main(int argc, const char *argv[]) {
    test();
    printf("value = %d\n", value); // 10
    // printf("main:value2 = %d\n", value2); // Error
    return 0;
}

3. Function Parameter Passing Methods

3.1 Global Parameter Passing

#include <stdio.h>
int ret = 0;
void my_add(int x, int y) {
    ret = x + y;
}
int main(int argc, const char *argv[]) {
    my_add(10, 20);
    printf("ret = %d\n", ret); // 30
    return 0;
}

3.2 Copy Parameter Passing – Value Passing

#include <stdio.h>
// This parameter passing method is called copy parameter passing, which is equivalent to copying the value of the actual parameter to the formal parameter
// No matter how the formal parameter is modified in the function, the actual parameter will not change
int my_add(int x, int y) {
    x = 520;
    y = 1314;
    printf("x = %d   &amp;x = %p\n", x, &amp;x); // 520
    printf("y = %d   &amp;y = %p\n", y, &amp;y); // 1314
    return x + y;
}
int main(int argc, const char *argv[]) {
    int a = 10;
    int b = 20;
    int ret = my_add(a, b); // Function call will not cause a and b to change
    printf("a = %d   &amp;a = %p\n", a, &amp;a); // 10
    printf("b = %d   &amp;b = %p\n", b, &amp;b); // 20
    printf("ret = %d\n", ret);
    return 0;
}

3.3 Address Parameter Passing – Address Passing

— Very Important

#include <stdio.h>
// x, y, ret are all value passing
// Therefore, no matter how ret is modified in the function, it will not change the ret in the main function
void my_add1(int x, int y, int ret) {
    ret = x + y;
    printf("func:ret = %d  &amp;ret = %p\n", ret, &amp;ret); // 30
}
// x and y are value passing
// p is address passing
// If you want to modify the value of the actual parameter in the function, you need to pass the address of the actual parameter to the function
void my_add2(int x, int y, int *p) {
    printf("func2:p = %p\n", p);
    *p = x + y;
}
int main(int argc, const char *argv[]) {
    int a = 10;
    int b = 20;
    int ret = 0;
    my_add1(a, b, ret);
    printf("main:ret = %d  &amp;ret = %p\n", ret, &amp;ret); // 0
    printf("-----------------------------\n");
    my_add2(a, b, &amp;ret);
    printf("main:ret = %d  &amp;ret = %p\n", ret, &amp;ret); // 30
    return 0;
}

Passing Addresses of Pointer Variables

#include <stdio.h>
int v1 = 520;
int v2 = 1314;
void my_test(int **q) {
    *q = &amp;v2;
}
int main(int argc, const char *argv[]) {
    int *p = &amp;v1;
    my_test(&amp;p);
    printf("*p = %d\n", *p); // 1314
    return 0;
}

4. Passing One-Dimensional Arrays as Parameters

#include <stdio.h>
// Method 1: Pass the address of the array and the number of elements
int print_arr1(int *p, int len) {
    // Generally, when the formal parameter is a pointer, it is best to check for NULL first
    if (NULL == p) {
        printf("p is NULL, please check\n");
        return -1;
    }
    int i = 0;
    // for(i = 0; i < sizeof(p); i++) // Error: sizeof(p) is the size of a pointer, which is fixed
    for (i = 0; i < len; i++) {
        printf("%d  ", p[i]);
    }
    printf("\n");
    return 0;
}
// Method 2: Code self-commenting, also passing a pointer
void print_arr2(int arr[], int len) {
    printf("sizeof(arr) = %ld\n", sizeof(arr)); // 8
    int i = 0;
    for (i = 0; i < len; i++) {
        printf("%d  ", arr[i]);
    }
    printf("\n");
}
int main(int argc, const char *argv[]) {
    int s[5] = {10, 20, 30, 40, 50};
    print_arr1(s, 5);
    printf("-----------------------\n");
    print_arr2(s, 5);
    return 0;
}

5. Passing Two-Dimensional Arrays as Parameters

#include <stdio.h>
// Function to traverse a two-dimensional array
// Passing a two-dimensional array requires using an array pointer
int print_arr(int (*p)[4], int hang, int lie) {
    if (NULL == p) {
        return -1;
    }
    int i = 0;
    int j = 0;
    for (i = 0; i < hang; i++) {
        for (j = 0; j < lie; j++) {
            printf("%d  ", p[i][j]);
        }
        printf("\n");
    }
    return 0;
}
int main(int argc, const char *argv[]) {
    int s[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
    print_arr(s, 3, 4);
    return 0;
}

Exercises:

1. Encapsulate a function to sum all members of an integer array and test it.

#include <stdio.h>
int arr_add(int *p, int len) {
    if (NULL == p) {
        return -1;
    }
    int sum = 0;
    int i = 0;
    for (i = 0; i < len; i++) {
        sum += p[i];
    }
    printf("sum = %d\n", sum);
    return 0;
}
int main(int argc, const char *argv[]) {
    int s[5] = {1, 2, 3, 4, 5};
    arr_add(s, 5);
    return 0;
}

2. Encapsulate a function to sort all members of an integer array and test it.

#include <stdio.h>
int my_sort(int *p, int len, int flag) { // flag 1 for ascending, 0 for descending
    if (NULL == p) {
        return -1;
    }
    int i = 0;
    int j = 0;
    int temp = 0;
    if (1 == flag) { // Ascending
        for (i = 0; i < len - 1; i++) {
            for (j = 0; j < len - 1 - i; j++) {
                if (p[j] > p[j + 1]) {
                    temp = p[j];
                    p[j] = p[j + 1];
                    p[j + 1] = temp;
                }
            }
        }
    } else if (0 == flag) { // Descending
        for (i = 0; i < len - 1; i++) {
            for (j = 0; j < len - 1 - i; j++) {
                if (p[j] < p[j + 1]) {
                    temp = p[j];
                    p[j] = p[j + 1];
                    p[j + 1] = temp;
                }
            }
        }
    }
    return 0;
}
int print_arr(int *p, int len) {
    if (NULL == p) {
        return -1;
    }
    int i = 0;
    for (i = 0; i < len; i++) {
        printf("%d  ", p[i]);
    }
    printf("\n");
    return 0;
}
int main(int argc, const char *argv[]) {
    int s[10] = {12, 34, 32, 6, 54, 87, 123, 90, 1, 100};
    print_arr(s, 10);
    my_sort(s, 10, 1);
    print_arr(s, 10);
    my_sort(s, 10, 0);
    print_arr(s, 10);
    return 0;
}

6. Main Function Parameter Passing

#include <stdio.h>
// When executing the executable file, parameters are separated by spaces
int main(int argc, const char *argv[]) {
    // argc is the number of parameters when executing the program from the command line (including the executable file itself)
    printf("argc = %d\n", argc);
    // argv is an array of pointers
    // Each element is a pointer of type const char *
    // argv[0] points to the executable file name ---- which is our "./a.out"
    // argv[1] points to the first parameter after executing ./a.out
    // ....
    int i = 0;
    for (i = 0; i < argc; i++) {
        printf("%s\n", argv[i]);
    }
    return 0;
}

Exercises:

Reimplement the functionality of a simple calculator, +, -, * (only these are sufficient)

Command line parameters required:

For example:

./a.out 10 + 20 —> 30

./a.out 10 – 20 —> -10

./a.out 10 * 20 —> 200

#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char *argv[]) {
    // atoi is the function to convert string to integer
    int lvalue = atoi(argv[1]);
    char operator = *argv[2];
    int rvalue = atoi(argv[3]);
    int ret = 0;
    switch (operator) {
        case '+':
            ret = lvalue + rvalue;
            break;
        case '-':
            ret = lvalue - rvalue;
            break;
        case '*':
            ret = lvalue * rvalue;
            break;
    }
    printf("ret = %d\n", ret);
    return 0;
}

7. Pointer Functions

The essence is a function that returns a pointer type.

Note, do not return the address of a local variable, as the space occupied by local variables

is reclaimed by the operating system when the function ends.

#include <stdio.h>
int value = 520;
int *my_function(int *p) {
    // return p; // Can return the address passed in by the parameter
    // int temp = 520;
    // return &amp;temp; // Cannot return the address of a local variable, this is incorrect
    // because the space occupied by local variables is reclaimed by the operating system when the function ends
    return &amp;value; // Can return the address of a global variable
    // Can also return the address of a static local variable
}
int main(int argc, const char *argv[]) {
    int a = 1314;
    int *ret = my_function(&amp;a);
    printf("*ret = %d\n", *ret);
    return 0;
}

8. Function Pointers

The essence is a pointer that points to a function.

#include <stdio.h>
int my_add(int x, int y) {
    return x + y;
}
int main(int argc, const char *argv[]) {
    int a = 10;
    int b = 20;
    int ret = 0;
    ret = my_add(a, b);
    printf("ret = %d\n", ret);
    // Function pointers are used to point to functions, so the format of the pointer is different for different types of functions
    // Defined a function pointer p, which can point to a function with return type int and parameter list (int, int)
    int (*p)(int, int) = NULL;
    p = my_add; // Let the pointer point to the function, the function name is the address of the function
    // After the pointer points to the function, both the pointer name and the function name can call the function
    ret = p(a, b);
    printf("ret = %d\n", ret);
    return 0;
}

Application scenarios of function pointers: Callback functions.

#include <stdio.h>
int my_add(int x, int y) {
    return x + y;
}
int my_sub(int x, int y) {
    return x - y;
}
// Callback function:
// Use function pointers as function parameters, and when calling the function through the function pointer,
// which specific function is called depends on the third parameter passed when the user calls the calculation function
int calculation(int x, int y, int (*p)(int, int)) {
    // Different actual parameters, the function called by p is also different
    // Equivalent to p calling the function passed as an actual parameter
    // Therefore, it is called a callback function
    return p(x, y);
}
int main(int argc, const char *argv[]) {
    int a = 10;
    int b = 20;
    int ret = 0;
    ret = calculation(a, b, my_add);
    printf("ret = %d\n", ret); // 30
    ret = calculation(a, b, my_sub);
    printf("ret = %d\n", ret); // -10
    return 0;
}

Example 2:

#include <stdio.h>
#include <signal.h>
void my_function(int x) {
    printf("hello world\n");
}
int main(int argc, const char *argv[]) {
    // The signal function is provided by the system to capture signals
    // The first parameter is the signal to be captured
    // The second parameter is how to handle the captured signal
    // Since the design of the signal function does not know how to handle the signal,
    // it can only provide the function to capture the signal
    // and provide a function pointer as a parameter
    // How to handle it is determined by the second parameter you pass
    // Equivalent to calling the function you provided through the function pointer inside the signal function
    signal(SIGINT, my_function);
    while (1);
    return 0;
}

9. Function Pointer Arrays

The essence is an array, where each element is a function pointer.

#include <stdio.h>
int my_add(int x, int y) {
    return x + y;
}
int my_sub(int x, int y) {
    return x - y;
}
int main(int argc, const char *argv[]) {
    // Defined a function pointer array p, with array length 2
    // Each element is a function pointer of type int (*)(int, int)
    int (*p[2])(int, int) = {NULL, NULL};
    p[0] = my_add;
    p[1] = my_sub;
    int a = 10;
    int b = 20;
    printf("%d\n", p[0](a, b)); // 30
    printf("%d\n", p[1](a, b)); // -10
    return 0;
}

10. Pointer to Function Pointer Arrays

The essence is a pointer that points to an array of function pointers.

#include <stdio.h>
int my_add(int x, int y) {
    return x + y;
}
int my_sub(int x, int y) {
    return x - y;
}
int main(int argc, const char *argv[]) {
    int (*arr[2])(int, int) = {my_add, my_sub};
    // Pointer to the function pointer array arr
    int (*(*p))(int, int) = arr;
    printf("%d\n", p[0](10, 20));
    printf("%d\n", p[1](10, 20));
    return 0;
}

Leave a Comment