tipos the significado reservadas programming palabras lenguaje language funciones español ejemplos caracteristicas c

the - ¿Cuáles son las nociones importantes en C que no aprendiste de tus maestros?



the c++ programming language español pdf (30)

En septiembre, daré mis primeras conferencias sobre C a estudiantes en la escuela de ingeniería (normalmente enseño matemáticas y procesamiento de señales, pero también he hecho mucho trabajo práctico en C, sin dar las conferencias). La informática no es su tema principal (son más estudios de electrónica y procesamiento de señales), pero necesitan tener una buena formación en programación (algunos de ellos pueden convertirse en desarrolladores de software)

Este año será su segundo año de aprendizaje de C (se supone que deben saber qué es un puntero y cómo usarlo, pero, por supuesto, esta noción aún no se ha asimilado)

Además de las cosas clásicas (estructuras de datos, algoritmos clásicos, ...), probablemente centraré algunas de mis conferencias en:

  • Diseñe el algoritmo (y escríbalo en pseudocódigo) antes de codificarlo en C (piense antes de codificar)
  • Haga que su código sea legible (comentarios, nombres de variables, ...) y
  • Punteros, punteros, punteros! (qué es, cómo y cuándo usarlo, asignación de memoria, etc.)

Según su experiencia, ¿cuáles son las nociones más importantes en C que sus maestros nunca le enseñaron? ¿En qué punto particular debo enfocar?

Por ejemplo, ¿debería presentarles algunas herramientas ( lint , ...)?


  1. Verifica los limites
  2. Compruebe los límites,

    y por supuesto,

  3. Revisa los límites.

Y si olvidó una de estas reglas, use Valgrind. Esto se aplica a matrices, cadenas y punteros, pero en realidad es muy fácil olvidarse de lo que realmente está haciendo al hacer asignaciones y aritmética de memoria.


¿Qué hay de las mejores prácticas generales?

  • Siempre asuma que alguien más ya ha escrito su código y que está disponible gratuitamente en Internet y mejor escrito y probado que cualquier cosa que produzca antes de su fecha límite.
  • Regresa temprano / Evita las cláusulas
  • Inicializar todas las variables
  • Una página por función como guía (es decir, utilice piezas de código más pequeñas juntas)
  • Cuándo usar switch, if-else if, o una tabla hash
  • Evitar variables globales.
  • Siempre revise sus entradas y sus salidas (no confío en mi propio código).
  • La mayoría de las funciones deberían devolver un estado

    [Para otros: siéntase libre de editar esto y agregarlo a la lista]

Con respecto a las entradas de control:

Una vez escribí un programa grande a toda prisa y escribí todo tipo de cláusulas de Guardia, verificaciones de entrada, en mis funciones. Cuando ejecuté el programa por primera vez, los errores de esas cláusulas se transmitieron tan rápido que ni siquiera pude leerlos, pero el programa no se bloqueó y se cerró limpiamente. Entonces era una simple cuestión de repasar la lista y corregir errores que fueron sorprendentemente rápidos.

Piense en las cláusulas de la Guardia como advertencias y errores del compilador en tiempo de ejecución.


Advertencias siempre activas. Con GCC, use al menos -Wall -Wextra -Wstrict-prototypes -Wwrite-strings .

I / O es difícil. scanf() es el mal. gets() nunca debe utilizarse.

Cuando imprime algo que no está ''/n'' terminado, debe vaciar la stdout si desea imprimirlo inmediatamente, por ejemplo

printf("Type something: "); fflush(stdout); getchar();

Utilice los punteros const siempre que sea posible. Por ejemplo, void foo(const char* p); .

Utilice size_t para almacenar tamaños.

Las cuerdas litterales generalmente no pueden modificarse, así que haz que sean const . Por ejemplo, const char* p = "whatever"; .


Creo que la idea general parece realmente buena. Estas son algunas cosas extra.

  1. Un depurador es un buen amigo.
  2. Revisa los límites.
  3. Asegúrese de que el puntero esté apuntando a algo antes de usarlo.
  4. Gestión de la memoria.

Cuando tuve que usar C como parte de un proyecto más grande en la escuela, fue la capacidad de usar gdb correctamente (es decir, en absoluto) lo que terminó por predecir quién terminaría su proyecto y quién no. Sí, si las cosas se vuelven locas y tienes un montón de errores relacionados con la memoria y el puntero, gdb mostrará información extraña, pero incluso sabiendo que puede apuntar a las personas en la dirección correcta.

También recordarles que C no es C ++, Java, C #, etc. es una buena idea. Esto ocurre con mayor frecuencia cuando ves a alguien tratando a un char * como una cadena en C ++.


Dados sus antecedentes, quizás un buen enfoque en C para sistemas integrados, incluyendo:

  • Herramientas de análisis estático (por ejemplo, PC-Lint )
  • MISRA-C .
  • Exposición a múltiples procesadores (por ejemplo, PIC, STM32) y compiladores
  • Cómo depurar.
  • Problemas en tiempo real, incluyendo interrupciones, señales de rebote, programación simple / RTOS.
  • Diseño de software.

Y muy significativamente: software de control de versiones . Trabajo en la industria y lo uso religiosamente, pero estoy asombrado de que nunca se mencionó en el curso de mi carrera.


El depurador es tu amigo. C es un lenguaje fácil de desordenar y la mejor manera de entender sus errores es a menudo verlos en un depurador.


Enséñales la prueba de unidad.


Entendiendo el enlazador. Cualquiera que use C debería entender por qué "static int x;" en el alcance del archivo no crea una variable global. El ejercicio de escribir un programa simple en el que cada función está en su propia unidad de traducción y compilar cada una por separado no se realiza con suficiente frecuencia en las primeras etapas del aprendizaje C.


Espero que esto no se haya publicado antes (solo lea muy rápido), pero creo que lo que es muy importante cuando tiene que trabajar con C, es conocer la representación de datos en la máquina. Por ejemplo: números de punto flotante IEEE 754, big vs little endian, alineación de estructuras (aquí: Windows vs Linux) ... Para practicar esto, es muy útil hacer algunos rompecabezas de bits (resolver algunos problemas sin usar ninguna funcionalidad) luego, printf para imprimir el resultado, un número limitado de variables y algunos operadores lógicos). También a menudo es útil tener un conocimiento básico sobre cómo funciona un enlazador, cómo funciona todo el proceso de compilación, etc. Pero sobre todo entender el enlazador (sin eso, es muy difícil encontrar algún tipo de error ...)

El libro que más me ayudó a mejorar mis habilidades en C y C ++ fue: http://www.amazon.com/Computer-Systems-Programmers-Randal-Bryant/dp/013034074X

Creo que un profundo conocimiento de la arquitectura de la computadora hace la diferencia entre un programador de C bueno y uno malo (o al menos es un factor importante).


Esta palabra clave en C: volatile


Estilo de sangría. Todos los maestros estaban diciendo que el código debe estar sangrado, pero nadie realmente dio instrucciones sobre cómo hacerlo. Recuerdo que el código de todos los estudiantes era realmente un desastre.


Hay demasiados para nombrarlos a todos. Algunos de ellos son específicos de C; Algunos de ellos son el mejor tipo de cosas en general.

  • Aprende a utilizar las herramientas disponibles.
    • Sistema de control de revisiones. Cada vez que funcione, registralo.
    • Diferentes herramientas: diff, rdiff, meld, kdiff3, etc. Especialmente en conjunto con el RCS.
    • Opciones del compilador. -Wextra -Wall __attribute __ ((alineado (8))), cómo empaquetar estructuras.
    • Marca: Produce versiones de depuración y producción.
    • depurador: cómo obtener e interpretar un seguimiento de pila. Cómo establecer puntos de interrupción. Cómo pasar a través / sobre el código.
    • Editor: Compilar dentro del editor. Abra varias ventanas, Mx tags-query-replace (¿se muestran mis raíces de emacs?) Etc.
    • cscope, kscope, [ce] tags u otras herramientas de navegación de origen
  • Programa defensivo. assert (foo! = NULL) en -DDEBUG; scrub entradas de usuario.
  • Detener y Catch Fire cuando se detecta un error. La depuración es más fácil cuando realiza un volcado de 2 líneas después de detectar el problema.
  • Mantenga una compilación de advertencia 0 con -Wextra y -Wall habilitados.
  • No ponga todo en 1 enorme archivo .c de bocina.
  • Prueba. Prueba. Y prueba un poco más. Y revisa esas pruebas junto a tu fuente. Porque el instructor puede volver y cambiar los requisitos después de que se haya entregado una vez.

Las herramientas son importantes, así que recomiendo al menos mencionar algo sobre

  • Makefiles y cómo funciona el proceso de construcción
  • gdb
  • hilas
  • La utilidad de las advertencias del compilador.

Con respecto a C, creo que es importante enfatizar que el programador debe saber lo que realmente significa "comportamiento indefinido", es decir, saber que podría haber un problema futuro incluso si parece funcionar con la combinación actual de compilador / plataforma.

Edit: Olvidé: enseñarles cómo buscar y hacer preguntas adecuadas sobre SO!


Los efectos secundarios (peligrosos) de las macros.


Mis maestros pasaron tanto tiempo enseñándonos que los punteros son pequeños goobers que pueden causar muchos problemas si no se usan correctamente, que nunca se molestaron en mostrarnos lo poderosos que pueden ser.

Por ejemplo, el concepto de aritmética de punteros era extraño para mí hasta que ya había estado utilizando C ++ durante varios años:

Ejemplos:

  • c [0] es equivalente a * c
  • c [1] es equivalente a * (c + 1)
  • Iteración de bucle: para (char * c = str; * c! = ''/ 0''; c ++)
  • y así...

En lugar de hacer que los alumnos tengan miedo de usar punteros, enséñeles cómo usarlos adecuadamente.

EDITAR: Como me llamó la atención un comentario que acabo de leer sobre una respuesta diferente, creo que también hay algo de valor en discutir las diferencias sutiles entre los punteros y las matrices (y cómo unirlas para facilitar algunas estructuras bastante complejas), así como la forma correcta de usar la palabra clave const con respecto a las declaraciones de puntero.


No creo que debas estar enseñando herramientas. Eso debería dejarse a los profesores de Java. Son útiles y ampliamente utilizados, pero no tienen nada que ver con C. Un depurador es todo lo que deberían tener acceso. Muchas veces todo lo que obtiene es printf y / o un LED parpadeante.

Enséñeles punteros pero enséñeles bien, diciéndoles que son una variable entera que representa una posición en la memoria (en la mayoría de los cursos también tienen algo de capacitación en ensamblaje, incluso si es para alguna máquina imaginaria, por lo que deberían poder entender eso) y no es una variable con un prefijo de asterisco que de alguna manera apunta a algo y que a veces se convierte en una matriz (C no es Java). Enséñeles que las matrices C son solo puntero + índice.

Pídales que escriban programas que se desborden y segreguen con seguridad y después de eso, asegúrese de que entiendan por qué sucedió.

La biblioteca estándar también es C, pídales que lo usen y que sus programas mueran dolorosamente en sus pruebas privadas debido a que han usado get () y strcpy () o algo de doble liberación.

Oblígalos a lidiar con variables de diferente tipo, endianness (tus pruebas podrían ejecutarse en un arco diferente), de flotación a conversión int. Haz que usen máscaras y operadores bit a bit.

es decir, enseñarles C.

Lo que obtuve en cambio fue un procesamiento por lotes en C que también podría haberse hecho en GW-BASIC.


Orientación a objetos:

struct Class { size_t size; void * (* ctor) (void * self, va_list * app); // constructor method void * (* dtor) (void * self); // destructor method void (* draw) (const void * self); // draw method };

( Código fuente )


Portabilidad: rara vez se enseña o se menciona en la escuela, pero aparece mucho en el mundo real.


Realmente deberían aprender a usar herramientas de ayuda (es decir, cualquier otra cosa que no sea el compilador).

1) Valgrind es una excelente herramienta. Es increíblemente fácil de usar y rastrea las fugas de memoria y la corrupción de la memoria a la perfección.

Les ayudará a entender el modelo de memoria de C: qué es, qué puede hacer y qué no debe hacer.

2) GDB + Emacs con gdb-many-windows. O cualquier otro depurador integrado, de verdad.

Ayudará a aquellos que son perezosos a pasar por el código con lápiz y papel.

Realmente no restringido a C; Esto es lo que creo que deberían aprender:

1) Cómo escribir correctamente el código: Cómo escribir un código que no se puede mantener . Al leer eso, encontré al menos tres delitos de los que fui culpable.

En serio, escribimos código para otros programadores . Por lo tanto, es más importante para nosotros escribir con claridad que escribir con inteligencia .

Usted dice que sus estudiantes no son en realidad programadores (son ingenieros). Entonces, no deberían estar haciendo cosas difíciles, deberían enfocarse en una codificación clara .

2) STFW. Cuando comencé a programar (comencé en Pascal, luego me mudé a C), lo hice leyendo libros. Pasé innumerables horas tratando de averiguar cómo hacer cosas.

Más tarde, descubrí que todo lo que había tenido que averiguar ya había sido hecho por muchos otros, y al menos uno de ellos lo había publicado en línea.

Tus estudiantes son ingenieros; No tienen tanto tiempo para dedicarse a la programación . Entonces, el poco tiempo que tienen, deben pasar leyendo el código de otras personas y, tal vez, repasando los modismos .

Con todo, C es un lenguaje bastante fácil de aprender. Tendrán muchos más problemas para escribir algo más que unas pocas líneas que para aprender nociones independientes.


Repase todo el ciclo de vida de la programación, incluido lo que sucede con su código una vez que haya terminado con él .

  • Etapas previas a la planificación, y un poco sobre cómo buscar un proyecto / código existente que pueda usar para reducir la cantidad de código original
  • Una pequeña descripción general (básica) de las licencias y cómo ese código externo afecta a las licencias que puede y no puede usar (y otras consideraciones relacionadas con la licencia)
  • Control de versiones concurrentes, y control de versiones. Haría SVN / Git, pero para cada uno lo suyo. Los ahorrará MUCHO tiempo si se los presenta ahora en lugar de aprender en el trabajo.
  • Muéstrales qué vías hay para el código de código abierto (Google Code, Github, etc.) y cuándo / cómo saber si es apropiado o no.

Nada de esto es específico de C, pero lo agrego porque, personalmente, acabo de pasar por la "C para Ingenieros Eléctricos" en mi universidad, y esto es todo lo que tenía que descubrir por mi cuenta.


Sepa que cuando incrementa un puntero, la nueva dirección depende del tamaño de los datos apuntados por ese puntero ... (IE, ¿cuál es la diferencia entre un carácter * incrementado y un largo sin signo *) ...

Saber exactamente qué es realmente una falla de segmentación en primer lugar, y también cómo tratar con ellos.

Saber cómo usar GDB es genial. Saber cómo usar valgrind es genial.

Desarrollar un estilo de programación en C ... Por ejemplo, tiendo a escribir código bastante orientado a objetos cuando escribo grandes programas en C (por lo general, todas las funciones en un archivo .C en particular aceptan algunas (1) estructuras en particular * y operan en él. .. Tiendo a tener foo * foo_create () y foo_destroy (foo *) ctor''s y dtors ...) ...


Sería beneficioso si los estudiantes estuvieran expuestos en algún momento a herramientas que les ayuden a escribir código mejor y más limpio. Es posible que no todas las herramientas sean relevantes para ellos en esta etapa, pero saber qué hay disponible ayuda.

También se debe hacer hincapié en el uso de compiladores diferentes (!) Con indicadores de advertencia de compilador estrictos y atender a todos y cada uno de los mensajes de advertencia.


Sin firmar vs firmado.

Operadores de cambio de bit

Enmascaramiento de bits

Ajuste de bits

tamaños enteros (8 bits, 16 bits, 32 bits)


Una noción importante en C que no aprendí de mis maestros es:

Operador * no significa "puntero a" (en el lado izquierdo). En cambio, es el operador de referencia, exactamente como está en el lado derecho (sí, sé que es molesto para algunos).

Así:

int *pInt

significa que cuando no se hace referencia a pInt, se obtiene un int. Por lo tanto, pInt es un puntero a int. O dicho de otra manera: * pInt es un int - no referenciado pInt es un int; pInt debe ser un puntero a int (de lo contrario, no obtendríamos un int cuando se elimine la referencia).

Esto significa que no es necesario aprender de memoria declaraciones más complicadas:

const char *pChar

* pChar es de tipo const char. Por lo tanto pChar es un puntero a const char.

char *const pChar

* const pChar es de tipo char. Así, const pChar es un puntero a char (pChar en sí es constante).

const char * const pChar

* const pChar es de tipo const char. Así, const pChar es un puntero a const char (pChar es constante).



Uso de la palabra clave const en el contexto de los punteros:

La diferencia entre las siguientes declaraciones:

A) const char* pChar // pointer to a CONSTANT char B) char* const pChar // CONSTANT pointer to a char C) const char* const pChar // Both

Así que con A:

const char* pChar = ''M''; *pChar = ''S''; // error: you can''t modify value pointed by pChar

Y con B:

char OneChar = ''M''; char AnotherChar = ''S''; char* const pChar = &OneChar; pChar = &AnotherChar; // error: you can''t modify address of pChar


Utilice un estilo de codificación coherente y legible.

(Esto también debería ayudarlo a revisar su código).

Relacionados: No optimizar prematuramente. Perfil primero para ver dónde está el cuello de botella.


  • Donde termina el lenguaje y comienza la implementación: por ejemplo, stdio.h es parte de la biblioteca estándar, conio.h no, cosas así;
  • La diferencia entre un comportamiento indefinido y definido por la implementación, y por qué cosas como x = x ++ no están definidas;
  • Solo porque compila no significa que sea correcto;
  • La diferencia entre la prioridad y el orden de evaluación, y por qué a * b + c no garantiza que a se evaluará antes de b o c;
  • "Funciona en mi máquina" no supera el comportamiento especificado por el estándar de idioma: por ejemplo, solo porque void main () o x = x ++ le está dando los resultados que espera para una plataforma específica y el compilador no significa que esté bien de usar ;
  • Imagina que nunca has oído hablar de get ();

  • La memoria en papel puede desencadenar todo tipo de errores extraños.
  • Los depuradores pueden mentirte.