Notas de lectura de "C y punteros" (Capítulo 7 Funciones)

En el ejemplo anterior, hemos utilizado la función más común: la función principal. De hecho, en lenguaje C, puedes definir de manera flexible tus propias funciones según sea necesario, y en C++, los tipos de funciones serán más abundantes. En los lenguajes orientados a objetos, a menudo existe el concepto de método, que parece similar, pero en realidad tiene básicamente la misma función: es una abstracción de un fragmento de código . Es solo que las funciones pasan valores directamente, mientras que los métodos procesan datos directamente en los objetos, dependen de clases u objetos y no pueden existir de forma independiente.

Como de costumbre, primero echemos un vistazo al marco de conocimiento (mapa mental) de este capítulo.

mapas mentales

Insertar descripción de la imagen aquí

7.1 Definición de función

No existe una definición popular de función en el libro. De hecho, la definición popular debería ser la abstracción de un determinado fragmento de código, es decir, si queremos implementar una determinada función, escribimos estos códigos juntos y luego usamos la sintaxis y otros símbolos, se construye una función y luego, si desea utilizar este código repetidamente en el futuro, simplemente llámelo directamente. La sintaxis de la definición de función es la siguiente.

Escriba el bloque de código
del nombre de la función (parámetro formal)

Otro concepto debe quedar claro: si la función no necesita devolver un valor al programa que llama, se omitirá. Estas funciones se llaman en la mayoría de los otros idiomas.proceso. Este concepto fue mencionado en mi estudio sobre "Sistema operativo".

7.2 Declaración de función

Generalmente, las funciones tendrán declaraciones de funciones e implementaciones de funciones. Hay poca diferencia entre un prototipo de función y una declaración de función. Debido a que el lenguaje C generalmente comienza la ejecución desde la función principal, y cuando llamamos a una función, le decimos al compilador cómo se llama la función, cuáles son los parámetros y cuál es el tipo de retorno. De lo contrario, el programa no se ejecutará correctamente, por lo que surgen declaraciones de funciones. Por ejemplo, considere el siguiente programa.

#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;
}

strlengthPuedes ver que la función está declarada al comienzo del programa .

7.3 Parámetros de funciones

Según la clasificación popular, los parámetros de una función se dividen en parámetros formales y parámetros reales. Como sugiere el nombre, los parámetros formales son los parámetros "formales" y los parámetros reales son los parámetros pasados ​​durante la llamada real. En lenguaje C, generalmente lo que se pasa es una copia del valor real.Tenga en cuenta que es una copia.

Si el parámetro es una matriz, generalmente se pasa la dirección del primer elemento de la matriz. Este comportamiento se denomina " llamada por dirección ". Por ejemplo.

#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';
}

Salida de impresión
Insertar descripción de la imagen aquí
Puede ver que en la función strexchange, se puede completar la modificación del primer elemento de la matriz de caracteres. Entonces debe ser "llamar por dirección".

7.4ADT y caja negra

Hay esta descripción en el libro:

C se puede utilizar para diseñar e implementar tipos de datos abstractos (ADT) porque puede mostrar el alcance de las funciones y las definiciones de datos. Esta técnica también se puede llamar diseño de caja negra .

De hecho, es más fácil de entender, es decir, a veces durante el desarrollo, no necesitamos conocer el proceso de implementación específico de la función, simplemente queremos llamarla para implementar la función correspondiente.

staticEl acceso directo a él en otros archivos se puede restringir mediante palabras clave. Por lo tanto, en otros archivos, solo es necesario prestar atención a sus funciones, sin prestar atención a su proceso de implementación específico.

Hay un ejemplo en el libro, con algunas adiciones más adelante:

Crea addrlist.hun archivo y escribe el siguiente programa:

#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);

Crea addrlist.cun archivo y escribe el siguiente programa:

#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.cEscribe el siguiente código en :

#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;
		}
	}
}

Ejecute e imprima:
Insertar descripción de la imagen aquí
puede ver que cuando ingresamos Zhang San , encontramos directamente la dirección de Zhang San: Zhangjiang, Shanghai . En este momento, en el archivo main.c, no conocemos el proceso de consulta específico. Entonces esto tiene el efecto de encapsulación.

7.5 Recursión

La recursividad es una idea de programación muy importante: intuitivamente significa que la función se llama a sí misma.

En cuanto a la recursividad, existe esta descripción en el libro:

Una vez que comprenda la recursividad, la forma más fácil de leer una función recursiva es no insistir en su ejecución, sino confiar en que la función recursiva completará su tarea con éxito si sus pasos son correctos, sus restricciones están configuradas correctamente y cada llamada posterior. más cerca de las restricciones, la función recursiva siempre hace el trabajo correctamente.

El ejemplo más clásico es la secuencia de Fibonacci, el programa es el siguiente:

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);
}

Por supuesto, también podemos escribir una versión no recursiva, que es un poco más complicada:

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;
}

Es posible que la versión no recursiva le resulte más fácil de entender al principio, pero una vez que se acostumbre, encontrará que la versión recursiva es más conveniente. Y a veces, usar la recursividad es mucho más fácil que hacer bucles, como en el siguiente ejemplo:

  1. todos suman

Dado un número entero no negativo num, suma repetidamente los dígitos hasta que el resultado sea un solo dígito. Devuelve este resultado.

Si utilizamos un método no recursivo, puede resultar difícil de resolver, una de las soluciones es la siguiente:

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;
}

Es decir, cuando el resultado de la suma es mayor que 10, continúa realizando la misma operación hasta que sea menor que 10, devuelve el resultado calculado. Pero si usamos la recursividad, se vuelve aún más sencillo:

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

Para las llamadas operaciones repetidas, podemos llamarlo directamente de forma recursiva y luego generar los resultados deseados.

Nota: Es necesario comprender la profundidad de la recursividad y asegurarse de que la recursividad sea terminable; de ​​lo contrario, puede producirse un desbordamiento de la pila.

7.6 Lista de parámetros variables

En el desarrollo de proyectos reales, a menudo nos encontramos con situaciones en las que se desconoce el número de parámetros pasados, en este caso necesitamos utilizar una lista de parámetros variables. Hay un ejemplo en el libro:

//可变参数列表头文件
#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;
}

Es una función que promedia, pero no sabemos de antemano cuántos números deben promediarse. Al llamar, puedes hacer esto:

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

Puede imprimir directamente los resultados calculados e imprimir el resultado:
Insertar descripción de la imagen aquí
Nota: Se debe acceder a los parámetros variables uno por uno en orden de principio a fin. Si desea detenerse a mitad de camino después de acceder a varios parámetros variables, está bien.

Desde este punto de vista, el acceso a listas de parámetros variables y listas vinculadas es muy similar.

Resumir

El lenguaje C también se puede utilizar para diseñar e implementar tipos de datos abstractos.

La recursividad es muy conveniente de usar una vez que se vuelve competente, pero no es tan eficiente en todos los casos. Al mismo tiempo, tenga en cuenta los problemas de desbordamiento de pila que pueden surgir de esto.

-------------------------------------------------- -------------------------FIN------------------------ -------------------------------------------------- -

Supongo que te gusta

Origin blog.csdn.net/weixin_43719763/article/details/128194759
Recomendado
Clasificación