Discussion:
Duda para los expertos en C sobre cadenas
(demasiado antiguo para responder)
jagg
2004-01-30 08:52:24 UTC
Permalink
Hola a todos. Tengo una duda importante que espero que me resolváis. En el
siguiente código:

void main()
{
char *p;

p="Esto es una prueba";
....
¿Es correcta la asignación a p? No da problemas en ejecución. ¿Se
reserva memoria de forma dinámica para la cadena?

Las mismas cuestiones para la inicialización en la propia definición:

char *p="Esto es una prueba";

¿es esto igual a lo anterior?

Es una duda crucial.

Muchas gracias de antemano.






--------------------------------------------------

Mensaje enviado desde http://grupos.buscadoc.org

--------------------------------------------------
Leto Atreides
2004-01-30 09:10:53 UTC
Permalink
Post by jagg
Hola a todos. Tengo una duda importante que espero que me resolváis. En el
void main()
{
char *p;
p="Esto es una prueba";
....
¿Es correcta la asignación a p? No da problemas en ejecución. ¿Se
reserva memoria de forma dinámica para la cadena?
La asignación es correcta pues estás asignado al puntero p la dirección
que ocupa la cadena en memoria. ¿La asigna dinámicamente? No, el
compilador, una de las cosas que hace, es buscar todas las las cadenas
de caractéres constantes escritas en el código y reserva un espacio de
memoria para todas ellas y las sitúa. Eso lo hace en tiempo de
compilación no en tiempo de ejecución.
Post by jagg
char *p="Esto es una prueba";
¿es esto igual a lo anterior?
Puede que haya alguna diferencia a nivel más bajo (código máquina final)
pero un compilador "listo" debería tratarlo de la misma forma. De todas
formas el funcionamiento lógico del sistema no debe cambiar.

Un saludo,
Leto Atreides
Sergio Fernandez
2004-01-30 11:15:18 UTC
Permalink
desde luego que no me considero experto en C, pero te resuelvo la duda
igualmente, siempre y cuando la quieras de un inexperto en la materia :-)

yo reservaria memoria dinamica para almacenar la cadena en p, ya que si no,
te puede dar problemas de memoria.
imagino que esto sera un ejemplo de lo que haces y que en realidad utilizas
para algo mas la cadena, asi que yo te recomendaria hacer la reserva de
memoria.
si lo haces asi, no te olvides luego del free, que hay que liberarla una vez
no se utilice.

void main()
{
char *p;

p= (char *) malloc (strlen("Esto es una prueba") * sizeof (char));
p="Esto es una prueba";
free (p);
}

nos vemos
Post by jagg
Hola a todos. Tengo una duda importante que espero que me resolváis. En el
void main()
{
char *p;
p="Esto es una prueba";
....
¿Es correcta la asignación a p? No da problemas en ejecución. ¿Se
reserva memoria de forma dinámica para la cadena?
char *p="Esto es una prueba";
¿es esto igual a lo anterior?
Es una duda crucial.
Muchas gracias de antemano.
Leto Atreides
2004-01-30 11:39:32 UTC
Permalink
Post by Sergio Fernandez
yo reservaria memoria dinamica para almacenar la cadena en p, ya que si no,
te puede dar problemas de memoria.
imagino que esto sera un ejemplo de lo que haces y que en realidad utilizas
para algo mas la cadena, asi que yo te recomendaria hacer la reserva de
memoria.
si lo haces asi, no te olvides luego del free, que hay que liberarla una vez
no se utilice.
void main()
{
char *p;
p= (char *) malloc (strlen("Esto es una prueba") * sizeof (char));
p="Esto es una prueba";
free (p);
}
Tienes un pequeño error en este código. En realidad, con este código,
estás reservando 3 veces más espacio del que necesitas. Es más, el
espacio reservado lo desaprovechas.

Como he mencionado antes, el compilador* ya reserva espacio para las
constantes de tu código. Así, este, reservará espacio para la primera
cadena de "Esto es una prueba" incluida en el strlen y la segunda cadena
en la asignación de p. Después, en tiempo de ejecución, se reserva un
espacio con la longitud de strlen("Esto es una prueba")*sizeof(char).
Espacio que desaprovechas porque para introducir es frase en ese espacio
tendrías que haber hecho lo siguiente:

strcpy(p,"Esto es una prueba");

en vez de

p="Esto es una prueba";

Además de que te olvidas del caracter nulo que hay al final de toda
cadena en C.

Voy a poner un ejemplo:

Cuando compilas el compilador reservará el espacio de las dos frases en
estas direcciones de ejemplo:

PosMem Value Tamaño
1000 Esto es una prueba(nulo) 19 (suponiendo que sizeof(char) = 1
1019 Esto es una prueba(nulo) 19 (idem arriba)

y para la variable p

PosMem Value Tamaño
1038 (basura) 4 (suponiendo q sizeof(char*) = 4
Post by Sergio Fernandez
p= (char *) malloc (strlen("Esto es una prueba") * sizeof (char));
la memoria queda:
PosMem Value Tamaño
20000 (basura) 19

Y el valor de p sería:
PosMem Value Tamaño
1038 20000 4

Después, cuando haces la otra asignación de p quedaría:
PosMem Value Tamaño
1038 1019 4

Si en vez de todo ese código hicieras:
char *p = "Esto es una prueba"

El resultado sería el mismo y la memoria quedaría:
PosMem Value Tamaño
1000 Esto es una prueba(nulo) 19
1019 1000 4 (posición reservada para p)

*Nota: Cuando digo que el compilador reserva tanto espacio para esta
variable o esta constante, me refiero a que prepara al programa para que
cuando éste se cargue en memoria deje el espacio (ahora mismo no me
acuerdo si lo reserva en el montículo o en el segmento del programa). Es
diferente al método utilizado por malloc que reserva sí y sólo sí la
ejecución ejecuta la instrucción malloc (o su equivante en código
máquina :P)
javuchi
2004-02-11 03:44:12 UTC
Permalink
Post by jagg
void main()
{
char *p;
p= (char *) malloc (strlen("Esto es una prueba") * sizeof (char));
p="Esto es una prueba";
free (p);
}
Probablemente, este código genere un error de violación de segmentación.
El problema se encuentra en las últimas líneas:

p="Esto es una prueba";
free(p);

¿Porqué? Porqué aunque anteriormente hayas reservado memoria, después
has asignado a "p" el valor de la dirección a una constante, perdiendo
su valor inicial.
Claro, luego intentas liberar "p" y te da error, pues "p" ya no está
apuntando a la dirección dinámica que primero generaste.

Luego hay dos formas de hacer este código correctamente.

La primera, que es estática:

void main ()
{
char *p ="Esto es una prueba";
}


Y la segunda, que es dinámica:

void main ()
{
char *p=strcpy("Esto es una prueba");
}

En la primera, p apunta a una dirección constante, cuyo contenido no
debería modificarse, pues podría colgar la aplicación.
En la segunda, p apunta a una dirección de memoria dinámica cuyo
contenido si puede modificarse sin problema, pero tiene el inconveniente
de gastar el doble de memoria (en realidad lo que hacemos es copiar el
contenido estático de un espacio de memoria a otro dinámico).

Es decir, en la primera NO podríamos hacer, por ejemplo, p[2]='j', pero
en la segunda si.

Saludos.
opotonil
2004-02-06 22:54:47 UTC
Permalink
Buenas.

Estoy completamente de acuerdo con que tengas que reservar memoria de forma
dinamica como te indican:

p= (char *) malloc (strlen("Esto es una prueba") * sizeof (char));

pero ten en cuenta que tienes que reservar siempre strlen() + 1 para el
caracter de final de cadena que es "\0".

Por otra parte nunca e visto que se pueda asignar a una variable char una
cadena (de mas de un caracter, claro) mediante un = sino que se tendria que
utilizar la funcion strcpy(variable, cadena); de la string.h si no recuerdo
mal.

Salu2.
Leto Atreides
2004-02-09 10:12:34 UTC
Permalink
Para asignar la cadena "Esto es una prueba" a un puntero, únicamente hay
que hacer lo siguiente:

char *p = "Esto es una prueba";

Y funciona perfectamente, sin problemas en ningún compilador, versión o
plataforma. No hace falta reservar dinámicamente memoria y es la forma
más eficaz, eficiente y que consume menos recursos.

Agur,
Leto Atreides
Mikel Irazabal
2004-02-09 10:51:55 UTC
Permalink
Post by opotonil
Estoy completamente de acuerdo con que tengas que reservar memoria de forma
p= (char *) malloc (strlen("Esto es una prueba") * sizeof (char));
Así estás desaprovechando memoria, como bien explicó Leto Atreides en su
respuesta a Sergio Fernández.
Post by opotonil
Por otra parte nunca e visto que se pueda asignar a una variable char una
cadena (de mas de un caracter, claro) mediante un = sino que se tendria que
utilizar la funcion strcpy(variable, cadena); de la string.h si no recuerdo
mal.
No es eso lo que hace, como bien le explicó Leto Atreides a jagg p es un
puntero (apunta a un punto concreto de la memoria, a una dirección), no
contiene ningún caracter.

Una cadena es una secuencia de caracteres terminada en un valor nulo, y
para referirse a una se usa la dirección del primer caracter.

Así que:

char *puntero; /* Esto es un puntero */
char caracter = 'a'; /* Esto es un sólo caracter */
char array[10]; /* Esto es un array de 10 caracteres */
char ptrcte[] = "Cadena"; /* Esto es un puntero constante que apunta a
una dirección que contiene la cadena "Cadena" */

puntero = &caracter; /* puntero apunta al caracter */
printf("%c", *puntero); /* Imprime el caracter 'a' */
puntero = ptrcte; /* puntero apunta al mismo sition que ptrcte */
printf("%s", puntero); /* Imprime la cadena "Cadena" */
strcpy(array, ptrcte); /* Copia cada uno de los caracteres de "Cadena"
y el '\0' terminador al array */
printf("%s", array); /* Imprime la cadena "Cadena" */
puntero = array; /* puntero apunta al primer caracter del array */
printf("%s", puntero); /* Imprime la cadena "Cadena" */



Si no entiendes esto de arriba leete un capitulo sobre punteros de algún
libro/tutorial de C.

Saludos,

Mikel
Leto Atreides
2004-02-09 11:49:28 UTC
Permalink
Post by Mikel Irazabal
Post by opotonil
Estoy completamente de acuerdo con que tengas que reservar memoria de forma
p= (char *) malloc (strlen("Esto es una prueba") * sizeof (char));
Así estás desaprovechando memoria, como bien explicó Leto Atreides en su
respuesta a Sergio Fernández.
Post by opotonil
Por otra parte nunca e visto que se pueda asignar a una variable char una
cadena (de mas de un caracter, claro) mediante un = sino que se tendria que
utilizar la funcion strcpy(variable, cadena); de la string.h si no recuerdo
mal.
No es eso lo que hace, como bien le explicó Leto Atreides a jagg p es un
puntero (apunta a un punto concreto de la memoria, a una dirección), no
contiene ningún caracter.
Una cadena es una secuencia de caracteres terminada en un valor nulo, y
para referirse a una se usa la dirección del primer caracter.
char *puntero; /* Esto es un puntero */
char caracter = 'a'; /* Esto es un sólo caracter */
char array[10]; /* Esto es un array de 10 caracteres */
char ptrcte[] = "Cadena"; /* Esto es un puntero constante que apunta a
una dirección que contiene la cadena "Cadena" */
puntero = &caracter; /* puntero apunta al caracter */
printf("%c", *puntero); /* Imprime el caracter 'a' */
puntero = ptrcte; /* puntero apunta al mismo sition que ptrcte */
printf("%s", puntero); /* Imprime la cadena "Cadena" */
strcpy(array, ptrcte); /* Copia cada uno de los caracteres de "Cadena"
y el '\0' terminador al array */
printf("%s", array); /* Imprime la cadena "Cadena" */
puntero = array; /* puntero apunta al primer caracter del array */
printf("%s", puntero); /* Imprime la cadena "Cadena" */
Estoy totalmente de acuerdo con Mikel pero yo añadiría a su lista de
ejemplos el siguiente:

char *p = "Esto es una prueba";
printf("%c",p[5]); /* Imprime la letra 'e' puesto que los punteros se
pueden tratar como arrays del tipo definido en el puntero (en este caso
char) */
p***@nospam.demon.co.uk
2004-02-09 17:39:04 UTC
Permalink
In article <c07olu$13i1sk$***@ID-172074.news.uni-berlin.de>
***@yahoo.es "Mikel Irazabal" writes:
[..]
Post by Mikel Irazabal
char *puntero; /* Esto es un puntero */
ok
Post by Mikel Irazabal
char caracter = 'a'; /* Esto es un sólo caracter */
ok
Post by Mikel Irazabal
char array[10]; /* Esto es un array de 10 caracteres */
ok
Post by Mikel Irazabal
char ptrcte[] = "Cadena"; /* Esto es un puntero constante que apunta a
una dirección que contiene la cadena "Cadena" */
¡no! 'ptrcte' is _not_ a pointer, constant or otherwise. It
defines an array { 'C','a','d','e','n','a','\0' } which will
likely be located in a CONST section (but not necessarily). A
pointer is a variable (even if its contents cannot be changed :-)
that contains an address; 'ptrcte' is a "symbolic address" which
to which the compiler assigns the value of the address of the 'C'
of the char array "Cadena".

Using the symbol ptrcte in your program causes the compiler to
use this address, but ptrcte is _not a pointer_ :-)
Post by Mikel Irazabal
puntero = &caracter; /* puntero apunta al caracter */
Exactly. But one could not write (generally)

ptrcte = puntero;

which would be legal if ptrcte were a pointer.

Please accept my apologies for butting in (y por escribir in
ingles...)

Saludos
Pete
--
"We have not inherited the earth from our ancestors,
we have borrowed it from our descendants."
Mikel Irazabal
2004-02-10 08:38:51 UTC
Permalink
Post by p***@nospam.demon.co.uk
Post by Mikel Irazabal
char ptrcte[] = "Cadena"; /* Esto es un puntero constante que apunta a
una dirección que contiene la cadena "Cadena" */
¡no! 'ptrcte' is _not_ a pointer, constant or otherwise. It
defines an array { 'C','a','d','e','n','a','\0' } which will
likely be located in a CONST section (but not necessarily). A
pointer is a variable (even if its contents cannot be changed :-)
that contains an address; 'ptrcte' is a "symbolic address" which
to which the compiler assigns the value of the address of the 'C'
of the char array "Cadena".
Using the symbol ptrcte in your program causes the compiler to
use this address, but ptrcte is _not a pointer_ :-)
Yes, right. I only wanted to say you can use ptrcte as a constant
pointer, and didn't say it correctly. I thought these two were the same:

char string1[] = "String";
const char *string2 = "String";

But I guess from what you said, that the second one allocates memory for
a pointer an the first one doesn't.
Post by p***@nospam.demon.co.uk
Post by Mikel Irazabal
puntero = &caracter; /* puntero apunta al caracter */
Exactly. But one could not write (generally)
ptrcte = puntero;
which would be legal if ptrcte were a pointer.
But not if it were a constant pointer (it can be took as if it were that).

Nevertheless, I understand and agree that ptrcte isn't really a pointer,
but an internal simbol name that compiler uses to refer to that address.
Post by p***@nospam.demon.co.uk
Please accept my apologies for butting in (y por escribir in
ingles...)
A good correction in a proper way is always wellcome.



Breve resumen en español:

He llamado puntero constante a algo que en realidad no lo es (aunque se
pueda usar como tal).
p***@nospam.demon.co.uk
2004-02-10 19:08:44 UTC
Permalink
Post by Mikel Irazabal
Post by p***@nospam.demon.co.uk
Post by Mikel Irazabal
char ptrcte[] = "Cadena"; /* Esto es un puntero constante que apunta a
una dirección que contiene la cadena "Cadena" */
¡no! 'ptrcte' is _not_ a pointer, constant or otherwise. It
defines an array { 'C','a','d','e','n','a','\0' } which will
likely be located in a CONST section (but not necessarily). A
pointer is a variable (even if its contents cannot be changed :-)
that contains an address; 'ptrcte' is a "symbolic address" which
to which the compiler assigns the value of the address of the 'C'
of the char array "Cadena".
Using the symbol ptrcte in your program causes the compiler to
use this address, but ptrcte is _not a pointer_ :-)
Yes, right. I only wanted to say you can use ptrcte as a constant
Estaba maleducado escribir inglés en este grupo :-( Intentaré
responder en español (pero a mi no es facíl).
Post by Mikel Irazabal
char string1[] = "String";
const char *string2 = "String";
But I guess from what you said, that the second one allocates memory for
a pointer an the first one doesn't.
Eso es; pero un buen compilador podía optimizar el segundo al
primero y producir el mismo código. No es garantizado...
Post by Mikel Irazabal
Post by p***@nospam.demon.co.uk
Post by Mikel Irazabal
puntero = &caracter; /* puntero apunta al caracter */
Exactly. But one could not write (generally)
ptrcte = puntero;
which would be legal if ptrcte were a pointer.
But not if it were a constant pointer (it can be took as if it were that).
[I commend your understanding and use of the subjunctive form; if
only all native English speakers were so well versed...]
Post by Mikel Irazabal
Nevertheless, I understand and agree that ptrcte isn't really a pointer,
but an internal simbol name that compiler uses to refer to that address.
Ahí está. Un puntero real puede ser 'lvalue' o 'rvalue';
'ptrcte' no puede nunca ser 'lvalue'. Pero no me cabe duda de
que lo sabes :-)
Post by Mikel Irazabal
Post by p***@nospam.demon.co.uk
Please accept my apologies for butting in (y por escribir in
ingles...)
A good correction in a proper way is always wellcome.
Creo que punteros en C sean las cosas las mas incomprendidas del
lenguaje -- todo poco ayuda el entendimiento. Espero...
Post by Mikel Irazabal
He llamado puntero constante a algo que en realidad no lo es (aunque se
pueda usar como tal).
[Indeed so. Thank you for your reply, Mikel. I read this group
partly for interest as a C programmer for nearly 20 years and
partly to help my learning of Spanish -- please feel free to
correct me on the latter!]

Saludos,
Pete
--
"We have not inherited the earth from our ancestors,
we have borrowed it from our descendants."
[check header entries if trying to reply by email]
Mikel Irazabal
2004-02-11 08:26:40 UTC
Permalink
Post by p***@nospam.demon.co.uk
Estaba maleducado escribir inglés en este grupo :-(
Es que para eso hay montones de grupos en inglés ;-)
Post by p***@nospam.demon.co.uk
Intentaré
responder en español (pero a mi no es facíl).
No lo haces nada mal.
Post by p***@nospam.demon.co.uk
[I commend your understanding and use of the subjunctive form; if
only all native English speakers were so well versed...]
Thanks, but I don't write so well :*)
Post by p***@nospam.demon.co.uk
Post by Mikel Irazabal
A good correction in a proper way is always wellcome.
I meant welcome ;-)
Post by p***@nospam.demon.co.uk
Post by Mikel Irazabal
He llamado puntero constante a algo que en realidad no lo es (aunque se
pueda usar como tal).
[Indeed so. Thank you for your reply, Mikel. I read this group
partly for interest as a C programmer for nearly 20 years and
partly to help my learning of Spanish -- please feel free to
correct me on the latter!]
Estaba maleducado
Era maleducado
(o es, porque lo sigue siendo)
Post by p***@nospam.demon.co.uk
(pero a mi no es facíl).
(pero para mí no es fácil).
Post by p***@nospam.demon.co.uk
Creo que *los* punteros en C *son* las cosas las mas incomprendidas
del lenguaje
De todas maneras, se te ha entendido bien todo lo que has escrito, y te
animo a que escribas en español en este grupo.


PS.:

I tried to send this directly to your e-mail address but got SMTP errors.
Loading...