[英]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
調用, main
的output_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
因為您要傳遞指向 main
的output_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.