Tabla de Contenidos

Comparación entre C y Java

Generalidades

Programación orientada a objetos

Tipos primitivos

Strings

Punteros

La siguiente tabla compara la sintaxis usada para las distintas operaciones con punteros:

Java C
declaración
Node p;
Node *p;
asignación de memoria
p= new Node();
p= malloc(sizeof Node);
acceso
Node q= p.next;
Node *q= p->next;
destrucción
free(p);
puntero nulo
p= null;
p= NULL;

Variables locales de tipo compuesto

Instrucciones

Java heredó las todas las instrucciones de control de C y por lo tanto las siguientes construcciones sintácticas funcionan igual que en Java:

Pero se debe tener cuidado si el compilador implementa una versión de C anterior al estándar C99, como por ejemplo ansi-C.

Antes de C99 el ciclo for no admite declarar la variable de control en la misma expresión de inicialización. Por ejemplo el siguiente código es ilegal:

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

La forma correcta es:

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

Además las declaraciones de variables antes de C99 siempre debían ir al comienzo de un bloque { … }. Por ejemplo era ilegal:

  int i;        /* declaración */
  i= getchar(); /* no es una declaración */
  int j;        /* error de sintaxis, porque no viene después de una declaración */
  j= ...;

Pero este código sí es correcto:

  int i= getchar(); /* sí es declaración */
  int j;            /* otra declaración */
  j= ...;

A partir de C99 sí se admiten declaraciones en cualquier punto y declaraciones en el ciclo for.

Funciones

La sintaxis para declarar un función es la misma de los métodos de Java, solo que una función no está contenida en la declaración de una clase. Por ejemplo, la función que calcula el factorial recursivamente es:

  /* Archivo fact.c */
  double fact(int n) {
    if (n<=1)
      return 1;
    else
      return n*fact(n-1);
  }

Para usar esta función en otro archivo se debe declarar un prototipo o encabezado de la función previamente:

  /* Archivo main.c */
  double fact(int n);  /* prototipo o encabezado de la función fact */
  
  int main(int argc, char **argv) {
    double res= fact(atoi(argv[1]));  /* invoca la función fact */
    printf("%e\n", res); /* despliega el resultado en la salida esstándar */
    return 0;
  }

Archivos de encabezado

Declarar los encabezados de la funciones en cada archivo en donde se usa es peligroso porque si uno se equivoca en el tipo de los parámetros o el valor de retorno, el compilador no avisa y el resultado es imprevisible. La solución es crear archivos que contengan solo los encabezados de un grupo de funciones. Estos archivos de encabezado tienen la extensión “.h” y normalmente se incluyen al inicio de los archivos en donde se usan la funciones incluidas.

Para el ejemplo anterior, el archivo de encabezado sería:

  /* archivo fact.h */
  double fact(int n);

Y el archivo en donde se usa:

  /* Archivo main.c */
  #include "fact.h"
  
  /* no declarar un encabezado para fact */
  
  int main(int argc, char **argv) {
    double res= fact(atoi(argv[1]));  /* invoca la función fact */
    printf("%e\n", res); /* despliega el resultado en la salida esstándar */
    return 0;
  }

Previo a la verdadera compilación de un archivo, el compilador invoca el preprocesador de C (llamado cpp) que se encarga de expandir literalmente los #include reemplazándolos por el contenido del archivo con los encabezados.

De esta forma, uno se debe preocupar solamente de la consistencia de los parámetros de la función declarada con los parámetros que aparecen en el archivo de encabezados “.h”. Esto reduce considerablemente la probabilidad de error.