¿Cuál es la diferencia entre asignar un puntero de cadena primero a la memoria asignada y directamente a un literal de cadena?

Así que mi entendimiento es que estos dos bloques de códigos son válidos y hacen lo mismo.

1.)

char *ptr = malloc(5); ptr = "hi"; 

2.)

 char *ptr = "hi"; 

Me gustaría saber la diferencia entre los dos como si hubiera alguna ventaja de uno sobre el otro.

El primero es un error, y ese código nunca debería haber sido escrito.

Sobrescribe el puntero devuelto por malloc() con la dirección de una cadena literal, dejando caer el puntero original y perdiendo memoria.

Debe usar strcpy() o algún otro método de copia de memoria para inicializar la memoria de stack recién asignada con una cadena.

El segundo simplemente asigna la dirección (constante de tiempo de ejecución) del literal de cadena al puntero ptr , no se copian caracteres en ninguna parte.

El primer bit es una posible pérdida de memoria, el segundo se basa en la clase de almacenamiento const implícita que se está utilizando y asigna la dirección de memoria de una cadena inmutable a un puntero.
Básicamente:

 char *ptr = malloc(5);//allocates 5 * sizeof *ptr //then assigns the address where this block starts to ptr //this: ptr = "hi";//assigns position of 'h','i', '\0' in read-only mem to ptr 

Ahora, la dirección que ha asignado, a la que apunta ptr , todavía está asignada. La diferencia es que ya no tiene “manejador” porque el valor de ptr cambió. No hay un puntero que apunte a la memoria dinámica que asignó usando malloc , por lo que es bastante difícil administrar la memoria … Probablemente no podrá free , y llamar free en ptr ahora resultará en un comportamiento indefinido.
Si tú escribes:

 char *ptr = "hi"; 

Entonces en realidad estás escribiendo:

 const char *ptr = "hi"; 

Lo que significa que no puedes cambiar la cadena a la que ptr apunta:

 ptr[0] = 'H';//IMBOSSIBRU 

Las alternativas son:

 char string[] = "Hi";//copies Hi\0 to string //or char *ptr = malloc(5); strcpy(ptr, "hi");//requires string.h 

La diferencia entre los dos fragmentos de código anteriores es que el primero crea una matriz de stack, el segundo asigna un bloque de memoria en el montón. La memoria de stack es más fácil de administrar, más rápida y mejor en casi todos los aspectos, además de ser menos abundante y realmente no se puede utilizar como valor de retorno …

Hay un grupo de literales de cadena para cada proceso. Cuando creas un literal de cadena dentro de tu código, el literal se guarda en el grupo y se devuelve la dirección de la cadena (es decir, una dirección que apunta a algún lugar del grupo). Por lo tanto, está creando una pérdida de memoria en su primera opción, porque está sobrescribiendo la dirección que recibió con malloc.

En el primer caso

 char *ptr = malloc(5); ptr = "hi"; 

Hay una pérdida de memoria y más tarde está apuntando ptr a una cadena literal “hola” que requiere memoria del montón (por eso hay una pérdida de memoria).

Pero si está asignando la memoria y si está utilizando

 strcpy (ptr, "hi"); 

Entonces si lo deseas puedes modificarlo.

 strcpy (ptr, "hello") 

con una condición que asigne suficiente memoria antes.

Pero en su caso, está asignando un puntero ptr con una cadena literal, aquí no podrá modificarlo.

 ptr = "hello" // not valid. This will give a segmentation fault error 

En su segundo caso, no hay pérdida de memoria y está haciendo un puntero para apuntar a una cadena literal y, por lo tanto, su valor no se puede modificar, ya que se almacenará en un segmento de datos de solo lectura.