9
votes

Combinez le répertoire et le chemin de fichier - c

Dans le cadre de l'apprentissage C, j'ai écrit le code suivant pour combiner le nom du répertoire avec le nom de fichier. Par exemple: combine ("/ home / utilisateur", "nom de fichier") code> entraînera / home / utilisateur / nom_fichier code>. Cette fonction est attendue de travail entre toutes les plateformes (au moins sur toutes les distributions Linux populaires et Windows 32 et 64 bits).

Voici le code. P>

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;
}


0 commentaires

6 Réponses :


-2
votes

Un coup d'œil rapide montre:

  1. Vous utilisez des commentaires C ++ (//) qui n'est pas standard C
  2. Vous déclarez que les variables font partie du code - non pas C. Ils doivent être définis au début de la fonction.
  3. Votre chaîne P1 au n ° 1 a 1 trop d'octets l'écrit à # 2 car Strlen renvoie la longueur d'une chaîne et vous avez besoin d'un autre octet pour le terminateur NULL.
  4. Le MALLOC n'alloit pas suffisamment de mémoire - vous avez besoin de longueur de la longueur de la longueur de la longueur du chemin2 + de la longueur du séparateur + Null Terminator.

4 commentaires

Merci. Les commentaires du code sont juste pour une explication. Je ne l'ai pas sur le vrai code. Mais avec // Style Style, je suis capable de compiler mon programme sur un compilateur C. 2. Je n'ai pas eu ce point. Pourquoi devrait-il être défini au début de la fonction? Encore une fois ce code compile sans aucun avertissement.


Les deux premiers points sont corrects, en ce que ANSI C prend uniquement en charge les commentaires à l'aide de / * * / paires et déclarations variables en haut de la portée. Mais de nombreux compilateurs modernes violent ces deux pour faciliter la programmation. C'est-à-dire qu'ils acceptent les commentaires // et réorganiseront automatiquement les déclarations variables lors de la compilation.


Les commentaires C ++ et les déclarations mélangées sont valables C99.


@jdmichal euh, un peu. Par "compilateurs modernes violer", vous voulez dire "compilateurs modernes adhérons au moins C99". Utilisation de -ansi appliquera les normes ISO C89 ou ISO C90, qui exerceront des commentaires de style C ++.



2
votes
  1. La seule fois que vous utilisez last_char est dans la comparaison pour vérifier si le dernier caractère est un séparateur.

    Pourquoi ne pas le remplacer par ceci: xxx

    Si vous souhaitez rendre compte de la possibilité de plusieurs séparateurs de caractères, vous pouvez utiliser ce qui suit. Mais assurez-vous que lors de l'allocation de la chaîne combinée pour ajouter SHLEN (Directory_Separator) au lieu de 1. xxx

    1. La méthode Moins d'erreur d'erreur serait d'avoir l'utilisateur de vous donner le tampon de destination et sa longueur, autant de la manière Strcpy fonctionne. Cela indique clairement qu'ils doivent gérer alloué et libérer la mémoire.

    2. Le processus semble assez décent. Je pense qu'il y a juste des détails qui peuvent être travaillés, principalement avec faire des choses de manière cluntée. Mais vous allez bien, en ce que vous pouvez déjà reconnaître que cela se passe et demander de l'aide.


6 commentaires

Merci. Si l'appelant fournit le tampon, comment il sait combien d'allouer? Bien entendu, l'appelant sait sur les deux chemins mais pas le séparateur de répertoires. Donc, je me demande, ce sera un bon choix? Toutes les autres suggestions sont excellentes. Très appréciée.


@Appu: à Unix, max_path_len est une taille de mémoire tampon raisonnable.


De même, Windows a un max_path, soit 260 caractères.


Si je fais répertoire_separator a char au lieu de char * , comment l'utiliser dans strcat ?


J'ai mis à jour le message avec le dernier code. S'il vous plaît jetez un coup d'oeil à nouveau.


Vous pouvez utiliser strncat , qui prend le nombre d'éléments à ajouter. Il suffit de lui donner & annuaire_separator d'une longueur de 1.



5
votes

Et il y a une fuite de mémoire: xxx

edit: Votre nouveau code semble mieux. Quelques changements stylistiques mineurs:

  • double semi-côon ;; dans la ligne 4.
  • dans la ligne 6, remplacez strallen (chemin2) == 0 avec chemin2 [0] == '\ 0' ' ou juste > chemin2 [0 ] .
  • De même dans la ligne 9.
  • Supprimer la vérification de la boucle last_char et utiliser const charer_char = chemin1 [SHLEN (PATH1) - 1];
  • Changement if (append_directory_separator) à si (last_char! = Directory_Separator [0]) . Et donc vous n'avez pas besoin de la variable append_directory_separator plus.
  • Demandez à votre fonction renvoyer également la destination , similaire à Strcpy (dst, src) , qui retourne dst . . .

    éditer : et votre boucle pour last_char a un bug : il renvoie toujours la fin de path1 < / Code>, et vous pourriez donc vous retrouver avec une double slash // dans votre réponse. (Mais UNIX traitera cela comme une seule barre oblique, à moins que ce soit au début). Quoi qu'il en soit, ma suggestion corrige cela - ce que je vois est assez similaire à la réponse de Jdmichal. et je vois que vous avez eu raison dans votre code original (que j'avoue que je n'ai que jeté seulement à - c'était trop compliqué à mon goût; votre nouveau code est bien meilleur ).

    et deux autres, légèrement plus subjectifs, opinions:

    • J'utiliserais stpcpy () , pour éviter l'inefficacité de strcat () . (Facile à écrire le vôtre, si besoin est.)
    • Certaines personnes ont des opinions très fortes sur strcat () et similaire comme étant dangereux . Cependant, je pense que votre usage ici est parfaitement bien.

5 commentaires

Bon point. J'étais au courant des fuites. Mais la catastrophe était nouvelle pour moi. Pouvez-vous s'il vous plaît expliquer comment cela fera problème?


@Appu: gratuit (deux) est identique que gratuit ("bar") . Ce qui peut ne pas être une catastrophe . Mais il est indéfini.


Puisque vous vous raccourci et renvoyez chemin1 ou chemin2 Si l'autre paramètre est vide, il est inconnu de l'utilisateur s'il devrait libérer la valeur renvoyée ou non. Bonne prise.


J'ai mis à jour le message avec le dernier code. S'il vous plaît jetez un coup d'oeil à nouveau.


Merci d'avoir répondu. J'ai résolu le problème et j'ai appris beaucoup de choses. Merci encore.



1
votes

C'est ce que j'utilise: xxx


0 commentaires

0
votes

Juste une petite remarque afin d'améliorer votre fonction:

Windows prend en charge les deux '/' et '\\' séparateurs dans les chemins. Donc, je devrais pouvoir effectuer l'appel suivant: xxx

une idée lors de la rédaction d'un projet multiplateforme pourrait être de convertir '\\' à < Code> '/' Dans n'importe quel chemin d'entrée (à partir de l'entrée de l'utilisateur, des fichiers chargés ...), vous n'aurez donc à traiter que '/' caractères. < p> Cordialement.


0 commentaires

1
votes

Peut-être que je suis un peu en retard à cela, mais j'ai amélioré le code mis à jour d'une manière que cela fonctionne également avec quelque chose comme ça "/../".

/*
 * Combine two paths into one. Note that the function
 * will write to the specified buffer, which has to
 * be allocated beforehand.
 *
 * @dst: The buffer to write to
 * @pth1: Part one of the path
 * @pth2: Part two of the path
*/
void joinpath(char *dst, const char *pth1, const char *pth2)
{
    if(pth1 == NULL && pth2 == NULL) {
        strcpy(dst, "");
    }
    else if(pth2 == NULL || strlen(pth2) == 0) {
        strcpy(dst, pth1);
    }
    else if(pth1 == NULL || strlen(pth1) == 0) {
        strcpy(dst, pth2);
    } 
    else {
        char directory_separator[] = "/";
#ifdef WIN32
        directory_separator[0] = '\\';
#endif
        const char *last_char = pth1;
        while(*last_char != '\0')
            last_char++;        
        int append_directory_separator = 0;
        if(strcmp(last_char, directory_separator) != 0) {
            append_directory_separator = 1;
        }
        strcpy(dst, pth1);
        if(append_directory_separator)
            strcat(dst, directory_separator);
        strcat(dst, pth2);
    }

    char *rm, *fn;
    int l;
    while((rm = strstr (dst, "/../")) != NULL) {
        for(fn = (rm - 1); fn >= dst; fn--) {
            if(*fn == '/') {
                l = strlen(rm + 4);
                memcpy(fn + 1, rm + 4, l);
                *(fn + len + 1) = 0;
                break;
            }
        }
    }
}


1 commentaires

Ajouté l'extrait.