簡體   English   中英

C:退出函數時丟失字符串

[英]C: Losing strings when exiting functions

我正在嘗試實現一個基本的shell,其中有幾個處理字符串的函數,試圖查找文件名,實現與*argv[]等效的東西,等等。

我在main()有字符串,這些字符串傳遞給要填充的函數。 接下來,程序返回到main() ,它將字符串傳遞給要執行的另一個函數。

我正在使用lldb進行調試,發現我已在第一個函數中成功使用正確的值填充了字符串,但是退出函數后,重新輸入main() output_str字符串再次為NULL 我以為字符串,因為它們指向內存中的空間將保留值。 在下面的代碼中,當flag = 1時,它們似乎只適用於一種情況。

我無法弄清楚發生了什么,因為這些值似乎僅在函數的最后}之后丟失。

編輯以添加完整的代碼,希望它不會太大。

當我嘗試將輸出從stdout重定向到文件時,該代碼適用於cat input.txt但不適用於cat input.txt>output.txt 。謝謝您的幫助。

這是功能.c文件:

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

這是功能.h文件:

#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

下面是main.c,在其中調用了函數。

#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;
}
        output_str = realloc (output_str, (count + 1) * sizeof (char *) );

這行代碼重新分配了本地參數變量output_str的值,但是新值決不會將其返回給string_breakdown函數的調用者-這意味着它所擁有的指針可能會懸空,並且在使用(“未定義行為”,表現為奇怪的程序行為或崩潰)。

您需要了解,在函數內, output_str是局部變量。 您可以更改其值,但這不會影響調用方中任何變量的值。

您從main調用函數:

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

main還使用output_str作為變量名,但是同樣,這是一個不同的變量。 一個變量在main本地,另一個變量在string_breakdown本地,即使它們共享相同的名稱。 由於上面的realloc調用, mainoutput_str的指針值很可能在從string_breakdown返回時無效,因為它不會更新為指向新分配的內存。 這就是為什么你從函數返回“丟失”的字符串值 -該output_str變量main不再實際上指向字符串數組,對已經通過移動到不同的位置realloc

通常,您可以通過添加另一個間接級別,將output_str參數從char **更改為char ***來解決此類問題:

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

       (*output_str)[count] = temp;

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

等等。 您還需要在main調整通話:

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

因為您要傳遞指向 mainoutput_str變量的指針 ,所以被調用函數現在可以修改其值。

您還應該了解string_breakdown會修改line參數指向的字符串。 那是因為它使用strtok ,並且strtok在處理字符串時將分隔符替換為nul個字節。 所以,奇怪的是,你通過這個修改行緩沖區com_exec與處理之后string_breakdown

嘗試編譯您的代碼時,我會收到一些警告; main.c使用fprintf但不#include <stdio.h> ,並使用malloc但不#include <stdlib.h>

您的重新分配不執行任何操作。

你的意思是*output_ptr = realloc....

它確實在做某事,但是真的很糟糕

這也是錯誤的

output_str[count] = temp;

和這個

filename = output_str[1];

您需要區分-指向緩沖區的指針,指向緩沖區的指針。

  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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM