简体   繁体   English

C:退出函数时丢失字符串

[英]C: Losing strings when exiting functions

I'm trying to implement a basic shell, I have several functions within it that deal with strings, trying to find file names, implement something equivalent to *argv[] and so on. 我正在尝试实现一个基本的shell,其中有几个处理字符串的函数,试图查找文件名,实现与*argv[]等效的东西,等等。

I have strings in main() , which are passed to a function to be populated. 我在main()有字符串,这些字符串传递给要填充的函数。 Next the program returns to main() , which passes the strings to another function to be acted upon. 接下来,程序返回到main() ,它将字符串传递给要执行的另一个函数。

I was debugging with lldb and found that I was successfully populating the strings with the correct values in the first function but upon exiting the function, re-entering main() the output_str string was NULL again. 我正在使用lldb进行调试,发现我已在第一个函数中成功使用正确的值填充了字符串,但是退出函数后,重新输入main() output_str字符串再次为NULL I thought strings, since they point to space in memory would retain values. 我以为字符串,因为它们指向内存中的空间将保留值。 They seem to for all but one case, when flag = 1 in the code below. 在下面的代码中,当flag = 1时,它们似乎只适用于一种情况。

I can't figure out what's happening as the values seem to only be lost after the final } of the function. 我无法弄清楚发生了什么,因为这些值似乎仅在函数的最后}之后丢失。

Edited to add complete code, hope it isn't too large. 编辑以添加完整的代码,希望它不会太大。

The code works with say, cat input.txt but not with cat input.txt>output.txt when I try to redirect the output from stdout to a file Thank you for your help in advance. 当我尝试将输出从stdout重定向到文件时,该代码适用于cat input.txt但不适用于cat input.txt>output.txt 。谢谢您的帮助。

Here is the function .c file: 这是功能.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);
                }
        }

Here is the functions .h file: 这是功能.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

Below is main.c, where the function is called. 下面是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 *) );

This line re-assigns the value of the the local parameter variable output_str , but the new value in no way makes it back to the caller of the string_breakdown function - meaning that the pointer it has will probably be left dangling, and will cause problems when used ("undefined behavior", manifesting in strange program behavior or crashing). 这行代码重新分配了本地参数变量output_str的值,但是新值决不会将其返回给string_breakdown函数的调用者-这意味着它所拥有的指针可能会悬空,并且在使用(“未定义行为”,表现为奇怪的程序行为或崩溃)。

You need to understand that within the function, output_str is a local variable. 您需要了解,在函数内, output_str是局部变量。 You can change its value, but that won't affect the value of any variable in the caller. 您可以更改其值,但这不会影响调用方中任何变量的值。

You call the function from main : 您从main调用函数:

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

main also uses output_str as the variable name, but again, this is a different variable. main还使用output_str作为变量名,但是同样,这是一个不同的变量。 One variable is local to main , the other is local to string_breakdown , even though they share the same name. 一个变量在main本地,另一个变量在string_breakdown本地,即使它们共享相同的名称。 Due to the realloc call above, the pointer value in main 's output_str will most likely be invalid on return from string_breakdown , because it is not updated to point to the newly allocated memory. 由于上面的realloc调用, mainoutput_str的指针值很可能在从string_breakdown返回时无效,因为它不会更新为指向新分配的内存。 That's why you are "losing" the string values on return from the function - the output_str variable in main is no longer actually pointing to the array of strings, which has been moved to a different location via realloc . 这就是为什么你从函数返回“丢失”的字符串值 -该output_str变量main不再实际上指向字符串数组,对已经通过移动到不同的位置realloc

Typically you resolve this kind of problem by adding another level of indirection, changing the output_str parameter from a char ** to a char *** : 通常,您可以通过添加另一个间接级别,将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)

and

       (*output_str)[count] = temp;

and

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

and so on. 等等。 You need to adjust the call in main as well: 您还需要在main调整通话:

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

Because you are passing a pointer to main 's output_str variable, the called function is now able to modify its value. 因为您要传递指向 mainoutput_str变量的指针 ,所以被调用函数现在可以修改其值。

You should also understand that string_breakdown as written modifies the string which the line parameter points to. 您还应该了解string_breakdown会修改line参数指向的字符串。 That's because it uses strtok , and strtok replaces delimiters with nul bytes as it processes the string. 那是因为它使用strtok ,并且strtok在处理字符串时将分隔符替换为nul个字节。 So, it is odd that you pass this modified line buffer to com_exec after processing it with string_breakdown . 所以,奇怪的是,你通过这个修改行缓冲区com_exec与处理之后string_breakdown

I get several warnings when I try to compile your code; 尝试编译您的代码时,我会收到一些警告; main.c uses fprintf but doesn't #include <stdio.h> , and uses malloc but doesn't #include <stdlib.h> . main.c使用fprintf但不#include <stdio.h> ,并使用malloc但不#include <stdlib.h>

your realloc does nothing. 您的重新分配不执行任何操作。

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

actually it does something, but its really bad 它确实在做某事,但是真的很糟糕

this is also wrong 这也是错误的

output_str[count] = temp;

and this 和这个

filename = output_str[1];

you need to distinguish - a pointer to your buffer, a pointer to the pointer to your buffer. 您需要区分-指向缓冲区的指针,指向缓冲区的指针。

  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