Implementando una función de copia de cadena en C

En una reciente entrevista de trabajo, me pidieron que implementara mi propia función de copia de cadenas. Me las arreglé para escribir código que creo que funciona hasta cierto punto. Sin embargo, cuando volví a casa para intentar el problema nuevamente, me di cuenta de que era mucho más complejo de lo que había pensado. Aquí está el código que se me ocurrió:

#include  #include  char * mycpy(char * d, char * s); int main() { int i; char buffer[1]; mycpy(buffer, "hello world\n"); printf("%s", buffer); return 0; } char * mycpy (char * destination, char * source) { if (!destination || !source) return NULL; char * tmp = destination; while (*destination != NULL || *source != NULL) { *destination = *source; destination++; source++; } return tmp; } 

Miré algunos otros ejemplos en línea y descubrí que dado que todas las cadenas en C terminan en nulo, debería haber leído el carácter nulo y luego agregar un carácter nulo a la cadena de destino antes de salir.

Sin embargo, algo de lo que tengo curiosidad es cómo se maneja la memoria. Noté que si utilizaba la función de biblioteca strcpy (), podría copiar una cadena de 10 caracteres en una matriz de caracteres de tamaño 1. ¿Cómo es posible? ¿La función strcpy () está asignando de alguna manera más memoria al destino?

La buena pregunta de la entrevista tiene varias capas, a las que el candidato puede demostrar diferentes niveles de comprensión.

En la capa sintáctica ‘lenguaje C’, el siguiente código es del clásico libro de Kernighan y Ritchie (‘El lenguaje de progtwigción C’):

 while( *dest++ = *src++ ) ; 

En una entrevista, podría indicar que la función no es segura, sobre todo que el buffer en *dest no es lo suficientemente grande. Además, puede haber superposición, es decir, si dest apunta a la mitad del búfer src , tendrá un bucle sin fin (que eventualmente creará un error de acceso a la memoria).

No, es que strcpy() no es seguro y está sobrescribiendo la memoria después de eso, creo. Se supone que debes usar strncpy() lugar.

Como han dicho las otras respuestas, usted está sobrescribiendo el búfer, así que por el bien de su prueba, cambie a:

 char buffer[ 12 ]; 

Para la entrevista de trabajo tal vez esperaban:

 char *mycpy( char *s, char *t ) { while ( *s++ = *t++ ) { ; } return s; } 

No, está escribiendo más allá del búfer y sobrescribiendo (en este caso) el rest de su stack más allá del búfer. Este es un comportamiento muy peligroso.

En general, siempre debe crear métodos que proporcionen límites. En la mayoría de las bibliotecas de C, estos métodos se indican con una n en el nombre del método.

C no realiza ninguna comprobación de límites de tiempo de ejecución como otros idiomas (C #, Java, etc.). Es por eso que puedes escribir cosas más allá del final de la matriz. Sin embargo, no podrá acceder a esa cadena en algunos casos porque podría estar invadiendo la memoria que no le pertenece, lo que le provoca un error de segementación. K&R sería un buen libro para aprender tales conceptos.

La función strcpy() renuncia a la administración de la memoria por completo, por lo tanto, toda la asignación debe realizarse antes de llamar a la función, y liberarse después cuando sea necesario. Si la cadena de origen tiene más caracteres que el búfer de destino, strcpy() seguirá escribiendo más allá del final del búfer en el espacio no asignado, o en el espacio asignado para otra cosa.

Esto puede ser muy malo.

strncpy() funciona de manera similar a strcpy() , excepto que le permite pasar una variable adicional que describe el tamaño del búfer, por lo que la función dejará de copiar cuando scope este límite. Esto es más seguro, pero aún depende del progtwig de llamada para asignar y describir el búfer de manera adecuada; todavía puede pasar el final del búfer si proporciona la longitud incorrecta, lo que lleva a los mismos problemas.

 char * mycpy (char * destination, char * source) { if (!destination || !source) return NULL; char * tmp = destination; while (*destination != NULL || *source != NULL) { *destination = *source; destination++; source++; } return tmp; } 

En la implementación de copia anterior, su tmp y destino tienen los mismos datos. Es mejor que no recupere ningún dato, y en su lugar deje que el destino sea su parámetro de salida. ¿Puedes reescribir lo mismo?

La siguiente versión funciona para mí. No estoy seguro si es mal diseño sin embargo:

 while(source[i] != '\0' && (i<= (MAXLINE-1))) { dest[i]=source[i]; ++i; } 

En general, siempre es una buena idea tener un modificador const donde sea posible, por ejemplo, para el parámetro fuente .