2016-03-22 12 views
-1

Ich versuche, eine grundlegende Shell zu implementieren, habe ich mehrere Funktionen innerhalb, die mit Zeichenfolgen zu tun haben, versuchen, Dateinamen zu finden, implementieren Sie etwas Entsprechendes zu *argv[] und so weiter.C: Strings verlieren beim Beenden von Funktionen

Ich habe Zeichenfolgen in main(), die an eine Funktion übergeben werden, um ausgefüllt werden. Als nächstes kehrt das Programm zu main() zurück, das die Zeichenfolgen an eine andere Funktion weiterleitet, die bearbeitet werden soll.

I wurde Debuggen mit lldb und festgestellt, daß ich erfolgreich die Saiten mit den richtigen Werten in der ersten Funktion Bevöl wurde aber die Funktion beim Verlassen, Wiedereintritt in dem main()output_str Zeichenfolge NULL wieder war. Ich dachte, dass Strings, da sie auf Speicherplatz im Speicher zeigen, Werte beibehalten würden. Sie scheinen für alle außer einem Fall, wenn Flag = 1 in dem Code unten.

Ich kann nicht herausfinden, was passiert, wie die Werte nur nach dem letzten } der Funktion verloren scheinen.

Bearbeitet, um vollständigen Code hinzuzufügen, hoffe, es ist nicht zu groß. Vielen Dank für Ihre Hilfe im Voraus

Der Code funktioniert mit etwa cat input.txt aber nicht mit cat input.txt>output.txt, wenn ich versuche die Ausgabe von stdout in eine Datei zu umleiten. Hier

ist die Funktion C-Datei:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 
#include <time.h> 
#include <sys/wait.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <signal.h> 

void sig_handler(int signo) 
{ 
     if (signo == SIGINT) 
     { 
       fprintf(stdout, "\n"); 
       fflush(stdout); 
     } 
} 
int check_redirect(char *line, int flag) 
{ 
     int n = 0; 
     if (line == NULL) return (flag); 
     else 
     { 
       do 
       { 
         if (line[n] == '>') flag = 1; 
         n++; 
       }while (line[n] != '\0'); 
     } 

     return (flag); 
} 

void string_breakdown(char *line, char **output_str, int count, char* temp, char *filename, int *f, int *saved_stdout, int flag, int debug) 
{ 
     char *sep = " \n"; 
     char *delim = ">\n"; 

     if (line != NULL) 
     { 
       temp = strtok(line, delim); 
       while (temp != NULL) 
       { 
         output_str[count] = temp; 

         if (debug) fprintf(stderr, "1:%s\n2:%s\n3:%s\n", line, temp, output_str[count]); 

         count++; 
         output_str = realloc (output_str, (count + 1) * sizeof (char *)); 

         temp = strtok(NULL, delim); 
       } 
       if (flag) 
       { 
         count = 0; 
         strcpy(filename, output_str[1]); 
         output_str[1] = NULL; 

         *saved_stdout = dup(1); 

         *f = open(filename , O_WRONLY|O_CREAT|O_TRUNC, 0666); 

         dup2(*f, 1); 

         temp = strtok(*output_str[0], sep); 
         while (temp != NULL) 
         { 
           output_str[count] = temp; 

           //if (debug) fprintf(stderr, "1:%s\n2:%s\n3:%s\n", line, temp, output_str[count]); 

           count++; 
           output_str = realloc (output_str, (count + 1) * sizeof (char *)); 

           temp = strtok(NULL, sep); 
         } 
       } 

       else 
       { 
         count = 0; 
         temp = strtok(line, sep); 
         while (temp != NULL) 
         { 
           output_str[count] = temp; 

           if (debug) fprintf(stderr, "1:%s\n2:%s\n3:%s\n", line, temp, output_str[count]); 

           count++; 
           output_str = realloc (output_str, (count + 1) * sizeof (char *)); 

           temp = strtok(NULL, sep); 
         } 
       } 
     } 
} 

void com_exec(char *line, char **output_str, char *filename, int *f, int *saved_stdout, int flag, int debug) 
{ 
     char *command = malloc(sizeof(char *)); 
     command = output_str[0]; 
     char *name = "HOME"; 
     int ret_val = 0; 
     pid_t child_pid; 
     int child_status; 
     if (command == NULL); 
     else if (strcmp("cd", command) == 0) 
     { 
       if (output_str[1] == NULL) output_str[1] = getenv(name); 

       ret_val = 0; 
       ret_val = chdir(output_str[1]); 
       if (ret_val) perror(NULL); 
     } 

     else 
     { 
       child_pid = fork(); 
       if (child_pid == 0) 
       { 
         if (debug) 
         { 
           system(line); 
           fprintf(stderr, "Post System Pre Exec\n1:%s\n2:%s\n3:%s\n", line, output_str[0], command); 
           sleep(2); 
         } 

         execvp(command, output_str); 

         if (flag) 
         { 
           close(*f); 

           dup2(*saved_stdout, 1); 
           close(*saved_stdout); 

         } 

         fprintf (stdout, "Unknown command\n"); 
         exit (0); 
       } 

       else 
       { 
         if (flag) 
         { 
           close(*f); 

           dup2(*saved_stdout, 1); 
           close(*saved_stdout); 
         } 

         signal(SIGINT, sig_handler); 

         usleep(500000); 

         //Parent process waits for child to finish 
         if (debug) fprintf (stderr, "parent waiting\n"); 

         wait(&child_status); 
         waitpid(child_pid, &child_status, 0); 

         signal(SIGINT, SIG_DFL); 
       } 
     } 

Hier die Funktionen H-Datei:

#ifndef SHELL_H_INCLUDED 
#define SHELL_H_INCLUDED 

void sig_handler(int signo); 

int prompt(char *line, size_t len, ssize_t read); 

int check_redirect(char *line, int flag); 

void string_breakdown(char *line, char **output_str, int count, char* temp, char *filename, int *f, int *saved_stdout, int flag, int debug); 

void com_exec(char *line, char **output_str, char *filename, int *f, int *saved_stdout, int flag, int debug); 

#endif // LINKLAYER_H_INCLUDED 

Im Folgenden finden Sie main.c, wo die Funktion aufgerufen wird.

#include <unistd.h> 
#include <time.h> 
#include <sys/wait.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <signal.h> 

#include "shell.h" 

int main(void) 
{ 
     int debug = 0; 

     char *line = NULL; 
     size_t len = 0; 
     ssize_t read = 0; 

     int flag = 0; 

     int f = 0; 
     int saved_stdout = 0; 

     do 
     { 
       flag = 0; 

       //read = prompt(line, len, read); 
       char buffer[15]; 
       time_t now = time(NULL); 
       strftime(buffer, 15, "[%d/%m %H:%M]", localtime(&now)); 

       fprintf(stdout, "%s # ", buffer); 

       signal(SIGINT, SIG_IGN); 
       read = getline (&line, &len, stdin); 
       signal(SIGINT, SIG_DFL); 

       flag = check_redirect(line, flag); 

       char **output_str = malloc(sizeof(char *)); 
       int count = 0; 
       char* temp = NULL; 
       char *filename = malloc(sizeof(char *)); 

       string_breakdown(line, output_str, count, temp, filename, &f, &saved_stdout, flag, debug); // function call of problem function 

       com_exec(line, output_str, filename, &f, &saved_stdout, flag, debug); 
     } while (read != EOF); 

     if (debug) fprintf(stderr, "parent exiting\n"); 
     else fprintf(stdout, "\n"); 

     return 0; 
} 
+0

welche Zeichenfolge in dieser Funktion? Senden Sie uns den aufrufenden Code zu – pm100

+0

Während Sie deklarieren, dass die Zeichenfolgen lokal für die Funktion ** string_breakdown() ** sind, müssten Sie entweder __ * delim__ oder __ * sep__ abhängig davon, was main() benötigt, zurückgeben und den Wert ändern Rückgabetyp dieser Funktion zu __char * __ –

+0

@ pm100 Ich fügte den Funktionsaufruf Code – BitFlow

Antwort

2
 output_str = realloc (output_str, (count + 1) * sizeof (char *)); 

Diese Linie des Wert den die lokalen Parameter Variable output_str-re zuweist, aber der neue Wert in keine Weise macht es zurück an den Aufrufer der string_breakdown Funktion - was bedeutet, dass der Zeiger es hat wird wahrscheinlich hängen bleiben und wird bei der Verwendung Probleme verursachen ("undefiniertes Verhalten", das sich in einem seltsamen Programmverhalten manifestiert oder abstürzt).

Sie müssen wissen, dass innerhalb der Funktion output_str eine lokale Variable ist. Sie können den Wert ändern, aber das hat keine Auswirkungen auf den Wert einer Variablen im Aufrufer.

Sie rufen die Funktion von main:

   string_breakdown(line, output_str, count, temp, filename, &f, &saved_stdout, flag, debug); // The call of the above function 

main auch output_str als Variablennamen verwendet, aber auch dies ist ein verschiedene variabel. Eine Variable ist lokal main, die andere ist lokal string_breakdown, obwohl sie den gleichen Namen haben. Aufgrund des obigen Aufrufs realloc wird der Zeigerwert in main 's output_str sehr wahrscheinlich bei der Rückkehr von string_breakdown ungültig sein, da es nicht aktualisiert wird, um auf den neu zugewiesenen Speicher zu zeigen. Deshalb "verlieren" Sie die Zeichenfolgenwerte bei der Rückkehr von der Funktion - die output_str Variable in main zeigt nicht mehr wirklich auf das Array von Zeichenfolgen, das über realloc an einen anderen Speicherort verschoben wurde.

Typischerweise Sie diese Art von Problem zu lösen, indem ein anderes Dereferenzierungsebene Hinzufügen, Ändern der output_str Parameter von einem char ** zu einem char ***:

void string_breakdown(char *line, char ***output_str, int count, char* temp, char *filename, int *f, int *saved_stdout, int flag, int debug) 

und

 (*output_str)[count] = temp; 

und

 *output_str = realloc (*output_str, (count + 1) * sizeof (char *)); 

und so weiter. Sie müssen den Anruf in main auch anpassen:

   string_breakdown(line, &output_str, count, temp, filename, &f, &saved_stdout, flag, debug); // The call of the above function 

Weil Sie vorbei einen Zeiger-main ‚s output_str Variable, die aufgerufene Funktion nun in der Lage ist, seinen Wert zu ändern.

Sie sollten auch verstehen, dass string_breakdown wie geschrieben die Zeichenfolge ändert, auf die der line-Parameter verweist. Das liegt daran, dass strtok verwendet wird und strtok Delimiter mit Nul Bytes ersetzt, wenn die Zeichenfolge verarbeitet wird. Es ist also seltsam, dass Sie diesen modifizierten Zeilenpuffer an com_exec übergeben, nachdem Sie ihn mit string_breakdown verarbeitet haben.

Ich bekomme mehrere Warnungen, wenn ich versuche, Ihren Code zu kompilieren; main.c verwendet fprintf, aber nicht #include <stdio.h>, und verwendet malloc, aber nicht #include <stdlib.h>.

+0

Ich habe den obigen Code bearbeitet, um Ihren Vorschlag wiederzugeben, aber nur Segmentierungsfehler Wenn 'flag = 1 ', dann erzeugen alle Prozesse Segmentierungsfehler. Ich fügte die zusätzlichen Dereferenzierung '*' s hinzu und übergab die Adresse. Ich bin mir nicht sicher, ob meine Bearbeitung sichtbar ist. Kannst du sehen, ob es mit dem übereinstimmt, was du gesagt hast, da mein Code momentan weniger funktional ist? – BitFlow

+0

@BitFlow Sie sollten jetzt die Frage nicht bearbeiten, um dieser Antwort zu entsprechen, da Sie nun eine _different_ Frage stellen und diese Antwort nicht mehr auf sie zutrifft. Ich bin zuversichtlich, dass meine Änderungen hier Verbesserungen sind. Wenn Sie immer noch Fehler bei der Segmentierung haben, kann es sein, dass Sie andere Probleme in Ihrem Code haben. Sie sollten versuchen, meine Antwort zu verstehen oder Fragen zu stellen, bis Sie es tun, und dann eine zweite Frage stellen, um weitere Probleme zu lösen (nachdem Sie zuerst versucht haben, sich selbst zu debuggen). – davmac

+0

@BitFlow BTW es wäre viel einfacher zu helfen, wenn Sie eine [MCVE] zur Verfügung stellen. Ich kann den von Ihnen geposteten Code nicht kompilieren und testen, da er nicht vollständig ist. – davmac

0

Ihr Realloc tut nichts.

meinen Sie *output_ptr = realloc....

es tatsächlich etwas tut, aber es ist wirklich schlecht

dies ist auch falsch

output_str[count] = temp; 

und diese

filename = output_str[1]; 

Sie unterscheiden müssen - ein Zeiger auf Ihren Puffer, ein Zeiger auf den Zeiger zu Ihrem Puffer.

char * buffer = *output_str; // to remove the confusion 
    strcpy(&buffer[count], temp); // assigning pointers doesnt copy things 


filename = buffer[1]; // is hat what you mean - filename is one char 
+0

Kann ich fragen, wie sich * output_str unterscheidet? – BitFlow

+0

* output_ptr = sagt - speichern Sie diesen Zeiger, wo output_ptr zeigt. output_ptr = sagt diesen Zeiger überschreiben. Gehe lesen auf Zeiger und Indirektion – pm100

+0

Ich implementierte die '* output_str = realloc ...' ändern und die Dinge tatsächlich schlechter geworden, jetzt Befehle sind alle nicht erkannt – BitFlow