Combiner de répertoire et de fichier chemin d'accès - C
Dans le cadre de l'apprentissage du C, j'ai écrit le code suivant pour combiner nom de répertoire avec un nom de fichier. Par exemple: combine("/home/user", "filename")
entraînera /home/user/filename
. Cette fonction devrait fonctionner sur toutes les plateformes (atleast sur toutes les distributions linux et windows 32 et 64 bits).
Voici le code.
const char* combine(const char* path1, const char* path2)
{
if(path1 == NULL && path2 == NULL) {
return NULL;
}
if(path2 == NULL || strlen(path2) == 0) return path1;
if(path1 == NULL || strlen(path1) == 0) return path2;
char* directory_separator = "";
#ifdef WIN32
directory_separator = "\\";
#else
directory_separator = "/";
#endif
char p1[strlen(path1)]; //(1)
strcpy(p1, path1); //(2)
char *last_char = &p1[strlen(path1) - 1]; //(3)
char *combined = malloc(strlen(path1) + 1 + strlen(path2));
int append_directory_separator = 0;
if(strcmp(last_char, directory_separator) != 0) {
append_directory_separator = 1;
}
strcpy(combined, path1);
if(append_directory_separator)
strcat(combined, directory_separator);
strcat(combined, path2);
return combined;
}
J'ai les questions suivantes concernant le code ci-dessus.
- Examiner les lignes, numérotées 1,2,3. Tous ces 3 lignes sont pour obtenir le dernier élément de la chaîne. On dirait que je suis en train d'écrire plus de code pour une si petite chose. Quelle est la bonne méthode pour obtenir le dernier élément de la
char*
chaîne. - De retourner le résultat, je suis l'allocation d'une nouvelle chaîne à l'aide de
malloc
. Je ne suis pas sûr que ce soit la bonne façon de le faire. L'appelant devrait libérer le résultat? Comment puis-je indiquer à l'appelant qu'il a de libre que le résultat? Est-il réduit les risques d'erreurs de méthode disponible? - Comment évaluez-vous le code (Faible, Moyen, Bon)? Quelles sont les zones qui peuvent être imrpoved?
Toute aide serait super.
Modifier
Fixe toutes les questions discutées et mises en œuvre les modifications proposées. Voici le code mis à jour.
void combine(char* destination, const char* path1, const char* path2)
{
if(path1 == NULL && path2 == NULL) {
strcpy(destination, "");;
}
else if(path2 == NULL || strlen(path2) == 0) {
strcpy(destination, path1);
}
else if(path1 == NULL || strlen(path1) == 0) {
strcpy(destination, path2);
}
else {
char directory_separator[] = "/";
#ifdef WIN32
directory_separator[0] = '\\';
#endif
const char *last_char = path1;
while(*last_char != 'void combine(char* destination, const char* path1, const char* path2)
{
if(path1 == NULL && path2 == NULL) {
strcpy(destination, "");;
}
else if(path2 == NULL || strlen(path2) == 0) {
strcpy(destination, path1);
}
else if(path1 == NULL || strlen(path1) == 0) {
strcpy(destination, path2);
}
else {
char directory_separator[] = "/";
#ifdef WIN32
directory_separator[0] = '\\';
#endif
const char *last_char = path1;
while(*last_char != '\0')
last_char++;
int append_directory_separator = 0;
if(strcmp(last_char, directory_separator) != 0) {
append_directory_separator = 1;
}
strcpy(destination, path1);
if(append_directory_separator)
strcat(destination, directory_separator);
strcat(destination, path2);
}
}
')
last_char++;
int append_directory_separator = 0;
if(strcmp(last_char, directory_separator) != 0) {
append_directory_separator = 1;
}
strcpy(destination, path1);
if(append_directory_separator)
strcat(destination, directory_separator);
strcat(destination, path2);
}
}
Dans la nouvelle version, l'appelant a allouer suffisamment de mémoire tampon et de l'envoyer à combine
méthode. Cela évite l'utilisation de malloc
et free
question. Ici est l'utilisation
int main(int argc, char **argv)
{
const char *d = "/usr/bin";
const char* f = "filename.txt";
char result[strlen(d) + strlen(f) + 2];
combine(result, d, f);
printf("%s\n", result);
return 0;
}
Des suggestions d'améliorations?
OriginalL'auteur Navaneeth K N | 2010-06-29
Vous devez vous connecter pour publier un commentaire.
Et il y a une fuite de mémoire:
Edit: Votre nouveau code a l'air mieux. Quelques petits changements de style:
;;
à la ligne 4.strlen(path2) == 0
avecpath2[0] == '\0''
ou tout simplement!path2[0]
.last_char
, et l'utilisationconst char last_char = path1[strlen(path1) - 1];
if(append_directory_separator)
àif(last_char != directory_separator[0])
. Et si vous n'avez pas besoin de la variableappend_directory_separator
plus.destination
, semblable àstrcpy(dst, src)
, qui renvoiedst
.Modifier: Et votre boucle pour
last_char
a un bug: elle renvoie toujours à la fin depath1
, et donc, vous pourriez vous retrouver avec un double slash //dans votre réponse. (Mais Unix permettra de traiter cela comme une seule barre oblique, sauf s'il est au départ). De toute façon, ma suggestion de corrections, qui je vois, c'est tout à fait semblable à jdmichal de réponse. Et je vois que vous avez eu ce correct dans votre original code (qui je l'avoue j'ai seulement jeté un coup d'oeil à--c'était trop compliqué à mon goût; votre nouveau code est beaucoup mieux).Et deux autres, un peu plus subjectif, de l'avis:
stpcpy()
, pour éviter l'inefficacité destrcat()
. (Facile à écrire votre propre, si besoin est.)strcat()
et la comme comme étant dangereux. Cependant, je pense que votre utilisation ici est parfaitement bien.est le même que
free("bar")
. Qui ne peut pas être un catastrophe. Mais il n'est pas défini.Depuis que vous avez raccourci et retour
path1
oupath2
si l'autre paramètre est vide, il est inconnu de l'utilisateur s'il doit libérer la valeur retournée ou non. Bonne prise.J'ai mis à jour le post avec la dernière version du code. Veuillez prendre un coup d'oeil à nouveau.
Merci pour la réponse. J'ai résolu le problème et appris beaucoup de choses. Merci encore.
OriginalL'auteur Joseph Quinsey
last_char
est dans la comparaison de vérifier si le dernier caractère est un séparateur.Pourquoi ne pas le remplacer par ceci:
Si vous voulez tenir compte de la possibilité de plusieurs caractères séparateurs, vous pouvez utiliser ce qui suit. Mais assurez-vous lors de l'attribution des combinés de la chaîne d'ajouter strlen(directory_separator) au lieu de 1.
Le moins d'erreur de la méthode pour les utilisateurs de vous donner le tampon de destination et de sa longueur, de la manière
strcpy
œuvres. Il est clair qu'ils doivent gérer l'allocation et la libération de la mémoire.Le processus semble assez décent. Je pense qu'il y a juste quelques détails qui peut être travaillé principalement à faire les choses dans un maladroit. Mais vous faites bien, que vous pouvez déjà conscients de ce qui se passe et demander de l'aide.
Dans Unix, MAX_PATH_LEN est raisonnable de taille de la mémoire tampon.
De même, Windows dispose d'un MAX_PATH, qui est de 260 caractères.
Si je fais
directory_separator
unchar
au lieu dechar*
, comment puis-je l'utiliser dansstrcat
?J'ai mis à jour le post avec la dernière version du code. Veuillez prendre un coup d'oeil à nouveau.
OriginalL'auteur jdmichal
C'est ce que j'utilise:
OriginalL'auteur Andrei Sedoi
Juste une petite remarque pour améliorer votre fonction:
Windows prend en charge les deux
'/'
et'\\'
séparateurs dans les chemins. Je devrais donc être en mesure d'effectuer l'appel suivant:Une idée lors de la rédaction d'un projet multiplateforme pourrait être de convertir
'\\'
à'/'
dans aucun chemin d'entrée (à partir de la saisie de l'utilisateur, les fichiers chargés,...), alors, vous n'avez à traiter avec'/'
caractères.Ce qui concerne.
OriginalL'auteur S.Clem
Un rapide coup d'œil montre:
//
les commentaires de style, je suis en mesure de compiler mon programme sur un compilateur C. 2. Je n'ai pas ce point. Pourquoi devrait-il être défini au début de la fonction? De nouveau ce code compile sans aucun avertissement.Les deux premiers points sont corrects, en ANSI C prend en charge uniquement les commentaires à l'aide de
/* */
paires et les déclarations de variables au-dessus de la portée. Mais nombreux sont les compilateurs modernes violent à la fois de ces à la facilité de programmation. Qui est, ils acceptent//
les commentaires et réorganiser automatiquement les déclarations de variables lors de la compilation.C++ commentaires et mêlé les déclarations sont valables C99.
Euh, un peu. Par "les compilateurs modernes violent", tu veux dire "les compilateurs modernes adhère au moins à c99". À l'aide de
-ansi
va appliquer la norme ISO C89 ou ISO C90 normes, ce qui permettra d'erreur C++-style de commentaires.OriginalL'auteur bohica