¿Qué devuelve sizeof(&array)?

10 minutos de lectura

avatar de usuario
usuario1980750

Siguiendo la pregunta: ¿Cómo es que la dirección de una matriz es igual a su valor en C?

#include <stdio.h>
#define N 10    
char str2[N]={"Hello"};
int main(){
    printf("sizeof(str2): %d bytes\n", sizeof(str2));
    printf("sizeof(&str2): %d bytes\n", sizeof(&str2));
    return 0;
}

Producción:

sizeof(str2): 10 bytes
sizeof(&str2): 4 bytes

Yo sé eso str2 solo es la dirección del primer elemento en la matriz str2. y que cuando str2 es un argumento de sizeof devuelve el tamaño de toda la matriz str2.

Además, &str2 es también la dirección del primer elemento en arr str2 pero de diferente tipo (char (*)[N] == puntero a la matriz). pero como &str2 comportarse cuando es un argumento de sizeof?

  • “Yo sé eso str2 solo es la dirección del primer elemento en la matriz str2“- bueno, no lo es. Se convierte en un puntero a su primer elemento en la mayoría de los contextos, pero sizeof 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 un char[], 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

avatar de usuario
grijesh chauhan

Diferencia entre &str y strcuando 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 charque 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?

str2 es de tipo char [10] (es decir, matriz 10 ofchar`)

&str2 es de tipo char (*)[10] (es decir, puntero a una matriz 10 de char).

Asi que sizeof (&str2) produce el tamaño de un objeto de tipo puntero char (*)[10]

avatar de usuario
lloviendo

Si simplemente usas la variable arr (como definido char arr[10]), siempre decae a un puntero constante char *const arr apuntando al primer elemento. Mientras &arr da como resultado un puntero char (*)[10] ese incluye la talla de arryo G 10.

&str2 es un puntero. Así que solo estás viendo el tamaño de un puntero en tu plataforma.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad