"Trampas C y Defectos"----Capítulo 3 Trampas Semánticas

3.1 Punteros y matrices

  1. Solo hay matrices unidimensionales en lenguaje C. Los elementos del arreglo pueden ser objetos de cualquier tipo, lo que también es la base teórica para la construcción de arreglos multidimensionales.
  2. Con una matriz, solo podemos hacer dos cosas: determinar el tamaño de la matriz y obtener un puntero al elemento en el índice 0 de la matriz.Cualquier operación de subíndice de matriz es equivalente a una operación de puntero correspondiente.
  3. El nombre de la matriz representa la dirección del primer elemento, que no se puede operar con ++ ni –. En otras palabras, no podemos cambiar el nombre de la matriz (valor representado), porque el nombre de la matriz es una constante y no se puede modificar.

3.2 Punteros que no son arreglos

Aquí hay un programa que señala su error:

char *r;
r = malloc(strlen(s)+strlen(t));
strcpy(r,s);
strcat(r,t);
  1. Es posible que Malloc no pueda proporcionar la memoria solicitada, en cuyo caso la función malloc devolverá un puntero nulo como señal del evento "fallo de asignación de memoria".
  2. La memoria asignada a r debe liberarse a tiempo después de que se agote.
  3. La rutina anterior no asigna suficiente memoria al llamar a malloc porque la cadena también contiene el marcador final '\0'.

3.3 Declaraciones de matrices como parámetros

1. Las dos expresiones enumeradas a continuación son equivalentes:

char hello[] = "hello";
printf("%s\n",hello);//写法1
printf("%s\n",&hello);//写法2

Motivo: el nombre de matriz hola representa la dirección del primer elemento de la matriz hola.

2. Las dos formas de escribir siguientes son equivalentes:

int strlen(char s[])
{
	/*具体内容*/
}
int strlen(char *s)
{
	/*具体内容*/
}

3. Tenga en cuenta las siguientes dos formas de escribir:

extern char *hello;
extern char hello[];

Aunque estas dos formas de escribir son correctas, los significados que nos transmiten las diferentes formas son completamente inconsistentes y tenemos que usarlos de acuerdo con la situación específica.

3.4 Un puntero nulo no es una cadena vacía

Aviso:Un puntero nulo no puede desreferenciarlo.

Al mismo tiempo, tenga cuidado de no escribir lo siguiente:

if(strcmp(p,(char*)0)==0)
	···

Esta forma de escribir es ilegal, porque la implementación de la función de biblioteca strcmp incluirá una operación para ver a qué apunta su parámetro de puntero, es decir, eliminar la referencia del puntero nulo.

Tampoco puede aparecer la siguiente grafía:

Supongamos que p es un puntero nulo

printf(p);
printf("%s",p);
//当然,这两种写法是等价的

Este comportamiento no está definido.

3.5 Cálculo de límites y límites asimétricos

  1. Antes de escribir el bucle, es mejor escribirlo así:

    int i = 0;
    for(i = 0;i < 10; i++)
    	···
    

    Escribiendo de esta forma se puede ver mejor el número de bucles, es decir, 10 veces.

  2. Cuando hay 10 elementos en el arreglo, el subíndice va de 0 a 9, pero cuando solo necesitamos referirnos a la dirección de este elemento cuando no necesitamos referirnos a este elemento, podemos escribir así

    int arr[10] = {1,2,3,4,5,6,7,8,9,10};
    for(int i = 0;&arr[i]<&(arr[10]);i++)
    	···
    

    De esta manera, los números de los elementos de la matriz del 1 al 10 se pueden imprimir sin problemas,

    El estándar ANSI C permite explícitamente este uso: la dirección de un elemento de "desbordamiento" en la matriz que en realidad no existe se ubica después de la memoria ocupada por la matriz fuera de la matriz, y esta dirección se puede usar para asignaciones y comparaciones. Por supuesto, sería ilegal hacer referencia al elemento. El resultado de leer realmente el valor del elemento no está definido y muy pocos compiladores detectan ocasionalmente este error. Por supuesto, si intenta modificar este elemento, inevitablemente hará que el programa se bloquee, ¡lo cual es un acceso ilegal!

3.6 Orden de evaluación

Solo hay cuatro operadores en C (&&, ||, ?: y ,) que tienen un orden de evaluación prescrito. El operador == && y el operador || evalúan primero el operando de la izquierda y el operando de la derecha solo si es necesario. ==El operador ?: tiene tres operandos: en a?b:c. Primero se evalúa el operando a, y luego se calcula el valor del operando b o c según el valor de a (en este momento solo se ejecutará una de las dos expresiones b o c según el resultado de la anterior a expresión).El operador de coma primero evalúa el operando izquierdo, luego "descarta el valor" y luego evalúa el operando derecho.

Nota: Los argumentos de la función de división no son operadores de coma. Por ejemplo, el orden de evaluación de xey en la función f(x,y) no está definido, pero en la función g((x,y)) es un orden definido de x primero y luego y. En el último ejemplo, la función g tiene solo un parámetro. El valor de este parámetro se obtiene evaluando primero x, luego "desechando" el valor de x y luego evaluando el valor de y.

La existencia de este orden de evaluación permite que algunos programas "incorrectos" se vuelvan correctos y, después de la ejecución, produzcan resultados correctos:

if(count!=0 && sum/count < smallaverage)
	···

Nota: El orden en que todos los demás operadores en C evalúan sus operandos no está definido. En particular, el operador de asignación no garantiza ningún orden de evaluación.

Por ejemplo: la siguiente copia de los primeros n elementos de la matriz x a la matriz y es incorrecta porque hace demasiadas suposiciones sobre el orden de evaluación:

i = 0;
while(i < n)
	y[i] = x[i++];

El código anterior asume que la dirección de y[i] se evaluará antes de que i se incremente para señalar, pero este no es necesariamente el caso, depende de la implementación específica del compilador. Asimismo, la siguiente notación es incorrecta:

i = 0;
while(i<n)
	y[i++] = x[i];

Modifíquelo a la siguiente escritura y funcionará normalmente:

i = 0;
while(i<n)
{
	y[i] = x[i];
	i++;
}

Por supuesto, esta forma de escribir también se puede abreviar como:

for(i = 0;i < n;i++)
	y[i] = x[i];

3.9 Desbordamiento de enteros

Los enteros sin signo no se desbordarán, lo que estipula el lenguaje C. Si el resultado es mayor que el valor máximo M que se puede representar, el módulo (M+1), es decir, se produce un truncamiento.

Se produce un desbordamiento cuando se suman dos enteros con signo y el resultado del desbordamiento no está definido.

Aquí hay una forma incorrecta de verificar:

if(a + b < 0)
	complain();

Porque cuando a+bocurre un desbordamiento, todas las suposiciones sobre cómo será el resultado ya no son confiables.

Aquí hay dos formas correctas:

//方法一:
if((unsigned)a + (unsigned) > INT_MAX)
	complain();
//方法二:
if(a > INT_MAX - b)
	complain()

3.10 Proporcionar valores de retorno para funciones

El lenguaje C a menudo devuelve un valor para informar al sistema operativo si la ejecución tiene éxito o falla.La solución típica es. Un valor de retorno de 0 indica que el programa se ejecutó correctamente y un valor de retorno distinto de cero indica que el programa no se pudo ejecutar.A menudo agregamos la operación de retorno 0 al final del programa.

Supongo que te gusta

Origin blog.csdn.net/m0_57304511/article/details/123509516
Recomendado
Clasificación