Линия:
a[i] = strtok(s," ");
наборы a[i]
к указателю в пределах строки, которые вы модифицирующие и которые могут в конечном итоге иметь временные NUL символов (от strtok
) удалены.
Вы можете попробовать:
a[i] = strdup (strtok (s," "));
вместо этого.
Позвольте мне подробнее пояснить. Скажем, у нас есть команда (как она существует в памяти):
ls -al xyzzy\0
Когда вы strtok
это, он почти наверняка получает изменено на:
ls\0-al xyzzy\0
^
, а затем он дает s
(обозначенный ^
) возвращается с strtok
и помещается в a[0]
. В следующий раз, через, он изменяет строку:
ls -al\0xyzzy\0
^
и дает адрес, указанный ^
и места, в a[1]
. К сожалению, a[0]
теперь указывает на строку "ls -al"
В конце концов, строка будет возвращаться в исходное состояние и ваши указатели, в то время как указывающие на право адреса, не будет иметь строки нулевым байтом, как вы ожидаете (за исключением последний).
Таким образом, вы будете в конечном итоге с:
a[0] = "ls -al xyzzy"
a[1] = "-al xyzzy"
a[2] = "xyzzy"
Используя strdup
, вы делаете копию каждой строки (в то время, когда строка, как вы ожидаете, одно слово), который затем не модифицируется последующими операциями в коде токенизации строки.
Помните, однако, чтобы освободить все те строки, которые вы выделили, когда закончите с ними.
Вы можете использовать этот код в качестве основы:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main (void) {
char str[256], *word[20];
int i, num, len;
printf ("Enter command: ");
fgets (str, sizeof (str), stdin);
num = 0;
word[num] = strtok (str, " ");
while (word[num] != NULL) {
word[num] = strdup (word[num]);
len = strlen (word[num]);
if (strlen (word[num]) > 0)
if (word[num][len-1] == '\n')
word[num][len-1] = '\0';
word[++num] = strtok (NULL, " ");
}
for (i = 0; i < num; i++) {
printf ("%d: [%s]\n", i, (word[i] == NULL) ? "<<null>>" : word[i]);
free (word[i]);
}
return 0;
}
и следующего транскрипта показывает его в действии:
Enter command: ls -al xyzzy | grep -v plugh
0: [ls]
1: [-al]
2: [xyzzy]
3: [|]
4: [grep]
5: [-v]
6: [plugh]
Кроме того, правильный способ сравнения строк C не :
if (a[0] = "cd")
, так как это сравнивает адреса ,, которые могут отличаться, даже если содержимое подложки идентично. Вместо этого вы должны использовать что-то вроде:
if (strcmp (a[0], "cd") == 0)
И одна заключительная вещь, argv[]
массив, который вы передаете execvp
должны иметь конечный указатель завершающего NULL. Это часть контракта, поэтому вам нужно будет убедиться, что он встает перед вызовом execvp
.
Научитесь использовать отладчик наподобие 'gdb'. Скомпилируйте свою программу с помощью 'gcc -Wall -g'. И очистите массив 'a [5]' (который должен быть намного больше или несколько выделенных кучей данных). Посмотрите также на исходный код небольших бесплатных программных оболочек (например, 'sash') –
Также' a [0]! = "Exit" ', вероятно, не то, что вы хотите. Используйте 'strcmp'. – cnicutar
Вам действительно нужно занять несколько часов, чтобы прочитать хорошую книгу программирования C. Затем прочитайте хорошую книгу программирования Linux, такую как http://advancedlinuxprogramming.com/; провести день или два для чтения (возможно, в библиотеке). –