[C] - skuteczne czyszczenie dwuwym. tablicy dynamicznej char


(Musialowski Tomasz) #1

Witam!

Mam wielki problem ze skutecznym wyczyszczeniem tablicy char**. Otóż mam do napisania shell z obsługą potoków. Aby to zrobić, dzielę linię ze standardowego wejścia na komendy i zapisuję każdą z nich do dynamicznej tablicy commands aby mieć do nich dostęp przy obsłudze potoków. Problem pojawia się przy kolejnych wywołaniach wiersza poleceń. Pierwsze zawsze wykonuje mi się poprawnie więc podejrzewam, że wina leży po stronie złego resetowania tablicy commands.

Np. po wpisaniu:

ls -l | grep *-

jest wszystko ok. Jeśli jednak potem wpiszę:

ls -l | grep -

to jakoś dziwnie do pierwszego polecenia dodaje "-".

Już powoli tracę na to siły. Byćmoże popełniam jakiś kardynalny błąd i tego nie widzę. Czy ktoś mógłby mi wskazać rozwiązanie lub ewentualnie inny sposób na podzielenie poleceń względem znaku "|" potoku i zapisanie go do tablicy char? Z góry szczere dziękuję.

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 


void shellcmd(int cmd_num);


char line[BUFSIZ];

char command[BUFSIZ];

char** commands;


int main(void)

{

    int i;

	int cmd_index, cmd_num, last;

    /*

     * Forever...

     */

    for (;;) {

        printf("Enter a command: ");


		//wyczyści bufor linii

		memset(line, 0, BUFSIZ * sizeof(char));


		//jeżeli nic nie wpisano to po prostu przejdź do nowej linii

        if (fgets(line, sizeof(line), stdin) == NULL) {

            putchar('\n');

            exit(0);

        }

        line[strlen(line)-1] = '\0';

		//policzy ile jest komend

		cmd_num = 1;

		for (i = 0; i < strlen(line); i++)

		{

			if (line[i] == '|')

				cmd_num++;

		}


		//zaalokowanie pamięci potrzebnej do przechowania cmd_num komend

		commands = (char**)malloc(cmd_num * sizeof(char*));

		for (i = 0; i < cmd_num; i++) {

			commands[i] = (char*)malloc(BUFSIZ * sizeof(char));

		}


		//podział linii na komendy oddzielone znakiem "|"

		//spacje po "|" są pomijane


		//wyzerowanie cmd_index

		cmd_index = 0;


		//wyzerowanie last

		last = 0;


		//przejdź po całej linii

		for (i = 0; i < strlen(line); i++)

		{

			//jeżeli to już ostatni znak w linii

			if (i == strlen(line) - 1)

			{


				command[i - last] = line[i];

				strcpy(commands[cmd_index], command);

				memset(command, 0, BUFSIZ * sizeof(char));

			}

			if (line[i] == '|')

			{

				strcpy(commands[cmd_index], command);

				memset(command, 0, BUFSIZ * sizeof(char));

				cmd_index++;

				//jeżeli jest spacja po "|"

				//to przejdź do następnego znaku

				if (line[i+1] == ' ')

					i++;

				last = i;

				last++;

			}

			else

			{

				command[i - last] = line[i];

			}

		}

		//usuwanie spacji z końców komend

		for (i = 0; i < cmd_num; i++)

		{

			if (commands[i][strlen(commands[i])-1] == ' ')

				commands[i][strlen(commands[i])-1] = '\0';

			printf("Command: '%s'\n", commands[i]);

		}

		//wywołanie komend w potoku

        shellcmd(cmd_num);


		//zwolnienie pamięci dla tablicy commands

		for (i=0; i
		{

			memset(commands[i], 0, BUFSIZ * sizeof(char));

			free(commands[i]);

		}

		free(commands);

    }

}

void shellcmd(int cmd_num)

{

    int status, i;

    pid_t pid;

    extern int errno;

	int old_fd[2];

	int new_fd[2];


	for (i = 0; i < cmd_num; i++)

	{

		//jeżeli jest następna komenda

		if (i < cmd_num - 1)

		{

			//to utwórz deskryptory dla nowego potoku

			if (pipe(new_fd) != 0)

				perror("Blad podczas wczytywania deskryptorow potokow");

		}

		if ((pid = fork()) < 0)

			status = -1;

		if (pid == 0) /* child */

		{

			//jeżeli była wcześniejsza komenda

			if (i > 0)

			{

				dup2(old_fd[0], 0);

				close(old_fd[0]);

				close(old_fd[1]);

			}

			//jeżeli jest następna komenda

			if (i < cmd_num - 1)

			{

				close(new_fd[0]);

				dup2(new_fd[1], 1);

				close(new_fd[1]);

			}

			//system(commands[i]);

			execlp("/bin/sh", "sh", "-c", commands[i], 0);

			//execl("/bin/sh", "sh", "-c", , 0);

		}

		else /* parent */

		{

			//jeżeli była wcześniejsza komenda

			if (i > 0)

			{

				close(old_fd[0]);

				close(old_fd[1]);

			}

			if (i < cmd_num - 1)

			{

				old_fd[0] = new_fd[0];

				old_fd[1] = new_fd[1];

			}

			while (waitpid(pid, &status, 0) < 0) {

				if (errno != EINTR) {

					status = -1;

					break;

				}

			}

		}

	}

	if (cmd_num > 1)

	{

		close(old_fd[0]);

		close(old_fd[1]);

	}

}

(Blapiter) #2

Pozmieniałem trochę i działa już dobrze, do dzielenia wykorzystuje "strtok" :

#include 

    #include 

    #include 

    #include 

    #include 

    #include 

    #include 

    #include 


    void shellcmd(int cmd_num);


// START z WIKI troche przerobione //


	void rtrim(char *str)

	{

	  char *ptr;

	  int len;


	  len = strlen(str);

	  for (ptr = str + len - 1; ptr >= str && isspace((int)*ptr ); --ptr);


	  ptr[1] = '\0';

	}


	void ltrim(char *str)

	{

	  char *ptr;

	  int len;


	  for (ptr = str; *ptr && isspace((int)*ptr); ++ptr);


	  len = strlen(ptr);

	  memmove(str, ptr, len + 1);

	}


	void trim(char *str)

	{

	  rtrim(str);

	  ltrim(str);

	}


// END z WIKI troche przerobione //


    char line[BUFSIZ];

    char * command;// tu tylko pointer

    char** commands;


    int main(void)

    {

        int i;

       int cmd_index, cmd_num, last;


        for (;;) {

            printf("Enter a command: ");          


          memset(line, 0, BUFSIZ * sizeof(char));



            if (fgets(line, sizeof(line), stdin) == NULL) {

                putchar('\n');

                exit(0);

            }

            line[strlen(line)-1] = '\0';


          cmd_num = 1;

          for (i = 0; i < strlen(line); i++)

          {

             if (line[i] == '|')

                cmd_num++;

          }



          commands = (char**)malloc(cmd_num * sizeof(char*));

          for (i = 0; i < cmd_num; i++) {

             commands[i] = (char*)malloc(BUFSIZ * sizeof(char));

          }


		// START zamast poprzedniego dzielenia po '|' //


          cmd_index = 0;


          command = strtok (line,"|");

          while (command != NULL)

          {

            strcpy(commands[cmd_index], command);

            trim(commands[cmd_index]);


            command = strtok (NULL, "|");

            cmd_index++;

          }


          for (i = 0; i < cmd_num; i++)

          {

             printf("Command: '%s'\n", commands[i]);

          }


		// END zamast poprzedniego dzielenia po '|' //



           shellcmd(cmd_num);


          for (i=0; i
          {

             memset(commands[i], 0, BUFSIZ * sizeof(char));

             free(commands[i]);

          }

          free(commands);

        }

    }

    void shellcmd(int cmd_num)

    {

        int status, i;

        pid_t pid;

        extern int errno;

       int old_fd[2];

       int new_fd[2];


       for (i = 0; i < cmd_num; i++)

       {

          //jeżeli jest następna komenda

          if (i < cmd_num - 1)

          {

             //to utwórz deskryptory dla nowego potoku

             if (pipe(new_fd) != 0)

                perror("Blad podczas wczytywania deskryptorow potokow");

          }

          if ((pid = fork()) < 0)

             status = -1;

          if (pid == 0) /* child */

          {

             //jeżeli była wcześniejsza komenda

             if (i > 0)

             {

                dup2(old_fd[0], 0);

                close(old_fd[0]);

                close(old_fd[1]);

             }

             //jeżeli jest następna komenda

             if (i < cmd_num - 1)

             {

                close(new_fd[0]);

                dup2(new_fd[1], 1);

                close(new_fd[1]);

             }

             //system(commands[i]);

             execlp("/bin/sh", "sh", "-c", commands[i], 0);

             //execl("/bin/sh", "sh", "-c", , 0);

          }

          else /* parent */

          {

             //jeżeli była wcześniejsza komenda

             if (i > 0)

             {

                close(old_fd[0]);

                close(old_fd[1]);

             }

             if (i < cmd_num - 1)

             {

                old_fd[0] = new_fd[0];

                old_fd[1] = new_fd[1];

             }

             while (waitpid(pid, &status, 0) < 0) {

                if (errno != EINTR) {

                   status = -1;

                   break;

                }

             }

          }

       }

       if (cmd_num > 1)

       {

          close(old_fd[0]);

          close(old_fd[1]);

       }

    }