Diferencia entre &str
y str
cuando str
se declara como char str[10]
?
Leer sizeof
Operador:
6.5.3.4 El tamaño del operador, 1125:
Cuando aplicas el sizeof
operador a un tipo de matriz, el resultado es el número total de bytes en la matriz.
Entonces, de acuerdo con su declaración, sizeof(str2)
da el tamaño completo de la matriz que es de 10 bytes (porque N se define como 10 y el tamaño de caracteres es de 1 byte).
Mientras que en la expresión sizeof(&str2)
, &str2
es una dirección de una matriz y el tamaño de esa dirección es de 4 bytes en su sistema. (el tamaño de la dirección puede ser de 8 bytes en algunos sistemas, por ejemplo, 64 bits).
Además, &str2
es también la dirección del primer elemento en arr str2
?
Noen cuanto a valor ambos &str2
y str
son iguales, pero semánticamente ambos son diferentes. Uno es una dirección de una matriz de 10 caracteres, mientras que el otro es una dirección de un carácter.
Uno la diferencia que ha visto en su propio ejemplo entre ellos es (@ouah explicó esto en una respuesta).
- tipo de
str
es char[10]
- tipo de
&str
es char(*)[10]
Segundo:
Seguir un diagrama te ayudará a observar la otra diferencia.
for declaration:
#define N 10
char str2[N] = {"Hello"};
str2 Array in memory is something like:
----------------------------------------
str
+----+----+----+----+----+----+----+----+----+----++----+
|'H' |'e' |'l' |'l' |'o' |'\0'|'\0'|'\0'|'\0'|'\0'|| '@'|
+----+----+----+----+----+----+----+----+----+----++----+
201 202 203 204 205 206 207 208 209 210 211
▲ ▲ ▲ ▲
| | | |
|(str2) (str2 + 1) |
| |
|-----------------------------------------------------|
|201 |
| |
| |
(&str2) = 201 (&str2 + 1) = 211
* assuming str address start from 201
* str[N] is 10 char long 201-210, partially initialized
* at uninitialized position, str2[i] = '\0'
* location 211 is unallocated, having garbage value,
access to this location is illegal-Undefined Behavior
Para el diagrama anterior, puede escribir código como:
#include <stdio.h>
#define N 10
int main(){
char str2[N]={"Hello"};
printf("\n %p, %p\n",str2, str2+1);
printf("\n %p, %p\n",(&str2), (&str2+1));
}
Producción:
0xbf67e142, 0xbf67e143
0xbf67e142, 0xbf67e14c
UN enlace para el teclado:
Observe que en la primera línea, la dirección de salida difiere en un byte, pero en la segunda, la diferencia es de 10 bytes porque es la matriz puntero (como se muestra en el diagrama anterior).
De acuerdo con las reglas de la aritmética de punteros, cuando agregas 1 a una variable de puntero, comienza a apuntar al siguiente elemento de su propio tipo. Esa es la razón de la diferencia de 10 bytes porque &str2
es una dirección que apunta a una matriz.
Tercera diferencia:
Haciendo *str2
puedes acceder al primer elemento. Mientras *(&str2)
no le dará el primer elemento, sino que le dará la dirección del primer elemento.
Un ejemplo ayudará aquí:
#include <stdio.h>
#define N 10
int main(){
char str2[N]={"Hello"};
printf("\n%p %c, %p %c\n",str2, *(str2), *(&str2), **(&str2));
}
producción:
0xbf587046 H, 0xbf587046 H
Enlace del teclado
en salida
str2 gives 0xbf587046
*(str2) H
*(&str2) 0xbf587046
**(&str2) H
Eso significa *(&str2) == str2
y el valor es la dirección. Y por lo tanto *(str2) = **(&str2)
valores es H
.
Editar: Arriba mostré la diferencia entre &str
y str
donde str
es una matriz de tipo char[10]
.
Diferencia entre char *str
y char str[]
y cómo ambos se almacenan en la memoria
Supongamos que tenemos dos declaraciones como las siguientes:
char *str1 = "hello";
char str2[] = "hello";
En las declaraciones anteriores str1
es un puntero a char
que apunta a un literal de cadena constante (manteniendo la dirección del primer carácter h
en "hello"
cuerda).
Una cadena en C es de char[N]
(matriz) tipo por eso sizeof("hello")
da 6 porque "hello"
la cadena tiene una matriz de 6 caracteres (incluida \0
nul, terminación de cadenas, tipo de hola es char[6]
).
En la memoria tu "hello"
cadena se almacena así:
str1 23 24 25 26 27 28
+----+ +----+----+----+----+----+----+
| 23 | | h | e | l | l | o | \0 |
+----+ +----+----+----+----+----+----+
+-----------▲
here the address of the hello string is the first address = 23.
str1: is a pointer capable of storing an address.
"hello" consists of 6 chars
char* str1 = "hello";
básicamente almacena una dirección de una cadena hola en una variable de puntero str1
como muestro en la figura anterior.
Nota: Si lo desea, puede cambiar str1
para señalar alguna otra cadena. Pero no puedes modificar hello
cuerda. por ejemplo, el siguiente código es válido:
char* str1 = "hello"; // str1 points to hello str1-->"hello"
str1 = "world"; //Now, str1 points to world str1-->"world"
Ahora str1
apunta a otro mundo de cadenas constantes.
str1 93 94 95 96 97 98
+----+ +----+----+----+----+----+----+
| 93 | | w | o | r | l | d | \0 |
+----+ +----+----+----+----+----+----+
+-----------▲
here address of world string is first address = 93.
str1: value change to point string world.
Importante tener en cuenta: str1
apunta a cadenas constantes, por lo tanto, no puede modificar la cadena accediendo/indexando la ubicación de la memoria, por ejemplo str1[i] = 'A'
; será ilegal porque eres escribir en la memoria de solo lectura y el comportamiento de esto no está definido en tiempo de ejecución (aunque no hay error de compilación porque sintácticamente es correcto).
De nuevo, porque str1
es un puntero sizeof(str1)
dará 4 en la misma máquina.
Mi siguiente código y su ejecución:
#include <stdio.h>
int main(){
char* str1="Hello";
printf("\nstr1: %s, address: %p, sizeof(str1): %u", str1, str1, sizeof(str1));
str1 = "world";
printf("\nstr1: %s, address: %p, sizeof(str1): %u", str1, str1, sizeof(str1));
return 1;
}
Producción:
str1: Hello, address: 0x80485e8, sizeof(str1): 4
str1: world, address: 0x8048619, sizeof(str1): 4
Enlace del teclado
Entonces, para asignar una nueva cadena, simplemente asigno una dirección de una nueva cadena. pero no puedo llamar strcpy()
eso intentará escribir en una ubicación de memoria de solo lectura y eso es ilegal.
En la segunda declaración char str2[] = "hello";
, str2[]
es un \0
matriz terminada de caracteres (o cadena) pero NO un puntero. Aviso porque en esta declaración no se da el tamaño. tamaño predeterminadovemos que el tamaño de la cadena constante “hola” que es 6. Tipo de str2
es char[6]
.
cuando lo hacemos char str2[] = "hello";
se crea una matriz de caracteres y la cadena de saludo se copiará en esa matriz. Asi que str2
no es simplemente un puntero, sino una matriz que almacena una cadena completa.
Conceptualmente es como
str2:
103 104 105 106 107 108
+----+----+----+----+----+----+
| h | e | l | l | o | \0 |
+----+----+----+----+----+----+
En este caso últimamente en tu código estás no permitido hacer str2[] = "world";
o str2 = "world"
será un error de tiempo de compilación.
Código de ejemplo:
#include<stdio.h>
int main(){
char str2[] = "hello";
str2[] = "world";
str2 = "world";
return 1;
}
Errores de compilación:
In function 'main':
Line 4: error: expected expression before ']' token
Line 5: error: incompatible types in assignment
Enlace de Codescape
donde esta matriz str2
no es una constante, podemos modificar su contenido por ejemplo haciendo str2[2] = 'A'
es perfectamente valido. También podemos llamar a strcpy para cambiar el contenido (y el espacio de direcciones no cambiará)
strcpy(str2, "world");
str2:
103 104 105 106 107 108
+----+----+----+----+----+----+
| w | o | r | l | d | \0 |
+----+----+----+----+----+----+
Note that when "world" is copied into a same memory space, the addresses of both "world" and "hello"
string are the same.
Ejemplo de código:
#include<stdio.h>
int main(){
char str2[] = "hello";
printf("\nstr2: %s, address: %p, sizeof(str2): %u", str2, str2, sizeof(str2));
str2[2] = 'A';
printf("\nstr2: %s, address: %p, sizeof(str2): %u", str2, str2, sizeof(str2));
strcpy(str2, "world");
printf("\nstr2: %s, address: %p, sizeof(str2): %u", str2, str2, sizeof(str2));
return 1;
}
Producción:
str2: hello, address: 0xbf58d056, sizeof(str2): 6
str2: heAlo, address: 0xbf58d056, sizeof(str2): 6
str2: world, address: 0xbf58d056, sizeof(str2): 6
Enlace del teclado
Nota: los valores de cadena son diferentes en el mismo espacio de direcciones. sizeof(str2)
= 6 perfectamente entendido de la respuesta anterior que es el tamaño de la matriz en bytes.
Para leer una descripción similar sobre una matriz bidimensional, lea: Diferencia entre char* str[]
y char str[][]
y como se almacena tanto en la memoria?
“Yo sé eso
str2
solo es la dirección del primer elemento en la matrizstr2
“- bueno, no lo es. Se convierte en un puntero a su primer elemento en la mayoría de los contextos, perosizeof
es una de las excepciones.–Daniel Fischer
2 de marzo de 2013 a las 19:01
@DanielFischer entonces por qué
printf("%p %p",str2, str2+1);
imprime la dirección del primer y segundo elemento respectivamente?– usuario1980750
02/03/2013 a las 20:43
@ user1980750 Porque esa no es una de las excepciones. A menos que sea el operando de
sizeof
,_Alignof
o el operador de dirección&
o, en el caso de literales de cadena, como un inicializador para unchar[]
, una expresión de tipo matriz se convierte en un puntero al primer elemento de la matriz. así que en la mayoría contextos, el nombre de una matriz se evalúa como un puntero a su primer elemento, pero es algo diferente (el nombre de una matriz).–Daniel Fischer
02/03/2013 a las 20:53
@DanielFischer:
_Alignof
no es una de las excepciones, ya que_Alignof
solo se puede aplicar a un nombre de tipo entre paréntesis, no a una expresión. Eso fue un error en el N1570 borrador, corregido en la norma ISO C11 publicada. (Como para por qué_Alignof
no se puede aplicar a una expresión, esa es una pregunta diferente).–Keith Thompson
29 de agosto de 2013 a las 15:03
@KeithThompson Mientras tanto, lo sé. Creo que fuiste tú quien me lo dijo, pero también podría haber sido otra persona. Pero gracias de todos modos, incluso si es un agradecimiento repetido.
–Daniel Fischer
29 de agosto de 2013 a las 15:11