Está en la página 1de 15

C# DESDE EL PUNTO DE VISTA DE C

C# es un lenguaje de programacin bastante semejante en lo que a sintaxis se refiere a C++. Por otra parte, C++ puede considerarse como un superconjunto de C. En este documento analizaremos diversos ejemplos de programacin utilizados habitualmente en C, y su correspondiente codificacin en C#. Por lo tanto, este documento no pretende ser un estudio exhaustivo de los tipos de datos, estructuras de control y libreras de C#, sino una muestra de un conjunto de ejemplos de cdigo escritos en ambos lenguajes. No se trata entonces de justificar todo cuanto se escribe, con cuidado de haber dado previamente las definiciones necesarias, sino de mostrar de forma intuitiva las diferencias sintcticas de ambos lenguajes en aquellos aspectos en que nos encontramos familiarizados en C. En otras palabras, con esto se quiere justificar la posible falta de rigor expositivo. Todo lo que aqu se muestra, se muestra de forma muy simple, procurando huir de elementos muy diferenciales. La forma de proceder utilizada en C# para estos ejemplos no es la ms adecuada, sino la ms aproximada a C, sin exponer en ningn caso otras alternativas mejores disponibles. Se parte de la base de que el alumno sabe C, y este documento es una primera toma de contacto con el nuevo lenguaje partiendo de ese supuesto. Por lo tanto, si el alumno no comprende los ejemplos propuestos en C, debera repasar un poco los contenidos de las asignaturas previas. Para simplificar el cdigo al mximo y quedarnos con lo esencial en lo que a sintaxis se refiere, todos los ejemplos estn realizados en modo consola, tanto en C como en C#.

1. Hola mundo.
Hola mundo en C
#include <stdio.h> void main (int argc, char* argv[]) { printf ("Hola mundo\n"); }

Hola mundo en C#
using System; namespace Simple { class CSimple { [STAThread] static void Main(string[] args) { Console.Write ("Hola mundo\n"); } } }

El ejemplo de la izquierda muestra un tpico programa Hola mundo en C. Es necesaria la directiva #include para poder usar la librera que define la funcin printf. La funcin main recibe el nmero de argumentos pasados por la lnea de comandos, y el array de cadenas de caracteres que los contiene. El ejemplo de la derecha muestra un tpico programa Hola mundo escrito en C#. Es necesaria la lnea using System para acceder a la clase Console y al mtodo Write. La funcin Main en este caso recibe directamente un array de strings (cadenas de caracteres en C#), como en el caso anterior. El nmero de argumentos est implcito en el array de C#. En C#, adems, es necesario un espacio de nombres (namespace Simple) y una clase (class CSimple), para poder contener la funcin Main, que ser el punto de entrada del programa al ejecutarse. Desde un punto de vista prctico y, si se quiere, simplista, dentro de la clase CSimple pondremos todo lo que pondramos en el fichero fuente de C a excepcin de las directivas include y define.

2. Declaracin de variables elementales e impresin de informacin por pantalla.


Ejemplo en C #include <stdio.h> void main (int argc, char* argv[]) { int i=4; double k=3.74; char C[] = "Hola que tal"; printf ("i = %d, k = %f, C = %s\n",i,k,C); } Ejemplo en C# using System; namespace Simple { class CSimple { [STAThread] static void Main(string[] args) { int i = 4; double k = 3.74; string C = "Hola que tal"; Console.Write ("i = {0}, k = {1}, C = {2}\n",i,k,C); Console.WriteLine ("i = " + i + ", k = " + k + ", C = " + C); } } } Vemos que las declaraciones de variables (por ahora) son semejantes en ambos lenguajes. Se ha declarado en C un array de caracteres, aunque no es un tipo simple, para comprobar su equivalencia con el tipo string de C#. En C# se ha hecho la impresin, usando el mtodo Write de Console, de dos formas diferentes: La primera usa {0}, {1}, etc. para indicar los argumentos a imprimir, mostrando su semejanza con los %d y %f, de C. La segunda usa el operador de concatenacin de strings (+), para unir los fragmentos que se desean imprimir. Como vemos, las variables se declaran en C# de forma semejante a C, y el mtodo Console.Write es el equivalente al printf, con algunas diferencias de formato.

3. Entrada de datos por la consola (teclado). Conversin de tipos.


Ejemplo en C #include <stdio.h> void main { char int float (int argc, char* argv[]) Cadena[256]; DatoEntero; DatoReal;

printf ("Introduce tu nombre: "); scanf ("%s",Cadena); printf ("Introduce tu edad: "); scanf ("%d",&DatoEntero); printf ("Introduce el precio de una barra de pan: "); scanf ("%f",&DatoReal); printf ("Tu nombre: %s\n",Cadena); printf ("Tu edad: %d\n",DatoEntero); printf ("Barra pan: %f\n",DatoReal); } Ejemplo en C# using System; namespace Simple { class CSimple { [STAThread] static void Main(string[] args) { string Cadena; int DatoEntero; double DatoReal; Console.Write ("Introduce tu nombre: "); Cadena = Console.ReadLine(); Console.Write ("Introduce tu edad: "); DatoEntero = Convert.ToInt32 (Console.ReadLine()); Console.Write ("Introduce el precio de una barra de pan: "); DatoReal = Convert.ToDouble (Console.ReadLine ()); Console.WriteLine ("Tu nombre: " + Cadena); Console.WriteLine ("Tu edad: " + DatoEntero.ToString()); Console.WriteLine ("Barra pan: " + DatoReal.ToString("0.00")); } } } Vemos que toda la entrada por la consola se realiza a travs de la funcin ReadLine de Console. ReadLine lee hasta que llega un <CR> (ENTER) del teclado, y retorna siempre un string. Es como si utilizramos scanf (%s,Cad) siempre, y luego convirtiramos la cadena de caracteres (con las funciones atoi y atof). Las operaciones de la clase Convert permiten convertir los strings ledos por el teclado al tipo de datos deseado.

4. Operadores.
En general, los operadores de C son semejantes a los de C#. Tenemos la suma, la resta, el producto, la divisin (+, -, *, /, %), tambin operadores de comparacin (==, !=, >, ), operadores de bits, etc. La siguiente tabla resume los operadores de C#.

Categoras
Aritmticos Lgicos (booleanos y bit a bit) Concatenacin de cadenas Incremento y decremento Desplazamiento Relacionales Asignacin Acceso a miembros Indizacin Conversin de tipos explcita Condicional Concatenacin y eliminacin de delegados Creacin de objetos Informacin de tipos Control de excepciones de desbordamiento Direccionamiento indirecto y direccin
+ & + ++ << == = . [] () ?: + new is * sizeof -> [] typeof & checked unchecked ->> != += < -= > *= <= /= | * ^ / ! % ~ && ||

Operadores
false true

>= %= &= |= ^= <<= >>=

5. Sentencias de control y palabras reservadas.


Las sentencias de control tambin son bsicamente las mismas. C# tiene algunas ms, que ya iremos viendo, pero por ahora no son relevantes. Un if se escribe igual en C que en C#, un for y un while tambin, etc. Por el momento no debemos prestarle ms atencin a este tema, aunque debemos saber que C# es ms potente que C en este aspecto. La lista de palabras reservadas de C# es la siguiente: abstract as base bool break byte case catch char checked class const continue decimal default delegate do double else enum event explicit extern false finally fixed float for foreach goto if implicit in int interface internal is lock long namespace new null object operator out override params private protected public readonly ref return sbyte sealed short sizeof stackalloc static string struct switch this throw true try typeof uint ulong unchecked unsafe ushort using virtual volatile void while

6. Declaracin y recorrido bsico de arrays.


Ejemplo en C #include <stdio.h> void main (int argc, char* argv[]) { int Numeros[5]; int i; for (i=0 ; i<5 ; i++) Numeros[i] = i; for (i=0 ; i<5 ; i++) printf ("%d ",Numeros[i]); } Ejemplo en C# using System; namespace Simple { class CSimple { [STAThread] static void Main(string[] args) { int[] Numeros = new int[5]; int i; for (i=0 ; i<5 ; i++) Numeros[i] = i; for (i=0 ; i<5 ; i++) Console.Write ("{0} ",Numeros[i]); } } } Como vemos en este caso, el manejo de arrays es bastante semejante en ambos lenguajes. La diferencia fundamental esta en la declaracin, como puede verse claramente. En el caso de C#, un array ha de construirse, con el operador new. Por ahora no vamos a ahondar en el tema de la construccin, basta con creer que es as, y utilizarlo, y dentro de poco tiempo lo entenderemos mejor. Ejemplo en C #include <stdio.h> void main (int argc, char* argv[]) { int Numeros[] = {1,2,3,4,5}; int i; for (i=0 ; i<5 ; i++) printf ("%d ",Numeros[i]); } Ejemplo en C# using System; namespace Simple { class CSimple { [STAThread] static void Main(string[] args) { int[] Numeros = new int[] {1,2,3,4,5}; for (int i=0 ; i<5 ; i++) Console.Write ("{0} ",Numeros[i]); } } } En el ejemplo anterior se muestra la declaracin esttica de un array, en ambos lenguajes. Vemos tambin la declaracin de la variable de control dentro del for, algo muy habitual en el estilo de programacin de C#.

7. Declaracin y llamadas a funciones.


Ejemplo en C #include <stdio.h> int UnaFuncion (int p, int q) { return (p+q); } void main (int argc, char* argv[]) { int Resultado; Resultado = UnaFuncion (7,2); printf ("%d\n",Resultado); } Ejemplo en C# using System; namespace Simple { class CSimple { static int UnaFuncion (int p, int q) { return (p+q); } [STAThread] static void Main(string[] args) { int Resultado = UnaFuncion (7,2); Console.WriteLine (Resultado); } } } Vemos que tanto la declaracin y las llamadas a funciones son muy semejantes en ambos lenguajes. En C# se puede inicializar una variable con el resultado de una expresin ejecutable, a diferencia de C (en C++ esto tambin est permitido).

8. Paso de parmetros por referencia.


Ejemplo en C #include <stdio.h> void UnaFuncion (int* p) { *p = *p + 2; } void main (int argc, char* argv[]) { int Dato = 7; UnaFuncion (&Dato); printf ("%d\n",Dato); } Ejemplo en C# using System; namespace Simple { class CSimple { static void UnaFuncion (ref int p) { p = p + 2; } [STAThread] static void Main(string[] args) { int Dato = 7; UnaFuncion (ref Dato); Console.WriteLine (Dato); } } } Un uso muy comn de los punteros en C es el paso de parmetros por referencia. Sin embargo, en C# los punteros son considerados como algo no seguro, y hay otras maneras de efectuar esta operacin. Vemos en el ejemplo que el parmetro se marca con el modificador ref, y que tambin se indica al invocar la funcin. Para enviar parmetros por referencia, ya no son necesarios los punteros, y no han de utilizarse para ello. El paso de estructuras por referencia tambin es diferente en C# con respecto a C. En C# es preferible utilizar objetos (elementos de clases) en lugar de estructuras, y en este caso, el paso de parmetros es siempre por referencia, aunque no se indique. Esto lo veremos en un ejemplo posterior.

9. Uso de punteros.
Ya se ha comentado anteriormente que no es necesario utilizar punteros en C#. Si an as queremos seguir utilizndolos (no en esta asignatura), es necesario marcar las funciones que los usen como no seguras. Ejemplo en C# using System; namespace Simple { class CSimple { unsafe static void UnaFuncion (int* p) { *p = *p + 2; } [STAThread] unsafe static void Main(string[] args) { int Dato = 7; UnaFuncion (&Dato); Console.WriteLine (Dato); } } } Para que el ejemplo anterior funcione, se ha de compilar el proyecto con el parmetro /unsafe, estableciendo la propiedad de cdigo no seguro de la siguiente manera:

En resumen, evitaremos usar punteros.

10. Definicin de estructuras.


Ejemplo en C #include <stdio.h> #include <string.h> typedef struct { char Nombre[80]; int Edad; } Persona;

void main (int argc, char* argv[]) { Persona P; P.Edad = 39; strcpy (P.Nombre,"Ruben Hidalgo"); printf ("%d - %s\n",P.Edad,P.Nombre); } Ejemplo en C# using System; namespace Simple { class CSimple { class Persona { public string Nombre; public int Edad; } [STAThread] static void Main(string[] args) { Persona P = new Persona(); P.Edad = 39; P.Nombre = "Ruben Hidalgo"; Console.WriteLine ("{0} - {1}",P.Edad,P.Nombre); } } } En C# son preferibles las clases a las estructuras. En el ejemplo anterior vemos la declaracin de la clase Persona, semejante a la estructura equivalente de C. Los miembros de la clase deben ser pblicos (public) para que la clase sea equivalente a la estructura. Salvo en la declaracin de la variable de tipo Persona (revisar el ejemplo anterior que mostraba la declaracin de un array), el uso de una clase definida de este modo y una estructura es prcticamente el mismo.

11. Paso de estructuras/objetos por parmetro.


Ejemplo en C #include <stdio.h> #include <string.h> typedef struct { char Nombre[80]; int Edad; } Persona; void TratarPersona (Persona* X) { X->Edad++; } void main (int argc, char* argv[]) { Persona P; P.Edad = 39; strcpy (P.Nombre,"Ruben Hidalgo"); printf ("%d - %s\n",P.Edad,P.Nombre); TratarPersona (&P); printf ("%d - %s\n",P.Edad,P.Nombre); } Ejemplo en C# using System; namespace Simple { class CSimple { class Persona { public int Edad; public string Nombre; } static void TratarPersona (Persona X) { X.Edad++; } [STAThread] static void Main(string[] args) { Persona P = new Persona(); P.Edad = 39; P.Nombre = "Ruben Hidalgo"; Console.WriteLine ("{0} - {1}",P.Edad,P.Nombre); TratarPersona (P); Console.WriteLine ("{0} - {1}",P.Edad,P.Nombre); } } } Tal como se comentaba en un punto anterior, el paso de objetos es siempre por referencia, y vemos en este ejemplo que la edad de la persona pasada por parmetro queda modificada, tal como en el ejemplo equivalente en C. El paso de estructuras por valor funciona en C, siempre y cuando la estructura no contenga ningn puntero o elemento dinmico, ya que entonces los resultados pueden ser impredecibles. Por este motivo C# no lo soporta.

12. Arrays dinmicos.


Ejemplo en C
#include <stdio.h> #include <malloc.h> #include <string.h> typedef struct { char Nombre[80]; int Edad; } Persona; typedef struct { Persona* Gente; int NumPersonas; } Personas; void IniPersonas (Personas* X) { X->Gente = NULL; X->NumPersonas = 0; } void FinPersonas (Personas* X) { free (X->Gente); X->Gente = NULL; X->NumPersonas = 0; } void AgregarPersona (Personas* X, Persona* P) { X->Gente = (Persona*) realloc (X->Gente,sizeof(Persona)*(X->NumPersonas+1)); X->Gente[X->NumPersonas++] = *P; } void EliminarPersona (Personas* X, int Indice) { int i; for (i=Indice ; i<X->NumPersonas-1 ; i++) X->Gente[i] = X->Gente[i+1]; X->Gente = (Persona*) realloc (X->Gente,sizeof(Persona)*(--X->NumPersonas)); } void ImprimirPersonas (Personas* X) { int i; printf ("Listado de personas:\n"); for (i=0 ; i<X->NumPersonas ; i++) printf ("%d - %s\n",X->Gente[i].Edad,X->Gente[i].Nombre); printf ("\n"); } void main (int argc, char* argv[]) { Personas K; IniPersonas (&K); Persona A; A.Edad = 15; strcpy (A.Nombre,"Manolo"); AgregarPersona (&K,&A); A.Edad = 25; strcpy (A.Nombre,"Filomeno"); AgregarPersona (&K,&A); A.Edad = 48; strcpy (A.Nombre,"Martirio"); AgregarPersona (&K,&A); ImprimirPersonas (&K); EliminarPersona (&K,1); ImprimirPersonas (&K); FinPersonas (&K); }

El ejemplo anterior muestra el uso frecuente de un array dinmico de estructuras.

En C, el manejo de este tipo de estructuras involucra malloc (reservar memoria), realloc (reasignar el espacio asignado), free (liberar espacio), y copias entre elementos. C# considera estas operaciones como no seguras, y ofrece tipos de datos para realizar estas tareas de forma segura. Adems, dichos tipos de datos son mucho ms fciles de utilizar. Ejemplo en C# using System; using System.Collections; namespace Simple { class CSimple { class Persona { public int Edad; public string Nombre; } static void ImprimirPersonas (ArrayList K) { Console.WriteLine ("Listado de personas:"); for (int i=0 ; i<K.Count ; i++) { Persona P = (Persona) K[i]; Console.WriteLine ("{0} - {1}",P.Edad,P.Nombre); } Console.WriteLine (); } [STAThread] static void Main(string[] args) { ArrayList K = new ArrayList (); Persona P = new Persona(); P.Edad = 15; P.Nombre = "Manolo"; K.Add (P); P = new Persona(); P.Edad = 25; P.Nombre = "Filomeno"; K.Add (P); P = new Persona(); P.Edad = 48; P.Nombre = "Martirio"; K.Add (P); ImprimirPersonas (K); K.RemoveAt (1); ImprimirPersonas (K); } } } Vemos que un objeto ArrayList tiene las operaciones necesarias para agregar y eliminar elementos, igual que el tratamiento implementado por malloc, realloc y free. Un objeto ArrayList se inicializa solo y se destruye solo. Pero esto es un tema sobre el que incidiremos profundamente cuando veamos la programacin orientada al objeto, ahora no es relevante.

13. Acceso a ficheros de texto en modo lectura.


Ejemplo en C #include <stdio.h> #include <stdlib.h> void main (int argc, char* argv[]) { FILE* F; char c; F = fopen ("C:\\Texto.txt","r"); while (!feof(F)) { fscanf (F,"%c",&c); printf ("%c",c); } fclose (F); } Ejemplo en C# using System; using System.IO; namespace Simple { class CSimple { [STAThread] static void Main(string[] args) { FileStream F = new FileStream ("C:\\Texto.txt",FileMode.Open, FileAccess.Read); while (F.Position < F.Length) { char c = (char) F.ReadByte (); Console.Write (c); } F.Close (); } } } El ejemplo anterior muestra cmo leer carcter a carcter un fichero de texto. Aqu terminan las semejanzas entre C y C# en este aspecto. La funcin fscanf permite ir leyendo datos separados por espacios, convirtiendo los tipos de la forma deseada. Sin embargo, un objeto FileStream slo permite leer caracteres o bloques de ellos, no es capaz de ir leyendo de separador en separador. Ejemplo en C# static void Main(string[] args) { StreamReader F = new StreamReader ("C:\\Texto.txt"); for (;;) { string s = F.ReadLine (); if (s == null) break; Console.WriteLine ("Linea: " + s); } F.Close (); } El ejemplo anterior usa un objeto StreamReader para leer el fichero de texto, lnea a lnea.

Ejemplo en C# using System; using System.IO; namespace Simple { class CSimple { [STAThread] static void Main(string[] args) { StreamReader F = new StreamReader ("C:\\Texto.txt"); for (;;) { string s = F.ReadLine (); if (s == null) break; Console.WriteLine ("Linea: " + s); string[] Palabras = s.Split (' '); for (int i=0 ; i<Palabras.Length ; i++) Console.WriteLine (" " + Palabras[i]); } F.Close (); } } } El ejemplo anterior va leyendo del fichero lnea a lnea, y utiliza el mtodo Split del objeto string para separar las palabras en un nuevo array de cadenas de caracteres. La salida de este programa muestra lnea a lnea el fichero, y para cada lnea muestra las palabras, separadas unas de otras. A partir de aqu, y con las operaciones del objeto Convert (Convert.ToInt32, Convert.ToDouble, etc), se puede emular el funcionamiento de un fscanf con formato.

14. Acceso a ficheros de texto en modo escritura.


Ejemplo en C #include <stdio.h> #include <stdlib.h> void main (int argc, char* argv[]) { FILE* F; int i = 4; double j = 45.67; char k[] = "Hola"; F = fopen ("C:\\TextoSalida.txt","wt"); fprintf (F,"Esto es una cosa a escribir\n"); fprintf (F,"Esto es otra cosa, que tambien salta de linea\n"); fprintf (F,"Impresion de datos: %d %f %s\n",i,j,k); fclose (F); } Ejemplo en C# using System; using System.IO; namespace Simple { class CSimple { [STAThread] static void Main(string[] args) { StreamWriter F = new StreamWriter ("C:\\TextoSalida.txt"); F.Write ("Esto es una cosa a escribir\r\n"); F.WriteLine ("Esto es otra cosa, que tambien salta de linea"); int i = 4; double j = 45.67; string k = "Hola"; F.WriteLine ("Impresion de datos: {0} {1} {2}",i,j,k); F.Close (); } } } StreamWriter es el tipo de datos (objeto) de C# que permite imprimir en un fichero de texto de forma semejante a fprintf en C.

También podría gustarte