[TUTORIAL] Programando en C

1, 2, 3, 4, 59
mellon escribió:
blipi escribió:@alpha_19_
perdon por no responder tu duda antes, no vi el post. Incluyes antes del "return 0;" algún tipo de pausa, ya sea el getchar(); o el system("pause") explicados en este tuto? De ser así, pasate por el final del capítulo 5, allí tienes el programa al completo. Asegurare que tienes lo mismo.

@mellon
Mira, yo no quiero hacer de esto una guerra, si después de leer mi respuesta sigues empeñado en discutir, mandame un MP y lo hacemos por allí, no quiero desvirtuar el tema del hilo.
1. Te pasa algo conmigo o con que quiera ayudar a la comunidad?
2. Nunca he dicho que saber programar en C implique tener todos los conceptos de C++ aprendidos, he dicho que saber C igual a saber programar en C++, y tampoco he dicho nunca que aprovechando todo su potencial. Eso lo has dicho tu. Si sabes programar en C, sabes programar en C++, y viceversa. Aunque no lo aproveches al máximo.
3. Lo que hace C++ y no C, lo pones porque tu crees que yo no lo se?
4. Y si, temo decirte que todo lo que no hace C y si hace C++ son añadidos a C. Sino, porque comparten todos los archivos de base?


No, no, me parece perfecto esta iniciativa y es por eso que sigo el hilo, sino no me hubiese molestado ni en escribir.
Lo unico que he hecho es puntualizar que C++ es mucho mas que un extension de C, y permite hacer muchas cosas que en C no puedes. Mi descripcion ha sido para dar idea de lo que hablo y para que si ha alguien le interesa pueda buscar mas informacion y pueda contrastar los conceptos que introduce C++ respecto a C.
Respecto a porque comparten librerias es porque C++ esta basado en C y por temas de compatibilidad se incluyen las librerias de C. Un añadido seria lo que han ido aportando los diferentes estandares de C (entre otras muchas cosas, características de C++)

Animo con el proyecto.

Salu2


Yo estoy con mellon, antes trabajaba principalmente utilizando C y ahora C++.

Al principio pensaba lo mismo que blipi, vamos prácticamente pensaba "C++ es un C con objetos y ya". Sin embargo el tiempo me ha ido demostrando que ese pensamiento era equivocado, de hecho el paso de C a C++ requiere bastante tiempo y no un par de tardes. Es práctica habitual ver un monton de codigo C dentro C++ durante la transición de aprendizaje, y sólo la experiencia te hace escribir codigo C++ puro.

C y C++ son lenguajes distintos y a diferencia de lo que alguien más comentaba uno no es ampliación del otro. C++ incluye el subconjunto de C sí, pero no ha de verse como "un parche que añade objetos y 4 cosas". Sería como decir que Ruby es un Python modificado, total si tienen casi la misma sintaxis pero con algunas diferencias: pues no. C++ tiene muchísimas peculiariedades y lo convierte en un lenguaje totalmente distinto (muy apto para programar videojuegos y motores de cálculo por cierto).

C es muy eficiente, de hecho muchas veces se ha planteado el si podría migrarse el kernel de Linux a C++ y la respuesta siempre ha sido un rotundo no (y no solo por parte de Towards). Como he dicho son lenguajes distintos y por tanto usan compiladores distintos: C++ añade una sobrecarga adicional al codigo (debido al uso de orientación a objetos, templates, referencias,...). Uno no es mejor que el otro sino que simplemente son distintos, de otra forma hoy dia siempre se usaría C++ ¿no? ;)

Me parece genial la iniciativa de este tutorial, pero siempre se ha de tener en cuenta que C no es C++ . Mucha gente acaba creyéndose el engaño y luego pasa lo que pasa (ej.: entrevistas de trabajo con pruebas de admisión, etc.). En cualquier caso el paso lógico es meterse primero con C y aprender el uso de punteros, creación de módulos, uso del preprocesador, linkado de librerías, etc. Para el que quiera profundizar el camino puede ser muy largo pero también muy interesante.

Un saludo!
Venga chicos, dejemos el dilema este entre C y C++ porque no vamos a llegar a ningún lado xd

Solo os quería comentar que me acabo de dar cuenta que cometí un error bastante grande en el capítulo de "3. Operaciones con variables numéricas" en concreto, en las potencias. Pido por favor que lo reviséis, ya que cambia mucho.
Si todo va bien, hoy añadiré un capítulo de "funciones" y quizás otro de "estructuras, enumeraciones y uniones".

Gracias,
Blipi.
ya empieza lo bueno, de momento todo entendido perfectamente. Muy bien explicado todo
esperando más actualizaciones profe :D
Hola a todos.

Lo primero de todo, es felicitarte Blipi por la más que fenomenal iniciativa que has tenido. Muchas Gracias [oki]
Espero que comentarios de este tipo sirvan para motivarte más a seguir adelante. Estate seguro de que muchos foreros entre los que me incluyo te estamos treméndamente agradecidos por este pedazo aporte.

Yo estoy acabando ingeniería por fin jajaja ... y desde hace tiempo que quiero aprender a programar en C y en C++ y después de esto ir a por Objetive C y Cocoa. Seguro que ya sabeis por donde van los tiros.

Y quien sabe, en función de lo bien que se me dé quizás pueda aportar a la comunidad en el caso de PS3. Pero bueno, de todo eso queda mucho aún. :-|

He estado leyendo lo que he podido, pero siendo bastante novato, no he entendido que programa debo usar para hacer mis pinitos. Yo era usuario de windows hasta hace unos meses, pero adquirí un imac y me encanta. Por eso, que me gustaría saber que programa usar. Si mal no entiendo, debería tener interfaz IDE y de paso compilador.
He visto que mencionais netbeans, ... incluye todo para poder seguir el curso?

En último caso, si programar con mac es mas complicado, podría virtualizar windows o bien tirar del portatil y usaría Visual C por ejemplo.

Voy bien o ando desencaminado.

Un Saludo y disculpad las preguntillas de novato. [carcajad]
@Seahawk: No, tendrás que bajar el plugin de C/C++, instalar un compilador y configurar NetBeans para que lo utilice.
@Seahawk
La verdad nunca he trabajado en MAC, pero te puedo asegurar que más difícil no es, ya que es mas de lo mismo, el código no cambia.
Respecto a que IDE utilizar, la verdad yo no lo se, pero en anteriores posts otros usuarios han comentado Netbeans y Eclipse. Échale un ojeada.
Yo de ti no usaría una maquina virtual para esto, esto sí que sería trabajo adicional.

Parece que se me han adelantado =P

@todos
Gracias por vuestros comentarios y animos
Una pregunta, para asimilarlo todo bien estoy tirando un poco de ejercicios que se me van ocurriendo y así repaso lo publicado hasta ahora, y hay un ejercicio que se me a trabado y que trataría de hacer algo así como, crear un programa al que le meto a una variable char una string con el hola mundo y sacar un texto al final diciendo "La 4 letra de Hola Mundo es a"
Mi idea a sido esta, pero así consigo sacar de esa posición en adelante
#include <stdio.h>
#include <stdlib.h>
int main()
{
   char texto[11] = "Hola Mundo";
   char *punterotexto;
   punterotexto = &texto[3];
   //%d variables numericas %s cadenas de letras, %x direcciones de memoria
   printf ("La 4 letra de %s es %s.\n", texto, punterotexto);
   system ("pause");
}

En una variable char no puedo puntear la dirección de memoria para mostrarla en pantalla en plan "hola mundo esta en la dirección 0x34fc84" ?
@DeathWalk
Me encanta tu iniciativa, y me encanta este programa que has hecho, demuestra que tienes ganas:

La cosa esta en, si tu pones %s, eso se reemplaza por una variable tipo (char*).
El problema reside que tu has guardado la posición de la "a", por lo que como tu bien has declarado el puntero, es tipo char*, hasta allí todo esta bien. Pero resulta que ha continuación de la "a" se encuentra " Mundo".
(Son direcciones de memoria "adyacentes", ya que se reservan de forma continua, las letras están a una posición de memoria detrás de otra. El porqué te lo explico en un ejemplo a continuación. Si estuvieran salteadas en direcciones de memoria diferente, ya no hablaríamos de una array de char). Es decir, una array de char sería algo tipo

punterotexto = 0x01
en 0x01 -> 'a'
en 0x02 -> ' ';
en 0x03 -> 'M';

Si lo que quieres es únicamente mostrar un carácter, debes poner %c, puesto que se reemplaza por una variable tipo (char). Una sola letra es una variable char. Pero, tu punterotexto es del tipo (char*). Para poder obtener el valor que reside en la dirección donde apunta, debes pasarlo a char, es decir *punterotexto.

Si pones %x, se reemplaza por la dirección de memoria de una variable, en este caso, pondrías punterotexto. O también directamente tu variable char*. Puesto que char* ya es un puntero, si pones %x te va a devolver la dirección.


Porqué si pones %s se substituye por todo?
Lo que hace la función para substituir es esto (quizás es un poco avanzado, si no lo entiendes aun y leer la explicación, es normal, pues hay cosas que aun no he explicado):
char texto[] = "Hola Mundo";
for(int i = 0; i < strlen(texto); i++){
       if(*texto)
             printf(*texto++);
}

Te explico, lo de for es un "loop" o "bucle", empieza a contar desde 0, y hasta que la i no es igual que el largo del texto (11 caracteres) hace lo que pone entre los {}, es decir, hace el printf ese 11 veces (de 0 a 10).
Luego, (el if(*texto) te lo explico luego) que es eso de *texto++;
Primero, lo de *texto. Obtenemos el valor de la primera letra ('h') y la mostramos.
Sabemos que un char ocupa 1, es decir, *texto++ es lo mismo que poner *texto += 1;
es decir, si antes *texto obtenía la dirección de 0x01, ahora lo hace de la 0x02, y así consecutivamente.
Lo de if(*texto), imaginate que por alguna razón se le va la pinza, y de repente *texto obtiene el resultado de la dirección 0x41234, donde no hay nada. Como no hay nada, *texto = 0, y como *texto == 0, y como lo siguiente solo se ejecuta si existe *texto (esto es lo que hace un if, ya lo veremos en otros capítulo), el printf no se ejecuta.

PD: para poder usar este ejemplo, debes incluir "#include <string.h>"

PD: este si que no lo vais a entender, pero de echo, lo que realmente hace y el porque no se para en el primer carácter, es esto:
while(*texto)
     printf(*texto++);
#include <stdio.h>
#include <stdlib.h>
int main(void){
   char texto[11] = "Hola Mundo";
   //%d variables numericas %s cadenas de letras, %p <-------- direcciones de memoria
   printf ("La 4 letra de %s es %p.\n", texto, &texto[3]);
   system ("pause");
   return 0;
}



Eso es lo que buscas, más información aquí
Hola,
quizá mi C está oxidado, pero en:

Del mismo modo que podemos hacer funciones de cualquier tipo, también podemos hacer que una función sea un puntero, por ejemplo:

Código: Seleccionar todo
    char *dame_un_texto(){
         char *texto = (char*)malloc(11);
         strcpy(texto, "Hola Mundo");
         return 0;
    }


¿no has de devolver la dirección del texto?
¿Y cual de las opciones es correcta? (¿o la segunda es redundante?)


return texto;


return (char *) texto;


Slds,
choldi
Si perdón, se me fue la mano, allí deberia poner "return texto;"
No hace falta poner (char *), puesto que texto ya es una variable tipo char*, aunque si lo pones tampoco va a pasar nada malo xd

Y choldi, eso no es lo que busca, el %p va a devolver el registro donde se encuentra y el offset de memoria xd es mas lioso.
Además, lo que el quería era mostrar solo la 'a', no la dirección.
DeathWalk, mirate mi post de arriba
En una variable char no puedo puntear la dirección de memoria para mostrarla en pantalla en plan "hola mundo esta en la dirección 0x34fc84" ?


Eso es lo que pregunta.

EDIT: Vale, también pregunta lo otro, he mezclado un poco de todo.
jeje, si, de echo, yo no había visto que también preguntaba lo que tu decías.
Acabo de editar el post poniendo también esto xd

Salu2
Te doy el agradecimiento mas sincero que he dado en mi vida por internet.

Menudo trabajo te estas pegando, gracias a ti me voy a iniciar en esto de la programación que tantas ganas tenia y no sabia por donde empezar [tadoramo] [tadoramo]

Ojalá que no te rindas y lo completes...
Ante todo, felicidades por éste gran tutorial. Estoy mirandolo detenidamente para refrescar mis conociminientos de c++. Para ello estoy haciendo un programa pero tengo una duda que no sé resolver: quiero comprovar letras del teclado y para ello hago:
char c;
cin >> c;
if (c == 'a' or c == 'e'....) cout << vocal << endl;
else if (c == 'à' or c == 'é' ...) cout << vocal con acento << endl;
.
.
.
Pues bien cuando compilo, me da un warning en las comparaciones con acento, es decir no puedo hacer if(c == ' à ') porque me dice que es multichar. Alguien tiene alguna solución para las letras con acento?
Muchas gracias!
Primero de todo, eltuto es de C, no de C++, pero bueno.
Luego, prueba a poner directamente el valor numérico, buscalo aquí http://www.asciitable.com/
De todas formas, usar acentos en la consola es un poco antinatural, y de hecho, no se si te contara el acento como una pulsación y la letra como otra, lo cual tiene lógica por lo de multichar.
Estas trabajando con "caracteres largos" (wide-characters) como UNICODE o UTF y ahí la cosa se complica
#include <iostream>
using namespace std;
int main(void){
  setlocale(LC_ALL,"es_ES.UTF-8");//hay que activar el locale que corresponda
  wchar_t c;//widechar
  wcin >> c;//versiones wide de cin y cout de toda la vida, están definidas en iostream
  wcout << c << endl;
  if (L'á' == c){//la L indica que es un carácter largo
    wcout << "IGUALES\n";
  }
 
  return 0;
}

El locale a cargar tendrá que ser el juego de caracteres en el que esté codificado el flujo (stream) del que estés leyendo.
He olvidado añadir que el string que da nombre al locale (en este caso es_ES.UTF-8) es especifico del sistema, en este caso es formato de GNU/Linux, en Windows no tengo ni idea de como será.
Uff tiene toda la razón juen, si es que a estas horas ya no de ni lo que me digo xd y además estoy en el ipod lol

Mejor me voy a la cama xd
Mañana estructuras, uniones y enumeraciones.
Muchas gracias a los dos blipi y juen, me a quedado clarisimo, efectivamente tenia dos duras ya que poniendo la dirección mediante %x con los int sin problemas pero con las strings que daba valores raros.
Finalmente:
#include <stdio.h>
#include <stdlib.h>
int main()
{
   char texto[11] = "Hola Mundo";
   char *punterotexto;
   punterotexto = &texto[3];
   //%d variables numericas %s cadenas de letras, %p direcciones de memoria
   printf ("La 4 letra de %s es %c.\n y se encuentra en la direccion 0x%p\n", texto, *punterotexto, punterotexto);
   system ("pause");
}


Aun así, no acabo de entender bien la diferencia entre %x y %p (que conste que ahora mismo estoy espeso y voy volando a la cama, igual mañana por la mañana me lo releo y lo pillo XD)

X Unsigned hexadecimal integer (lo que vendría siendo todos los hexadecimales) 0x7FA
p Puntero de memoria B800:0000

En esta aclaración entiendo que la p efectivamente apunta a la memoria, pero en algun ejemplo anterior hemos usado %x como aqui:
#include <stdio.h>

int main(){
   unsigned long hexa_1 = 0xAABBCCDD;

   char texto[100];
   sprintf(texto, "0x%x", hexa_1); //Copiamos en la variable texto el hexa_1
   //NOTA: el %x se sustituye por hexa_1, pero no pone el 0x, por eso lo ponemos nosotros delante
   //es simple estética, ¡no influye en nada!
   printf(texto); //va a mostrar 0xAABBCCDD
   
   getchar();

   return 0;
}

LO siento si ya esta respondido, como os digo es tarde XD

Edit Añado: tu ejemplo blipi se entiende bien, aunque sea algo no visto aun, ya me tengo mirados los do----while if--else jejeje, que me pongo a consultar cosillas y acabo adelantándome, aprovecho ahora que estoy de vacaciones, cuando vuelva al curro no tendré tanto tiempo
Es lo mismo.
Lo que pasa que %x lee el contenido en formato hexadecimal. Piensa que lo único que hace es leer el contenido del puntero, puesto que dicho contenido ya es la dirección, y enseñartelo como hexadecimal.
%p hace lo mismo, lee el contenido y te muestra la dirección. Lo que pasa que %p va mas allá, y te lo presenta de forma que te indica el registro y la dirección en que se encuentra de ese registro (offset). Esto si no me equivoco, tendría que revisarlo.

En lo ejemplos he usado %x ya que muestra el concepto de hexadecimal, y (creo) que es mas fácil de entender que no el formato en que lo presenta %p

En el fondo son dos maneras distintas de ver la misma cosa
Cuando usas %x estás indicando al compilador que vas a pasar datos que son unsigned int (que si, una dirección de memoria es eso, un entero sin signo) pero sin embargo estas pasando un puntero a otra cosa, en tu caso, a carácter y estos dos tipos no coinciden, por eso el compilador te dará un aviso
aviso: el formato ‘%x’ espera el tipo ‘unsigned int’, pero el argumento 3 es de tipo ‘char*’

Ahora por partes:

a) Seguramente funcionará con %x porque el número de bits necesarios para representar una dirección de memoria en la arquitectura sobre la que estás programando es menor o igual a la capacidad del unsigned int, si esto no fuera así lo que mostraría printf ya no sería correcto, seguramente truncaría el número. (En GCC unsigned int, long unsigned int y void* ocupan todos 4 bytes)

b)%p no produce aviso porque espera un tipo void* (además formatea la cadena añadiendo el 0x) este tipo es un tipo comodín, cualquier puntero es un void* y void* puede almacenar un puntero a cualquier cosa, el tamaño de void* (al igual que un puntero a cualquier cosa, pero ahí ya estás metiendo verificación de tipos) coincide necesariamente con el numero de bits necesarios para codificar una dirección de memoria en la arquitectura sobre la que estás programando. De hecho puedes mirar como malloc lo que devuelve es void* y tienes que castearlo al tipo que necesites para que el compilador no de un aviso.

#include <stdio.h>
#include <stdlib.h>
int main(void){
   void *v;
   char s[] = "ABC";
   v = s;//<-- esta asignación no requiere casting (ver nota al final)  porque se está usando el tipo comodín void*
   printf ("%s\n",s);
   printf ("%s\n", (char*) v);//<--casting requerido
   
   return 0;
}


Como puedes ver ahí hace falta hacer un casting de void* a char* porque al indicarle a printf la cadena de formato "%s" estas diciendole que lo que vas a pasar es un char*, no un void*, ocurre de nuevo lo mismo que ocurría con el "%x" y el void*

Por supuesto se pueden hacer marranadas como esta
#include <stdio.h>
#include <stdlib.h>
int main(void){
   void *v;
   float *f;//<---preparación de la marranada
   char s[] = "ABC";
   v = s;
   f = (float*) s;//<<--- marranada
   printf ("%s\n",s);
   printf ("%s\n", (char*) v);
   printf ("%s\n", (char*) f);//<--- arreglo de la marranada
 
   return 0;
}

pero como ves requieren más trabajo para que funcionen, sin el casting f = (float*) s daría un error y no compilaría, pero es que además no tiene ningún sentido hacer algo así. Por razones como esta (C te deja hacer casi cualquier cosa) es por la que a menudo no se recomienda C como lenguaje para aprender y se recomienda por ejemplo Pascal que es mucho menos flexible. Personalmente no estoy de acuerdo con eso porque cuanto más te equivocas más aprendes y no me parece que aprender C desde el principio sea algo descabellado.

Los punteros pueden dar muchos dolores de cabeza, a mucha gente les cuesta entenderlos. Espero que no haya quedado muy liosa la explicación.

Nota: No sé si esto se ha tratado ya en el tutorial así que te lo comento, hacer casting es poner (T) variable, al hacer esto se indica al compilador que trate la variable como si tuviera tipo T en lugar del tipo original, este cambio es local, solo afecta allí donde se haya indicado .
por fin un tuto de C en el que me entero algo, muchas gracias y animo para seguir adelante
Añadido capítulos:
9. Profundizando en las Array
10. Bucles (de momento solo el 10.1 - Bucle while)

El capitulo de estructuras, enumeraciones y uniones lo dejo para el 12, puesto que en el 11 explicaré los condicionales (if y switch). Así en el 12 podré explicar estructuras de una forma bonita =P aplicando todos los conocimientos de punteros, arrays, if y compañia =)
Iría bien que volvierais a mirar el capitulo de "Operando con variables numéricas", pues al final de todo he puesto los operadores >, <, >=, <=.

Mi planning ahora mismo, que posiblemente cambie, es:
10. Bucles (while, for, do-while y palabras como break y continue)
11. Condicionales (if, switch)
12. Estructuras, enumeraciones y uniones
13. Profundizando en asignaciones de memoria dinámicas
14. Profundizando en las cadenas
15. Algoritmos de ordenación y búsqueda (en arrays)
16. Flujos y archivos
17. Linked list (listas enlazadas)
(18. Pilas, colas) -> Si veo que el nivel está como para hacerlo

Y como ya he puesto en el final de tuto:
No se si podré escribir nada más hasta dentro de 2 días, pues esta tarde (día 05), me voy con la familia, en el pueblo, para celebrar reyes. Si tenéis (y tengo) suerte xd pillaré el wifi de primo y escribiré algo =P
Seguiré escribiendo, sea mañana o al cabo de 2 días. Espero no ver ningún post de que el tutorial está incompleto.


PD: Acabo de copiarlo todo en un word y me he quedado parado de que solo ocupara 32 páginas en letra pequeña xd en cuando termine unos capítulos más, voy a poner cantidad de programas de ejemplo más para que todo se entienda mejor, pues creo que 32 páginas por todo lo que llevamos explicado es muy poco.
blipi escribió:@Seahawk
La verdad nunca he trabajado en MAC, pero te puedo asegurar que más difícil no es, ya que es mas de lo mismo, el código no cambia.
Respecto a que IDE utilizar, la verdad yo no lo se, pero en anteriores posts otros usuarios han comentado Netbeans y Eclipse. Échale un ojeada.
Yo de ti no usaría una maquina virtual para esto, esto sí que sería trabajo adicional.

Parece que se me han adelantado =P

@todos
Gracias por vuestros comentarios y animos


Gracias Blipi y Juen. ;)

Bueno, he descargado Netbeans y Eclipse para escribir el código y Gcc como compilador.

Decia tambien Juen que con el Netbeans tenía que conseguir el plugin de C/C++ y configurarlo para que lo use el Netbeans. Perdonazme pero me suena a chino esta parte.

Por cierto, no se en donde leí por ahí que lo de tener el C/C++ te viene con xcode y ya lo tengo instalado.

A ver si alguien que tenga mac me puede ayudar. [carcajad]

Un Saludo.
blipi escribió:17. Linked list (listas enlazadas)
(18. Pilas, colas) -> Si veo que el nivel está como para hacerlo


Si vas a meter estructuras de datos dinamicas como listas enlazadas, creo que vale la pena explicar tambien pilas y colas (o por lo menos de forma esquemática como se programarían y ejemplos donde aplicarlas).
Ya, pero si la gente no entiendiese el funcionamiento de la linked list, explicar las colas sería una especie de tortura, tanto para ellos como para mí.
Intentar explicar el funcionamiento de una cola/pila sin entender el funcionamiento de una linked list es bastante difícil. Por eso lo he puesto entre paréntesis y he puesto que dependía del nivel de la gente.
@Seahawk
Al Parecer Xcode es un IDE por tanto no necesitas Netbeans ni Eclipse, ya lo tienes todo.
Juen escribió:@Seahawk
Al Parecer Xcode es un IDE por tanto no necesitas Netbeans ni Eclipse, ya lo tienes todo.


XCode es IDE + compilador (gcc), requiere registro en la Apple Developer (es gratuito).

Pese a que XCode es un IDE excelente no lo veo apropiado para personas que quieren hacer pruebas simples en C, y por tanto no puedo recomendarlo. En cualquier caso resulta esencial para tener una toolchain de GCC, ya que es necesario instalar el paquete que incluye el XCode (además en un futuro al que quiera le permitirá a su vez instalar "fink" y "macports", muy utiles para obtener otros paquetes de uso comun).

Para los principiantes recomiendo comenzar con un editor de texto sencillo ( http://sourceforge.net/projects/smultron/ es GPL), si bien no es el más potente por lo menos tiene resaltado de sintaxis y numeros de linea. Vim esta disponible directamente en el OSX, un editor excelente pero que tampoco puedo recomendarlo a quien no lo haya manejado antes (complejidad media-alta).

Para compilar se puede usar un terminal (basta con escribir 'terminal' en spotlight) y en ella las lineas de comando típicas de compilación y ejecucion:
gcc -o helloworld helloworld.c
./helloworld

Aclaro de nuevo, no estoy diciendo que XCode no valga o sea malo (todo lo contrario), pero requiere unos conocimientos mínimos tanto del lenguaje como de compilación/linkado (incluso tiene cosas peculiares que no se dan en otros IDEs, como es el uso de "paquetes framework").

Por otro lado comentaré que instalar la toolchain de PS3 en OSX a diferencia de Linux no es trivial (fallan paquetes al compilar). Llegado el momento si alguien necesita instalar TOOLCHAIN + PSL1GHT podría hacer un tutorial (si es que encuentro tiempo...).
@Pom: No, si yo tampoco recomiendo un IDE para empezar, puedes comprobarlo unos cuantos mensajes más arriba xD
joder que currazo de manual, yo que casi aprendí más en la carrera con los manuales de aprenda XXX como si estuviera en primero que con lo que enseñaban los profesores de las diferentes asignaturas (en ing. informatica que se supone que todos los profesores son grandes programadores y luego.....a mas de un profesor le caeria la cara de verguenza al ver este post y revisar luego su temario de la asignatura) y ahora veo este pedazo de manual.


ME POSTRO A SUS PIES CABALLERO!!! ENHORABUENA.
pom escribió:
Juen escribió:@Seahawk
Al Parecer Xcode es un IDE por tanto no necesitas Netbeans ni Eclipse, ya lo tienes todo.


XCode es IDE + compilador (gcc), requiere registro en la Apple Developer (es gratuito).

Pese a que XCode es un IDE excelente no lo veo apropiado para personas que quieren hacer pruebas simples en C, y por tanto no puedo recomendarlo. En cualquier caso resulta esencial para tener una toolchain de GCC, ya que es necesario instalar el paquete que incluye el XCode (además en un futuro al que quiera le permitirá a su vez instalar "fink" y "macports", muy utiles para obtener otros paquetes de uso comun).

Para los principiantes recomiendo comenzar con un editor de texto sencillo ( http://sourceforge.net/projects/smultron/ es GPL), si bien no es el más potente por lo menos tiene resaltado de sintaxis y numeros de linea. Vim esta disponible directamente en el OSX, un editor excelente pero que tampoco puedo recomendarlo a quien no lo haya manejado antes (complejidad media-alta).

Para compilar se puede usar un terminal (basta con escribir 'terminal' en spotlight) y en ella las lineas de comando típicas de compilación y ejecucion:
gcc -o helloworld helloworld.c
./helloworld

Aclaro de nuevo, no estoy diciendo que XCode no valga o sea malo (todo lo contrario), pero requiere unos conocimientos mínimos tanto del lenguaje como de compilación/linkado (incluso tiene cosas peculiares que no se dan en otros IDEs, como es el uso de "paquetes framework").

Por otro lado comentaré que instalar la toolchain de PS3 en OSX a diferencia de Linux no es trivial (fallan paquetes al compilar). Llegado el momento si alguien necesita instalar TOOLCHAIN + PSL1GHT podría hacer un tutorial (si es que encuentro tiempo...).


Hola a todos ;)

Evidentemente no tengo mucha idea del asunto, pero como dije anteriormente lo del plugin C/C++ se podía conseguir con Xcode pues lo leí por eol en algun sitio, de ahí que lo instalara para aprovecharlo.
Y ya me imaginaba que para un novato como yo, Xcode no era lo más conveniente para empezar. jejeje ...


Probaré entonces con Smultron y ya os contaré. Gracias porn por la ayuda de veras. [oki] y no me olvido de Blipi y Juen [oki]

Un Saludo.
¿Me explica alguien por qué no funciona este sencillo código? Si invierto las cadenas en strcat(), es decir, si en lugar de
strcat(t2, S);
strcat(t2, t1);
printf ("%s\n", t2);

pongo:
strcat(t1, S);
strcat(t1, t2);
printf ("%s\n", t1);

en el siguiente código, el mensaje que recibo solo muestra en pantalla el primer argumento (t1) saltándose el resto de la línea.
#include <stdio.h>
#include <string.h>

void makeText (char *t1, char *t2, char *S){
   strcat(t2, S);
   strcat(t2, t1);
   printf ("%s\n", t2);
}

int main(int argc,char *argv[]){
   if (argc != 3){
      printf("Uso: Texto1 Texto2\n");
      return;
      }
   if (!strcmp(argv[1], "-c")) makeText(argv[1], argv[2], " ");
   return 0;
}
gracias por el curro. la verdad q tenia tiempo por meterle mano a un tuto, pero ahora q lo pusiste aqui voy leyendome todo dos veces antes de seguir, y la verdad muy comprensible, Gracias, aver para cuando uno de nivel intermedio.
@xXDraklordXx

Tienes una gran cantidad de fallos en ese código. Antes de nada ese código no debería compilar, no sé que compilador usas pero desde luego es muy permisivo

Voy a obviar los #includes

void makeText (char *t1, char *t2, char *S){
   strcat(t2, S);
   strcat(t2, t1);
   printf ("%s\n", t2);
}

int main(int argc,char *argv[]){
   if (argc != 3){
      printf("Uso: Texto1 Texto2\n");
      return; <--- return 0
      }
   if (!strcmp(argv[1], "-c")) makeText(argv[1], argv[2], " ");
   return 0
}


Fallos (si es que pueden llamarse así) de estilo. Sí, esto es cosa de gustos, pero a la larga afectan a la calidad y la mantenibilidad del código

void makeText (char *t1, char *t2, char *S){
  strcat(t2, S);
  strcat(t2, t1);
  printf ("%s\n", t2);
}

int main(int argc, char *argv[]){
  if (argc != 3){
    printf("Uso: Texto1 Texto2\n");
  }else if (!strcmp(argv[1], "-c")){//Condiciones mutuamente excluyentes y uso de corchetes, aunque sea para delimitar una sola instrucción.
    makeText(argv[1], argv[2], " ");
  }
  //Un único punto de salida de la función, ya tendrás ocasión de romper esta regla.
  return 0;
}


Correcciones en el uso de los parametros

int main(int argc, char *argv[]){
  //una llamada a un ejecutable consta de:
  //nombreEjecutable parámetro1 parámetro2 parámetro3 ... parámetroN
  //que se corresponden respectivamente con:
  //argv[0] argv[1] argv[2] argv[3] ... argv[N]
  //el valor de argc no es exactamente el numero de parámetros, sino el número de parámetros + 1
  //por tanto como mínimo siempre vale 1, el 1 es por el nombre del ejecutable que como ya te he
  //comentado es uno de los elementos de la matriz *argv[]
  //Por tanto el valor válido de argc para 3 parámetros es 4, 3 parámetros (-c texto1 text2) y nombreEjecutable
  if (argc != 4){
    printf("Uso: Texto1 Texto2\n");
  }else if (!strcmp(argv[1], "-c")){
    makeText(argv[2], argv[3], " ");//Aqui supongo que el primer argumento debia ser argv[2], no 1 (que sera "-c")
  }

  return 0;
}


Aviso:
aviso: conversión obsoleta de una constante de cadena a ‘char*’

producido por
makeText(argv[2], argv[3], " ")

La signatura de la fúncion makeText es
void makeText (char *t1, char *t2, char *S);

Es decir, espera tres vectores (o cadenas o, más generalmente, tres punteros) de char, sin embargo estás pasando dos punteros (más tarde te diré que aquí hay otro error) y una constante. Hay muchas soluciones para arreglar esto:

Pasando el espacio como un vector puedes hacer:
char espacio[] = " ";
...
makeText(argv[2], argv[3], espacio);


Ahora lo grave:

void makeText (char *t1, char *t2, char *S){
  strcat(t2, S);
  strcat(t2, t1);
  printf ("%s\n", t2);
}

main(){
  ..
  makeText(argv[2], argv[3], espacio);
  ...
}

Estás concatenando sobre t2, es decir, todas las cadenas estan copiandose en t2 (se entiende que una a continuación de la otra) sin embargo no se ha reservado memoria para t2, t2 no tiene un espacio propio, de hecho lo que realmente estas haciendo es usar la memoria donde esta almacenado argv[2] como t2, esto pareces saberlo por el codigo que has hecho. Sin embargo esto es un gran problema, no solo porque estás machacando el contenido de argv[1] y potencialmente también el contenido de los demás parámetros, sino porque probablemente te saldrás de la zona reservada y el programa abortará.

Ejecuta este ejemplo con parametros "AAA BBB CCC DDD" para ver lo que ocurre
#include <stdio.h>
#include <string.h>
void makeText (char *t1, char *t2, char *S){
  strcat(t2, S);
  strcat(t2, t1);
}

int main(int argc,char *argv[]){
  char espacio[] = " ";
  if (argc == 5){
    printf("ANTES:|%s|%s|%s|%s|\n", argv[1], argv[2], argv[3], argv[4]);
    makeText(argv[2], argv[3], espacio);
    printf("DESPU:|%s|%s|%s|%s|\n", argv[1], argv[2], argv[3], argv[4]);
  }
  return 0;
}


la salida será
ANTES:|AAA|BBB|CCC|DDD|
DESPU:|AAA|BBB|CCC BBB|BBB|


Como ves se ha machado el DDD al aumentar de longitud la cadena contenida en argv[3], esto se debe a que argv es una matriz y los datos en las matrices se encuentran almacenados consecutivamente, además, pese a que se ha sobrepasado la longitud al añadir el espacio, no cascará porque la memoria reservada para los parametros es mayor que la necesaria.

Haciendolo con strcat
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void makeText (char *t1, char *t2, char *S){
  int longitudTotal = 0;
  char *cadenaFinal;
  //primero se calcula el tamaño de la cadena
  longitudTotal += strlen(t2);
  longitudTotal += strlen(t1);
  longitudTotal += strlen(S);
  //se reserva el espacio necesario
  cadenaFinal = (char*) malloc (sizeof(char) * (longitudTotal + 1));//+1 debido a que hay que dejar espacio para el caracter terminador
  //se monta la cadena
  cadenaFinal[0] = '\0'; //para indicar que la cadena esta vacia, el terminador como primer elemento
  strcat(cadenaFinal, t2);
  strcat(cadenaFinal, S);
  strcat(cadenaFinal, t1);
  printf ("%s\n", cadenaFinal);
  //se libera la memoria reservada
  free(cadenaFinal);
}


De mejor manera:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void makeText (char *t1, char *t2, char *S){
  int longitudTotal = 0;
  char *cadenaFinal;
  longitudTotal += strlen(t2);
  longitudTotal += strlen(t1);
  longitudTotal += strlen(S);
  cadenaFinal = (char*) malloc (sizeof(char) * (longitudTotal + 1));
  sprintf(cadenaFinal, "%s%s%s", t2, S, t1);
  printf ("%s\n", cadenaFinal);
  //se libera la memoria reservada
  free(cadenaFinal);
}


Lo ideal, en cualquier version, es que te cargues el parámetro donde pasas el espacio.

Espero que haya quedado claro.
Joder que gran tuto!!!! Me lo voy a empapar con calma y buena letra. Muchas gracias!!!
Menuda currada de tuto, mil gracias ;)
@Juen

Entenderlo lo he entendido pero has malinterpretado mi código (por cierto, para compilar uso gcc en ubuntu). Con los argumentos quería que el resultado sólo se mostrara si argv[1] era "-c", o no se mostrara nada si argv[1] no era dicha cadena. Por eso solo usé 3 argumentos: ./ejecutable argv[1] argv[2]. Pretendía que si argv[1] era "-c" se imprimieran en pantalla ambas cadenas separadas por un espacio. Con mi código se mostraban ambas cadenas, sin embargo, si invertía las cadenas en strcat(), es decir:

void makeText (char *t1, char *t2, char *S){
   strcat(t1, S);
   strcat(t1, t2);
   printf ("%s\n", t1);
}

Sólo se mostraba t1, ignorando el resto. Mi duda es el por qué de ésto. Sé que hay varias formas (y mejores) de hacerlo, como tu mismo me has enseñado, pero mi duda es el por qué en mi código se da esa peculiaridad. Espero no molestar con mis dudas de novato jejeje.

Aún así, ¿mejor esta solucion?:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int argc,char *argv[]){
   /*Verificación de argumentos*/
   if (argc != 3 && !strcmp(argv[1], "-c")){
      printf("Uso: Texto1 Texto2\n");
      } else {
         /*Creacion e impresion de cadena*/
         int l = strlen(argv[1]) + strlen(" ") + strlen(argv[2]);
         char *cadena = (char *) malloc(sizeof(char) * (l + 1));
         if (!strcmp(argv[1], "-c")){
         sprintf(cadena, "%s %s", argv[1], argv[2]);
         printf("Cadena: \"%s\" Tamaño: %i\n", cadena, sizeof(cadena));
         }
      }
   return 0;
}
Vale, el problema es que las dos cadenas se solapan

[-c | \0 | T | e | x | t | o | 2 | \0 ]
  ^        ^
argv[1]  argv[2]


cuando metes el espacio, por lo que ya comenté antes de machacar los argumentos

[-c | _ | \0 | e | x | t | o | 2 | \0 ]
  ^        ^
argv[1]   argv[2]


Por lo que la cadena argv[2] se considera vacía pues comienza con el carácter fin de cadena (\0). Lo puedes comprobar con este código:
void makeText (char *t1, char *t2, char *S){
   strcat(t1, S);
   strcat(t1, t2);
   for (int i=0; i<20; i++){//20, por poner algo
     printf("%c", t1[i]);
   }
   printf("\n");
}


veras como se machaca el primer carácter de "Texto2".

Concretamente, para los parametros "-c Texto2" visto en ASCII el antes y el despues quedan:

|45|99|0 |84|101|120|116|111|50|0|83|83|72|95|65|71|69|78|84|95|
|45|99|32|0 |101|120|116|111|50|0|83|83|72|95|65|71|69|78|84|95|

donde se ve claramente que el 0 se ha machacado al 84 que es la T. A partir del último 0 los valores que aparecen forman parte de las variables de entorno.
@Juen

Ahora lo entiendo con total claridad, aunque no sé el por qué se produce eso pero a medida que estudie este lenguaje espero entenderlo jeje. Muchas gracias por tu ayuda.
Buenas, ya estoy de vuelta.
¡Gracias juen por ir resolviendo las dudas que la gente va presentado!

Seguiré escribiendo, aunque ahora mismo ando bastante liado con el Free PStore ya que queremos sacar una beta de aquí muy poco y tengo que acabar de pulir algunos aspectos aun.

A ver si antes de irme a dormir hoy, puedo escribir alguna cosilla.
Muchas gracias por el tuto, soy nuevo con esto del C, he programado algo en Visual Basic, pero hace mucho tiempo que no toco nada, y me he ido olvidando, soy un paquete, empiezo de cero!

Estoy intentado la función para... "Imaginarios que os viene un empresario y os dice que quiere una función tipo "int", con 2 parámetros int, que la función sume esos parámetros, y devuelva el resultado."
De la forma que esta planteado, parece que debe recoger los parámetros por teclado y sumarlos, le he intentado con este código pero da error:

# include <stdio.h>
# include <stdlib.h>
int main (){
   printf ("Escribe el valor del primer numero");
   int var1 = getchar ();
   printf ("Escribe el valor del segundo numero");
   int var2 = getchar ();
   int suma;
   suma = var1 + var2;
   char valorsuma [100];
   sprintf (valorsuma, "La suma de los dos numeros es: %d", suma);
   printf (valorsuma);
   system ("pause");
   return 0;
}


Como se usa getchar (), cual es el problema?
Otra dudilla, ya que estoy... como se escriben los caracteres acentuados y caracteres especiales? Es igual que en HTML, hace falta indicarle al Visual C++ el formato en las propiedades del proyecto, o algo así?

Gracias y saludos!
dracojcs escribió:Muchas gracias por el tuto, soy nuevo con esto del C, he programado algo en Visual Basic, pero hace mucho tiempo que no toco nada, y me he ido olvidando, soy un paquete, empiezo de cero!

Estoy intentado la función para... "Imaginarios que os viene un empresario y os dice que quiere una función tipo "int", con 2 parámetros int, que la función sume esos parámetros, y devuelva el resultado."
De la forma que esta planteado, parece que debe recoger los parámetros por teclado y sumarlos, le he intentado con este código pero da error:

# include <stdio.h>
# include <stdlib.h>
int main (){
   printf ("Escribe el valor del primer numero");
   int var1 = getchar ();
   printf ("Escribe el valor del segundo numero");
   int var2 = getchar ();
   int suma;
   suma = var1 + var2;
   char valorsuma [100];
   sprintf (valorsuma, "La suma de los dos numeros es: %d", suma);
   printf (valorsuma);
   system ("pause");
   return 0;
}


Como se usa getchar (), cual es el problema?
Otra dudilla, ya que estoy... como se escriben los caracteres acentuados y caracteres especiales? Es igual que en HTML, hace falta indicarle al Visual C++ el formato en las propiedades del proyecto, o algo así?

Gracias y saludos!


La funcion getchar lee caracteres de la entrada estandar, y aunque su retorno sea un "int" no significa que sea para leer numeros, lee caracteres . El entero que te devuelve es su codigo ASCII.

Si quieres leer enteros te recomiendo que mires scanf: http://www.cplusplus.com/reference/clib ... dio/scanf/

En C++ los codigos de escape van precedidos del caracter \ , asi por ejemplo tienes \n (salto de linea) o \t (tabulado).
Bueno, lo que intentabas no está del todo mal, aunque la idea no era exactamente esa, jeje, si lees un poco más abajo de ese mismo capítulo, verás lo que quería decir.

Respecto tu programa:
La idea de getchar() es: el usuario escribe 1 letra/numero y se pulsa [enter], y getchar devuelve el valor numérico equivalente a la letra.
si quieres obtener la letra pulsada, debes pasar ese int a char:
int numero_letra = getchar();
char buffer[1] //considerando que solo se va a teclear una vez, es suficiente con 1, pues es solo 1 letra
sprintf(buffer, "%c", numero_letra); //Ahora buffer tiene la letra


Ahora, si quieres sabes que numero era, debes hacer:
int numero = atoi(buffer);
//atoi convierte una cadena de texto en numero, si la cadena era "2", ahora numero = 2;
//Nota: si la cadena fuera, por ejemplo, "a", obtendriamos que numero = 0


El hecho de que usemos una variable char* (buffer) es que atoi nos pide una variable de este tipo. Si usaramos una variable char, cosa totalmente viable, al llegar a atoi tendríamos que pasar la address (direccion) con &.
Queda mucho más simple asi:
int num = getchar();
     char buffer = (char)num;
     int numero = atoi(&buffer);


Ahora si que, usando la variable "numero" podrías hacer lo que ya hacías.
Gracias a pom y a Blipi por la ayuda, voy a intentarlo de la forma que sugiere Blipi, con scanf es también fácil, en los ejemplos de la web cpluplus se entiende perfectamente.
extraordinario tutorial. aver si puedo sacar tiempo entre estudiar, hacer deporte y eso. De verdad GRACIAS nunca he programado nada y creo que ya es hora de aprender un poco y si me gusta pues a más.
Si tengo alguna duda ya te la comentaré.
Saludos [oki] [oki]
Primero, muchas gracias por el tuto, siempre que querido aprender a programar más allá de basic y el Qbasic, xDDD, me lo voy a tomar muy en serio a ver si consigo hacer algo, lo que sea para mi psp.

Lo segundo, estoy practicando con la primera lección, el hola mundo, y creo que tengo algún problema con printf y sprint por que si hago esto:

#include <stdio.h>

int main() {
   int numero = 10;
   char texto[30] = "d%ds";
   printf(texto, numero);
   
   getchar();

}


Funciona, me sale el texto "d10s", que es lo que pretendo, pero si escribo

#include <stdio.h>

int main() {
   int numero = 10;
   char texto[30];
   sprintf(texto, "d%ds", numero);
   
   getchar();

}


Solo me sale la consola esperando a que de el intro sin ningún tipo de texto..

Por lo que he entendido, sprintf te permite definir la variable a continuación de mandarla imprimir, pero a mi no me sale.

Por favor, decidme si voy por buen camino.

Saludos.
kinbi escribió:Primero, muchas gracias por el tuto, siempre que querido aprender a programar más allá de basic y el Qbasic, xDDD, me lo voy a tomar muy en serio a ver si consigo hacer algo, lo que sea para mi psp.

Lo segundo, estoy practicando con la primera lección, el hola mundo, y creo que tengo algún problema con printf y sprint por que si hago esto:

#include <stdio.h>

int main() {
   int numero = 10;
   char texto[30] = "d%ds";
   printf(texto, numero);
   
   getchar();

}


Funciona, me sale el texto "d10s", que es lo que pretendo, pero si escribo

#include <stdio.h>

int main() {
   int numero = 10;
   char texto[30];
   sprintf(texto, "d%ds", numero);
   
   getchar();

}


Solo me sale la consola esperando a que de el intro sin ningún tipo de texto..

Por lo que he entendido, sprintf te permite definir la variable a continuación de mandarla imprimir, pero a mi no me sale.

Por favor, decidme si voy por buen camino.

Saludos.


Sprintf no imprime nada por salida estándar. Si quieres que se imprima algo por la salida estándar tienes que colocar luego un printf.
dano88 escribió:
kinbi escribió:Primero, muchas gracias por el tuto, siempre que querido aprender a programar más allá de basic y el Qbasic, xDDD, me lo voy a tomar muy en serio a ver si consigo hacer algo, lo que sea para mi psp.

Lo segundo, estoy practicando con la primera lección, el hola mundo, y creo que tengo algún problema con printf y sprint por que si hago esto:

#include <stdio.h>

int main() {
   int numero = 10;
   char texto[30] = "d%ds";
   printf(texto, numero);
   
   getchar();

}


Funciona, me sale el texto "d10s", que es lo que pretendo, pero si escribo

#include <stdio.h>

int main() {
   int numero = 10;
   char texto[30];
   sprintf(texto, "d%ds", numero);
   
   getchar();

}


Solo me sale la consola esperando a que de el intro sin ningún tipo de texto..

Por lo que he entendido, sprintf te permite definir la variable a continuación de mandarla imprimir, pero a mi no me sale.

Por favor, decidme si voy por buen camino.

Saludos.


Sprintf no imprime nada por salida estándar. Si quieres que se imprima algo por la salida estándar tienes que colocar luego un printf.


Sasto. Ahi lo que te hace sprintf es que la variable texto contenga lo de la variable numero; en este caso "d10s".

Ahora te falta sacar en pantalla el contenido de esa variable.

Simplemente te falta añadir una linea:

printf(texto);

o bien

puts(texto);

Puts es una funcion de C específica para dar una salida en pantalla de una cadena de caracteres.
Lol, entonces supongo que sprinft tendrá alguna gran utilidad más adelante por que si no, menuda castaña.

Ya funca. Ahora voy a hacer pruebas con arrays a ver si tengo claro los conceptos.

Saludos y muchas gracias a todos.
kinbi escribió:Lol, entonces supongo que sprinft tendrá alguna gran utilidad más adelante por que si no, menuda castaña.

Ya funca. Ahora voy a hacer pruebas con arrays a ver si tengo claro los conceptos.

Saludos y muchas gracias a todos.


sprintf es una función muy potente y muy utilizada. Más adelante, si continuas, te darás cuenta de eso. Digo que es muy utilizada porque permite unir datos como cadena y es algo que puede ser útil en ciertos contextos. Sprintf tiene un comportamiento superficialmente similar (por no decir igual) que fprintf. Con fprintf se puede hacer lo que querías (eso sí, sin guardar el texto en una variable) ya que puedes imprimir el texto en salida estandar así: fprintf (stdout, "texto"); stdout es una constante que almacena un puntero a FILE que está asociado al stream de salida estándar. Pero es una tontería usarlo porque por algo está printf o puts, como comentó anikilator .No te quiero liar, ésto seguramente aparezca en el tutorial más adelante.
448 respuestas
1, 2, 3, 4, 59