Ir al contenido principal

Expresiones y Operaciones C++


Expresiones y Operadores

En C casi todo es una expresión. Por ejemplo, la instrucción de asignación "=" regresa el valor del operando derecho. Como un "efecto secundario", también establece el valor del operando izquierdo. Así,




  ix = 12;
le da a ix el valor de 12 (asumiendo que ix es del tipo apropiado). Como la asignación también es una expresión, podemos combinar varias de ellas ; por ejemplo :

  kx = jx = ix = 12;
¿Qué sucede ? La primera asignación le da a kx el valor de su derecha. Este es el valor de la asignación a jx. Pero ésta última es el valor de la asignación a ix. El valor de ix es 12, el cuál es regresado a jx que a su vez es regresado a kx. Así, hemos expresado

  ix = 12;
  jx = 12;
  kx = 12;
en una línea.
Verdadero en C se define como sigue. El valor 0 (cero) significa FALSE (falso). Cualquier otro valor es TRUE (verdadero). Por ejemplo, la función estándar strcmp() lleva dos strings como argumentos y regresa -1 si el primero es inferior al segundo, 0 si son iguales y 1 si el primero es mayor que el segundo. Para comparar si dos strings str1 y str2 son iguales, seguido ves la siguiente construcción if:

  if (!strcmp(str1, str2)) {
    /* str1 es igual a str2 */
  }
  else {
    /* str1 no es igual a str2 */
  }
El signo de admiración indica el NOT booleano. Así, la expresión evalúa TRUE solamente si strcmp() regresa 0.
Las expresiones son combinaciones de ambos términos y operadores. Los primeros podrían ser constantes, variables o expresiones. De los segundos, C ofrece todos los operadores conocidos de otros lenguajes. Sin embargo, ofrece algunos operadores que podrían ser vistos como abreviaciones a combinaciones de otros operadores. La Tabla 7.3 muestra los operadores disponibles. La segunda columna muestra su prioridad, donde los números más chicos indican prioridad más alta y números iguales, prioridad igual. La última columna enlista el orden de evaluación.


Table 7.3:  Operadores.

\begin{tabular}
{\vert c\vert c\vert p{0.4\textwidth}\vert l\vert} \hline
{\bf O...
 ...rom right \\  \hline
, & 15 & Comma operator & from left \\  \hline\end{tabular}

La mayoría de estos operadores ya son conocidos para ti. Sin embargo, algunos necesitan alguna descripción adicional. Primero que nada, nótese que los operadores booleanos binarios &and son de menor prioidad que los operadores de igualdad == and!=. Consecuentemente, si quieres checar patrones de bits como en

  if ((pattern & MASK) == MASK) {
    ...
  }
debes encerrar la operación binaria entre paréntesis [*].
Los operadores de incrementeo ++ y $-\,-$ pueden ser explicados por medio del siguiente ejemplo. Si tienes la siguiente secuencia de instrucciones

  a = a + 1;
  b = a;
puedes usar el operador de preincremento

  b = ++a;
En forma similar, si tienes el siguiente orden de instrucciones :

  b = a;
  a = a + 1;
puedes usar el operador de postincremento

  b = a++;
De esta manera, el operador de preincremento primero incrementa su variable asociada y entonces, regresa el nuevo valor ; mientras que el operador de postincremento primero regresa el valor y después incrementa su variable. Se aplican las mismas reglas para los operadores de pre- y postdecremento $-\,-$.
Las llamadas a funciones, las asignaciones anidadas y los operadores de incremento/decremento provocan efectos secundarios cuando se aplican. Esto puede introducir dependencias del compilador debido a que el orden de evaluación en algunas situaciones es dependiente del compilador. Considera el siguiente ejemplo que demuestra esto:

  a[i] = i++;
La pregunta es, si el nuevo o el viejo valor de i se usa como subíndice dentro del arreglo a depende del orden que use el compilador para evaluar la asignación.
El operador condicional ?: es una abreviatura para una instrucción if de uso común. Por ejemplo para asignarle a max el valor máximos de entre a y b, podemos usar la siguiente instrucción if:

  if (a > b) 
    max = a;
  else
    max = b;
Estos tipos de instrucciones if pueden ser más cortas si se escriben así

  max = (a > b) ? a : b;
El siguiente operador poco común es el operador de asignación. Nosotros seguido estamos usando asignaciones de la forma siguiente

  expr1 = (expr1) op (expr2)
por ejemplo

  i = i * (j + 1);
En estas asignaciones, el valor de la izquierda también aparece en el lado derecho. Por medio de lenguaje informal, podríamos expresar esto como "poner al valor de i i el valor actual de i multiplicado por la suma del valor de j más 1''. Usando una manera más natural, diríamos más bien "Multiplicar i por la suma del valor de j más 1''. C nos permite abreviar estos tipos de asignaciones a

  i *= j + 1;
Nosotros podemos hacer éso con casi todos los operadores binarios. Nótese que el operador de asignación de arriba realmente implementa la forma larga "j + 1'' no esté entre paréntesis.
El último operador poco común es el operador coma (,). Se explica mejor por medio de un ejemplo:

  i = 0;
  j = (i += 1, i += 2, i + 3);
Este operador toma sus argumentos y los evalúa de izquierda a derecha y regresa el valor de la expresión de la derecha. Así, en el ejemplo de arriba, el operador primero evalúa "i += 1" lo cuál, como un efecto secundario, incrementa el valor de i. Después, es evaluada la siguiente expresión "i += 2" la cuál añade 2 a i conduciendo al valor de 3. La tercera expresión es evaluada y su valor es regresado como el resultado del operador. Así, se le asigna 6 a j.
El operador coma presenta una particular posiblidad de cometer el siguiente error cuando se usan arreglos de n-dimensiones siendo $n\gt 1$. Un error frecuente es usar una lista de índices separados por comas para tratar de accesar un elemento:

  int matrix[10][5];  // matriz de 2-dimensiones
  int i;

  ...
  i = matrix[1,2];    // ¡¡NO FUNCIONARA ! !
  i = matrix[1][2];   // OK
Lo que actualmente sucede en el primer caso es que la lista separada por comas es interpretada como un operador coma. Por consecuencia, el resultado es 2, lo que conduce a una asignación de la dirección a los terceros cinco elementos de la matriz.
Algunos de ustedes se podrían preguntar que es lo que C hace con valores que no son usados. Por ejemplo en las instrucciones de asignación que hemos visto anteriormente,

  ix = 12;
  jx = 12;
  kx = 12;
tenemos tres líneas cada una de las cuáles regresa 12. La respuesta es que C ignora los valores que no se usan. Esto lleva a algunas cosas extrañas. Por ejemplo, tú podrías escribir algo como ésto :

  ix = 1;
  4711;
  jx = 2;
Olvidemos estas cosas extrañas y regresemos a algo de más utilidad. Hablemos de funciones.

7.1.4 Funciones

Debido a que C es un lenguaje procedimental, permite la definición de funciones. Los procedimientos son "simulados" por funciones que no regresan "ningún valor". Este valor es un tipo especial llamado void.
Las funciones se declaran en forma similar a las variables, pero aquéllas encierran sus argumentos entre paréntesis (aún si no llevan argumentos, los paréntesis deben ser especificados):

  int sum(int to);  /* Declaración de sum con un argumento */
  int bar();        /* Declaración de bar sin argumentos */
  void foo(int ix, int jx);
                    /* Declaración de foo con dos argumentos */
Para definir efectivamente una función, simplemente añade su cuerpo :

  int sum(int to) {
    int ix, ret;
    ret = 0;
    for (ix = 0; ix < to; ix = ix + 1)
      ret = ret + ix;
    return ret;      /* regresa el valor de la función */
  } /* sum */
C solamente permite que pases los argumentos de las funciones por valor. Por consecuencia, no puedes cambiar el valor de un argumento dentro de la función. Si tu debes pasar un argumento por referencia, debes programarlo por ti mismo(a). Para tal efecto usas apuntadores.

7.1.5 Apuntadores y Arreglos

Uno de los problemas más comunes al programar en C (y algunas veces en C++) es la comprensión de apuntadores y arreglos. En C (C++) ambos están altamente relacionados ; con algunas pequeñas pero esenciales diferencias. Tú declaras un apuntador poniendo un asterisco entre el tipo de datos y el nombre de la variable o función :

  char *strp;      /* strp es un "apuntador a char" */
Se accesa el contenido de un apuntador derreferenciándolo por medio de -otra vez- el asterisco :

  *strp = 'a';            /* Un carácter simple */
Al igual que en otros lenguajes, se debe proveer algún espacio para el valor al cuál el apuntador está apuntando. Un apuntador a caracteres puede ser usado para apuntar a una secuencia de caracteres : el string. Los strings en C están terminados por un carácter especial NUL (0 o como char '${\backslash}0$'). Así, puedes tener strings de cualquier longitud. Los strings se encierran en dobles comillas:

  strp = "hello";
En este caso, el compilador automáticamente agrega el carácter de terminación NUL. De este modostrp apunta a una secuencia de 6 caracteres. El primer carácter es 'h', el segundo es 'e' y así sucesivamente. Podemos accesar estos caracteres por medio de un índice en strp:

  strp[0]     /* h */
  strp[1]     /* e */
  strp[2]     /* l */
  strp[3]     /* l */
  strp[4]     /* o */
  strp[5]     /* \0 */
El primer carácter también es igual a "*strp" que puede ser escrito como "*(strp + 0)". Esto nos lleva a algo llamado aritmética de apuntadores lo cuál constituye una de las poderosas cararacterísticas de C. Así, tenemos las siguientes ecuaciones :

  *strp == *(strp + 0) == strp[0]
           *(strp + 1) == strp[1]
           *(strp + 2) == strp[2]
           ...
Nótese que estas ecuaciones son verdaderas para cualquier tipo de datos. La suma no está orientada a bytes, está orientada al tamaño del correspondiente tipo del apuntador.
El apuntador strp puede ser puesto en otras localidades. Su destino puede variar. En contraste con eso, los arreglos son apuntadores fijos. Apuntan a una predefinida área de memoria, la cuál es especificada por corchetes :

  char str[6];
Puedes ver a str como un apuntador constante apuntando a una área de 6 caracteres. No podemos usar ésto del siguiente modo:

  str = "hallo";   /* ERROR */
debido a que esto significaría cambiar el apuntador para que apuntara a 'h'. Debemos copiar el string al área de memoria provista. Por lo tanto, usamos una función llamada strcpy() la cuál es parte de la biblioteca estándar de C.

  strcpy(str, "hallo"); /* Ok */
Nota sin embargo, que podemos usar str en cualquier caso donde un apuntador a carácter es utilizado, debido a que es un apuntador (si bien fijo).

7.1.6 Un Primer Programa

Presentamos aquí el primer programa tab frecuentemente usado : un programa que despliega "Hello, world !" en tu pantalla :

  #include <stdio.h>

  /* Aquí deberían ir las variables globales */
  /* Las definiciones de funciones deberián ir aquí */
  int
  main() {
    puts("Hello, world!");
    return 0;
  } /* main */
La primera línea se ve algo extraña. Su explicación requiere alguna información acerca de como los programas en C (y C++) son manejados por el compilador. La compilación se divide gruesamente en dos pasos. El primer paso es llamado "preprocesamiento" y se usa para preparar código C "en bruto". En este caso, este paso toma la primera línea como un argumento para incluir un archivo llamado stdio.h dentro del código fuente. Los corchetes angulares simplemente indican que el archivo debe ser buscado en la trayectoria de búsqueda estándar configurada para tu compilador. El archivo en sí mismo provee algunas declaraciones y definiciones para input/output estándar. Por ejemplo, declara la función llamada put(). Este paso del preprocesador también borra todos los comentarios.
En el segundo paso, el "código en bruto" de C generado se compila como un ejecutable. Cada ejecutable debe definir una función llamada main(). Es esta función la que es llamada cuando el programa es arrancado. Esta función regresa un entero que significa el estatus de salida del programa.
La función main() puede llevar argumentos que vienen a representar los parámetos de la línea de comandos. Los presentamos aquí solamentes pero no damos ninguna explicación ulterior :

  #include <stdio.h>

  int
  main(int argc, char *argv[]) {
    int ix;
    for (ix = 0; ix < argc; ix++) 
      printf("My %d. argument is %s\n", ix, argv[ix]);
    return 0;
  } /* main */
El primer argumento argc regresa simplemente el número de argumentos dados en la línea de comandos. El segundo argumento argv es un arreglo de strings. (Recuerda que todos los strings se representan por apuntadores a caracteres. Así, argv es un arreglo de apuntadores a caracteres.)

Comentarios

Entradas populares de este blog

Como descargar e instalar Fuentes en tu PC

Los  distintos tipos de letras nos permiten generar trabajos impresos de mejor calidad.  De allí la importancia de poseer en nuestra computadora de un gran número de fuentes entre las cuales elegir. Tanto los   profesionales del diseño gráfico   como todos aquellos que solemos utilizar nuestra computadora para realizar trabajos impresos, conocemos la importancia de disponer de un importante número de fuentes. 

(Blogger) Corazones que sube por el blog

Cupido ya está a la vuelta de la esquina y ahora no es el amor el que está en el aire sino los corazones, muchos corazones. Giffy.me  nos ofrece estos dos scripts que harán que tu blog se inhunde de romanticismo al mostrar muchos  corazones subiendo como globos por el blog . Son dos diseños, el primero son corazones color rosa de un tamaño mediano, el segundo son corazones pequeños en color rojo; en ambos casos los corazones subirán por la página moviéndose de un lado al otro.

C# - Jerarquia de Operaciones - .NET

El problema de no tomar en cuenta la jerarquía de los operadores al plantear y resolver una operación casi siempre conduce a resultados muchas veces equivocados como estos: