Я пытаюсь написать ОЧЕНЬ простую программу оболочки на C. Проблема, с которой я столкнулся, заключается в попытке заполнить мой массив указателей символов argv словами, взятыми из ввода. Когда я пытаюсь распечатать содержимое массива argv после попытки заполнить его с помощью функции parse() ниже, я получаю ошибку сегментации. Я знаю, что это означает, что я, вероятно, пытаюсь получить доступ к части массива argv, которая находится за пределами границ. Однако даже при предоставлении только одного аргумента для заполнения массива я все равно получаю segfault. Вызов printf, используемый для печати argc, возвращает правильное значение argc на основе ввода, но второй вызов printf с *argv[0] вызывает ошибку segfault. Мне интересно, связана ли моя ошибка с тем, как я пытаюсь распечатать содержимое argv, или ошибка связана с тем, что я пытаюсь неправильно заполнить argv.
РЕДАКТИРОВАТЬ: я должен добавить, что функция getword() принимает строку текста и возвращает первое слово, разделенное пробелами, и ряд других разделителей. Я могу опубликовать все разделители, на которые он разбивает слова, если это необходимо, но я не думаю, что проблема связана с getword().
РЕДАКТИРОВАТЬ 2: добавлено в заголовочный файл и включено выражение #include в main.
РЕДАКТИРОВАТЬ 3: добавлена функция getword в main() и getword.h ниже p2.h
Вот p2.h, заголовочный файл, включенный в main:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "getword.h"
#include <signal.h>
#define MAXITEM 100
получитьслово.ч:
#include <stdio.h>
#include <string.h>
#include <strings.h>
#define STORAGE 255
int getword(char *w);
int parse(char *, char *[]);
Вот основная функция:
#include "p2.h"
int main() {
pid_t pid, child_pid;
int argc, inputRedirect;
char *devNull;
devNull = (char *) malloc(10);
strcpy(devNull, "/dev/null");
char *argv[MAXITEM];
char commandLine[STORAGE];
for (;;) {
printf("p2: ");
scanf("%s", commandLine);
argc = parse(commandLine, argv);
printf("argc = %d\n", argc);
if(argc == 0)
continue;
printf("*argv = %s\n", *argv[0]);
child_pid = fork();
if (child_pid < 0) {
printf("Cannot fork! Terminating...");
exit(1);
} else if (child_pid == 0) {
inputRedirect = open(devNull, O_RDONLY);
dup2(inputRedirect, STDIN_FILENO);
close(inputRedirect);
execvp(*argv, argv);
}
else {
for(;;) {
pid = wait(NULL);
if(pid == child_pid)
break;
}
printf("Child's pid is %d\n", child_pid);
}
}
killpg(getpid(), SIGTERM);
printf("p2 Terminated.\n");
exit(0);
}
int parse(char *commandLine, char *argv[]) {
int i, argc = 0;
char *commandPointer = commandLine;
while (*commandPointer != '\0') {
*argv = commandPointer;
argc++;
getword(commandPointer);
}
*commandPointer = '\0';
*argv = '\0';
return argc;
}
получитьслово.с:
#include "getword.h"
#include <stdlib.h>
/*Function Prototypes*/
int tilde(char *p, int i);
int BSFollowedByMetaCharacter(int c, char *w);
int getword(char *w) {
int c;
int index = 0;
/*This while loop removes all leading blanks and whitespace characters
* The if statement then tests if the first character is a new line or
* semicolon metacharacter*/
while ((c = getchar()) == ' ' || c == '\t' || c == '\n' || c == ';') {
if (c == '\n' || c == ';') {
w[index] = '\0';
return 0;
}
}
/*This if statement calls ungetc() to push whatever character was taken
* from the input stream in the previous while loop back to the input
* stream. If EOF was taken from the input stream, ungetc() will return EOF,
* which will then cause getword() to return -1, signalling that it reached
* the End Of File. */
if (ungetc(c, stdin) == EOF)
return -1;
/*This if statement deals with some of the "non-special" metacharacters.
* If one of these metacharacters is pulled from the input stream by getchar(),
* it is stored in w and null-terminated. getword() then returns the length of
* the current string stored in w. If getchar() pulls anything besides one of the
* specified metacharacters from the input stream, it is then returned using ungetc() after
* the if statement.*/
if ((c = getchar()) == '<' || c == '>' || c == '|' || c == '&') {
w[index++] = c;
int d = getchar();
if (c == '>' && d == '>')
w[index++] = d;
else {
ungetc(d, stdin);
}
w[index] = '\0';
return index;
}
ungetc(c, stdin);
/*This while statement handles plain text from the input stream, as well as a few 'special'
* metacharacters. It also ensures that the word scanned is shorter than STORAGE-1 bytes.*/
while ((c = getchar()) != ' ' && c != '<' && c != '>' && c != '|'
&& c != ';' && c != '&' && c != '\t' && c != '\n' && c != '\0'
&& index <= STORAGE - 1) {
if (c == '~') {
int *ip = &index;
index = tilde(&w[index], *ip);
continue;
}/*END IF*/
else if (c == '\\') {
int d = c;
c = getchar();
if (BSFollowedByMetaCharacter(c, w)) {
w[index++] = c;
continue;
} else {
w[index++] = d;
}
}/*END ELSE IF*/
w[index] = c;
index++;
}/*END WHILE*/
ungetc(c, stdin);/*This final ungetc() call is used to push any meta characters*/
w[index] = '\0'; /*used as delimiters back to the input stream, to be retrieved*/
return index; /*at the next call of getword(). */
}/*END getword()*/
int tilde(char *cp, int i) {
int *ip;
ip = &i;
char *p = cp;
char *o;
o = (strcpy(p, getenv("HOME")));
int offset = strlen(o);
*ip = *ip + offset;
return i;
}
int BSFollowedByMetaCharacter(int c, char *w) {
if (c == '~' || c == '<' || c == '>' || c == '|' || c == ';' || c == '&'
|| c == ' ' || c == '\t' || c == '\\') {
return 1;
} else {
return 0;
}
}
char *devNull; devNull = (char *) malloc(10); strcpy(devNull, "/dev/null");
это худшее, что вы можете сделать. Вы выделяете кучу без всякой причины, не можете освободить выделенную память, что приводит к ее утечке. Вы также возвращаете возвращаемое значениеmalloc()
, что неверно. Почему бы просто не написатьconst char *devNull = "/dev/null";
? - person   schedule 25.11.2013argv[0]
уже имеет типchar*
и не должен разыменовываться при использовании для %s` ` - person starrify   schedule 25.11.2013getenv
, поскольку оно может вернутьNULL
, если элемент не найден, тогдаstrcpy
может ничего не делать (однако я думаю, что это вызовет исключение) и оставьте строкуp
без изменений. Тогдаstrlen
может выйти из строя, так как данные поступают из неинициализированного массиваcommandLine
. - person starrify   schedule 25.11.2013*commandPointer
. Таким образом, цикл должен быть бесконечным. Кроме того, вindex = tilde(&w[index], *ip);
, почему бы не отправить толькоip
и не обработать его в функции? - person asif   schedule 25.11.2013