"C and Pointers" Reading Notes (Chapter 7 Functions)

In the previous example, we have used the most common function: the main function. In fact, in C language, you can flexibly define your own functions as needed, and in C++, the function types will be more abundant. In object-oriented languages, there is often the concept of method, which looks similar, but in fact has basically the same function. It is an abstraction of a piece of code . It's just that functions pass values ​​directly, while methods directly process data on objects. They depend on classes or objects and cannot exist independently.

As usual, let’s take a look at the knowledge framework (mind map) of this chapter first.

mind Mapping

Insert image description here

7.1 Function definition

There is no popular definition of function in the book. In fact, the popular definition should be the abstraction of a certain piece of code. That is to say, if we want to implement a certain function, we write these codes together and then use the syntax and other symbols, a function is constructed, and then if you want to use this code repeatedly in the future, just call it directly. The syntax of function definition is as follows.

Type function
name (formal parameter)
code block

Another concept needs to be clear: if the function does not need to return a value to the calling program, it will be omitted. Such functions are called in most other languagesprocess. This concept was mentioned in my study of "Operating System".

7.2 Function declaration

Generally, functions will have function declarations and function implementations. There is little difference between a function prototype and a function declaration. Because C language generally starts execution from the main function, and when calling a function, we tell the compiler what the function is called, what the parameters are, and what the return type is. Otherwise, the program will not run smoothly, so function declarations come into being. For example, consider the following program.

#include <stdio.h> 

size_t strlength(char *string);
int main()
{
    
    
	int res = 0;
	char a[] = "qwer";
	res = strlength(a);
	if (res)
		printf("The string length is %d\n",res);
	else
		printf("The string length is zero!\n");
	system("pause");
	return 0;
}

size_t strlength(char *string)
{
    
    
	int length = 0;
	while (*string++ != '\0')
		length++;
	return length;
}

strlengthYou can see that the function is declared at the beginning of the program .

7.3 Parameters of functions

According to popular classification, the parameters of a function are divided into formal parameters and actual parameters. As the name suggests, the formal parameters are the "formal" parameters, and the actual parameters are the parameters passed in during the actual call. In C language, generally what is passed in is a copy of the actual value.Note that it is a copy

If the parameter is an array, the address of the first element of the array is generally passed in. This behavior is called " call by address ". for example.

#include <stdio.h> 

void strexchange(char a[]);
int main()
{
    
    
	int res = 0;
	char a[] = "wwww";
	strexchange(a);
	for(int i = 0; i < 4; i++)
		printf("The string elements is %c\n",a[i]);
	system("pause");
	return 0;
}

void strexchange(char a[])
{
    
    
	a[0] = 'q';
}

Print output
Insert image description here
You can see that in the strexchange function, the modification of the first element of the character array can be completed. So it must be "call by address".

7.4ADT and black box

There is this description in the book:

C can be used to design and implement abstract data types (ADT) because it can show the scope of function and data definitions. This technique can also be called black box design.

In fact, it is easier to understand, that is to say, sometimes during development, we do not need to know the specific implementation process of the function, but simply want to call it to implement the corresponding function.

staticDirect access to it in other files can be restricted via keywords. Therefore, in other files, you only need to pay attention to its functions, without paying attention to its specific implementation process.

There is an example in the book, with some additions later:

Create addrlist.ha file and write the following program:

#pragma once
#define NAME_LENGTH 20                       //姓名最大长度
#define ADDR_LENGTH 100                      //地址最大长度
#define PHONE_LENGTH 11                      //电话号码最大长度
#define MAX_ADDRESSES 1000                   //地址个数限制
void data_init();
char const *lookup_address(char const *name);
char const *lookup_phone(char const *name);

Create addrlist.ca file and write the following program:

#include "addrlist.h"
#include <stdio.h>
#include <string.h>
static char name[MAX_ADDRESSES][NAME_LENGTH];
static char address[MAX_ADDRESSES][ADDR_LENGTH];
static char phone[MAX_ADDRESSES][PHONE_LENGTH];


static int find_entry(char const *name_to_find)
{
    
    
	int entry;
	for (entry = 0; entry < MAX_ADDRESSES; entry++)
		if (strcmp(name_to_find, name[entry]) == 0)
			return entry;
	return -1;

}
//给定一个名字,找到对应的地址,如果找不到,则返回空指针
char const *lookup_address(char const *name)
{
    
    
	int entry;
	entry = find_entry(name);
	if (entry == -1)
		return NULL;
	else
		return address[entry];
}
char const *lookup_phone(char const *name)
{
    
    
	int entry;
	entry = find_entry(name);
	if (entry == -1)
		return NULL;
	else
		return phone[entry];
}
void data_init()
{
    
    
	char name_1[NAME_LENGTH] = "zhangsan";
	for (int i = 0; i < NAME_LENGTH; i++)
	{
    
    
		name[0][i] = name_1[i];
	}
	char address_1[ADDR_LENGTH] = "shanghai/zhangjiang";
	for (int i = 0; i < ADDR_LENGTH; i++)
	{
    
    
		address[0][i] = address_1[i];
	}
}

main.cWrite the following code in :

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

int main()
{
    
    
	static char find_addr[MAX_ADDRESSES] = "zhangsan";
	char const *addr_res = NULL;
	//数据初始化
	data_init();

	addr_res = lookup_address(find_addr);

	
	if (addr_res == NULL)
		printf("^-^");
	else
	{
    
    
		for (int i = 0; i < ADDR_LENGTH; i++)
		{
    
    
			if (addr_res[i] != 0)
				printf("%c", addr_res[i]);
			else
				break;
		}
	}
}

Run and print out:
Insert image description here
You can see that when we input Zhang San , we directly found Zhang San’s address: Zhangjiang, Shanghai . At this time, in the main.c file, we do not know the specific query process. So this has the effect of encapsulation.

7.5 Recursion

Recursion is a very important programming idea. Intuitively, it means that the function calls itself.

Regarding recursion, there is this description in the book:

Once you understand recursion, the easiest way to read a recursive function is not to dwell on its execution, but to trust that the recursive function will complete its task successfully if your steps are correct, your constraints are set correctly, and every call Later, closer to the constraints, the recursive function always gets the job done correctly.

The most classic example is the Fibonacci sequence. The program is as follows:

int fibonacci(int const n)
{
    
    
	int sum = 0;
	if (n == 0)  return 0;
	if (n == 1 || n == 2)  return 1;
	return fibonacci(n - 1) + fibonacci(n-2);
}

Of course, we can also write a non-recursive version, which is just a little more complicated:

int fibonacci(int const n)
{
    
    
	int f1 = 1, f2 = 1, f3 = 0;
	if (n == 0)  return 0;
	if (n == 1 || n == 2)  return 1;

	for (int i = 3; i <= n; i++)
	{
    
    
		f3 = f1 + f2;
		f1 = f2;
		f2 = f3;
	}
	return f3;
}

You may find the non-recursive version easier to understand at first, but after you get used to it, you will find the recursive version more convenient. And sometimes, using recursion is much easier than looping, such as the following example:

  1. Everyone adds up

Given a non-negative integer num, repeatedly add the digits until the result is a single digit. Return this result.

If we use a non-recursive method, it may be difficult to solve. One of the solutions is as follows:

int addDigits(int num){
    
    
    int add = 0;
    do
    {
    
       
        add = 0;  
        while(num > 0)
        {
    
    
            add += num % 10;
            num /= 10;
        }
        num = add;
    }while(add >= 10);

    return add;
}

That is, when the summation result is greater than 10, continue to perform the same operation until it is less than 10, return the calculated result. But if we use recursion, it becomes even simpler:

int addDigits(int num){
    
    
    int add = 0;
    while(num > 0)
    {
    
    
        add += num % 10;
        num /= 10;
    }
    num = add;
    return add < 10 ? add : addDigits(add);
}

For so-called repeated operations, we can directly call it recursively, and then output the desired results.

Note: It is necessary to grasp the depth of recursion and ensure that the recursion is terminable, otherwise a stack overflow may occur.

7.6 Variable parameter list

In actual project development, we often encounter situations where the number of parameters passed is unknown. In this case, we need to use a variable parameter list. There is an example in the book:

//可变参数列表头文件
#include<stdarg.h>

float average(int n_values, ...)
{
    
    
	va_list var_arg;
	int count;
	float sum = 0;
	//准备访问可变参数
	va_start(var_arg, n_values);
	//添加取自可变参数的值
	for (count = 0; count < n_values; count++)
	{
    
    
		sum += va_arg(var_arg, int);
	}
	//完成处理可变参数
	va_end(var_arg);
	return sum / n_values;
}

It is a function that averages, but we don’t know in advance how many numbers need to be averaged. When calling, you can do this:

	printf("%f\n", average(10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10));

You can directly print out the calculated results and print the output:
Insert image description here
Note: The variable parameters must be accessed one by one in order from beginning to end. If you want to stop halfway after accessing several variadic parameters, this is OK.

From this point of view, the access of variable parameter lists and linked lists are very similar.

Summarize

C language can also be used to design and implement abstract data types.

Recursion is very convenient to use after you become proficient, but it is not so efficient in all cases. At the same time, be aware of the stack overflow problems that may result from this.

---------------------------------------------------------------------------END---------------------------------------------------------------------------

Guess you like

Origin blog.csdn.net/weixin_43719763/article/details/128194759