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 &x = %p\n", x, &x); // 520
printf("y = %d &y = %p\n", y, &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 &a = %p\n", a, &a); // 10
printf("b = %d &b = %p\n", b, &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 &ret = %p\n", ret, &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 &ret = %p\n", ret, &ret); // 0
printf("-----------------------------\n");
my_add2(a, b, &ret);
printf("main:ret = %d &ret = %p\n", ret, &ret); // 30
return 0;
}
Passing Addresses of Pointer Variables
#include <stdio.h>
int v1 = 520;
int v2 = 1314;
void my_test(int **q) {
*q = &v2;
}
int main(int argc, const char *argv[]) {
int *p = &v1;
my_test(&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 &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 &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(&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;
}