2015-05-07 3 views
1

Это первый раз, когда я столкнулся с ошибкой сегментации 11 в C, и я, похоже, не склоняю голову о том, что на самом деле происходит неправильно.Ошибка сегментации 11 строка печати из структуры

Что я пытаюсь сделать, это написать несколько значений int для структуры плюс имя файла из командной строки (char *) из дочернего процесса, а затем записать структуру в трубу для чтения из родительского обработать. Он отлично работает, когда это только целые числа, и я вынимаю код, работающий со строкой, но как только я добавляю в строку и пытаюсь распечатать имя файла в родительском процессе, я получаю ошибку сегментации 11 при запуске программы.

Я просмотрел различные сообщения со всех сторон, но заметил, что общая проблема заключается в том, что кто-то пытается назначить строку массиву символов и печатает, но я обязательно использовал только char * здесь. Вот код, где он блокирует

if((read(pd[0], &pv, 2048)) == -1) 
{ 
    error_exit("read not working"); 
} 

printf("words = %d\n", pv.words); 
printf("lines = %d\n", pv.lines); 
printf("bytes = %d\n", pv.bytes); 
printf("file = %s\n", pv.file); //locks up here and gives segmentation fault 11 on the command line 

Вот прочитанный из того, что делает программа, когда я запускаю его:

$ ./a testfile 
Parent process... should be waiting on child... 
In child process! pid = 21993 
it worked? testfile 
Done with child process! 
words = 1 
lines = 2 
bytes = 3 
Segmentation fault: 11 

Также здесь полный код EDIT: Я выгружена код используя sizeof для струн и использованные strlen

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <string.h> 
#include <errno.h> 

void error_exit(char *); 

typedef struct total { 

    int words, lines, bytes; 
    char *file; 

} Vals; 

int main(int argc, char *argv[]) 
{ 

    int pd[2]; //pipe descriptor 
    pid_t pid; 
    Vals v, pv; 
    char *fname = "Not set"; 

    if(argc > 1) 
    { 
    fname = malloc(strlen(argv[1])); 
    strcpy(fname, argv[1]); 
    } 

    if((pipe(pd)) == -1) 
    { 
    error_exit("pipe creation"); 
    } 

    if((pid = fork()) == -1) 
    { 
    error_exit("the fork forked up!"); 
    } 
    else if(pid == 0) 
    { 

    printf("In child process! pid = %d\n", getpid()); 
    v.words = 1; 
    v.lines = 2; 
    v.bytes = 3; 
    v.file = malloc(strlen(fname)); 
    strcpy(v.file, fname); 
    printf("it worked? %s\n", v.file); 

    close(pd[0]); 

    if((write(pd[1], &v, sizeof(v.words) + sizeof(v.lines) + sizeof(v.bytes) + strlen(v.file))) == -1) 
    { 
     error_exit("Write from child"); 
    } 

    //return; //return from child 
    printf("Done with child process!\n"); 
    close(pd[1]); 
    return 0; 
    } 
    else 
    { 
    printf("Parent process... should be waiting on child...\n"); 
    } 
    //wait for child 
    while((pid = wait(NULL)) > 0); 

    close(pd[1]); 

    //Vals pv = {0, 0, 0, "pv.file not set"}; 

    //just assign anything to file to see if it fixes 
    //pv.file = malloc(strlen(fname)); 

    if((read(pd[0], &pv, 2048)) == -1) 
    { 
    error_exit("read not working"); 
    } 

    printf("words = %d\n", pv.words); 
    printf("lines = %d\n", pv.lines); 
    printf("bytes = %d\n", pv.bytes); 
    printf("file = %s\n", pv.file); //locks up here and gives segmentation fault 11 on the command line 

    close(pd[0]); 

    //program ended normally 
    return 0; 

} 

void error_exit(char *err) 
{ 
    printf("exiting because of this section: %s\nerrno = %d", err, errno); 
    exit(1); 
} 

Я очень благодарен за понимание!

+0

Я думаю, что вы хотите 'strlen (v.file)' вместо 'sizeof (v.file)'. – fvu

+0

О да, это делает жизнь намного проще :) Я изменил это на протяжении всего кода, но все равно получаю ошибку сегментации. Я заметил, что перед родительским чтением из канала, если я делаю pv.file = malloc (strlen (fname)); то он не даст мне ошибку сегментации, но печатает пустую строку. –

+0

тоже, 'размерof (argv [1])', такой же проблема. И 'fname = argv [1];' вероятно, также не делает того, что вы хотите. Попробуйте 'strcpy'. – fvu

ответ

4

Основная проблема заключается в том, что вы не совсем правильно понимаете строки C. Вы не можете сделать sizeof(char_pointer). Это просто даст вам размер указателя (4 в 32-битной системе), а не размер строки, на которую указывает. Используйте strlen, чтобы получить длину строки.

Вторая связанная проблема заключается в том, что вы пишете адрес указателя, v.file, а не полное содержимое строки через трубу. Это неверно, потому что каждый процесс имеет отдельное адресное пространство и, следовательно, указатель в одном процессе недействителен в другом процессе.

Существует несколько способов устранить вашу проблему. Я дам вам самый простой (но не самый лучший).

Сначала объявите file внутри структуры как массив символов, а не указатель на символ. Это существенно дает вам буфер фиксированного размера.

#define MAX_FILENAME_LEN 64 
typedef struct total { 
    int words, lines, bytes; 
    char file[MAX_FILENAME_LEN]; 
} Vals; 

Затем удалите вызов malloc. Вам это больше не нужно, поскольку file уже является буфером, в который вы можете копировать.

Наконец, убедитесь, что вы не переполнения буфера во время копирования строки:

if (strlen(fname) >= MAX_FILENAME_LEN) { 
    error_exit("File name too long"); 
} 
strcpy(v.file, fname); 

Вы также не нужно +1 в write как sizeof дает вам полный размер буфера.

Я оставлю это упражнение для использования динамической памяти для имени файла в структуре. Это не сложно, но вам потребуется немного изменить логику чтения и записи, так как вам нужно будет читать/писать имя файла отдельно (потому что запись всей структуры в этом случае будет просто писать указатель, а не содержимое).

+0

Привет, спасибо вы за ответ! Это определенно сделал трюк. Я знал, что до этого я должен был почистить струны C. Я действительно ценю их объяснения! Это очень помогло! –

1

Здесь несколько вещей не так.Во-первых, вы не free() в пространстве, которое вы выделяете, с malloc().

Во-вторых, вы должны использовать strlen() вместо sizeof() в своих расчетах. Это происходит дважды в коде.

В-третьих, декларация char fname = "Not set"; небезопасна, поскольку на самом деле это const char* для постоянной памяти (текстовый сегмент), и позже она указывает на что-то, выделенное через malloc(). Не делай этого.

Исправленный Листинг


#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <string.h> 
#include <errno.h> 

#define MAX_BUF_LEN (1024) 

void error_exit(char *); 

typedef struct total { 

    int words, lines, bytes; 
    char file[MAX_BUF_LEN]; 

} Vals; 

int main(int argc, char *argv[]) 
{ 
    int pd[2]; //pipe descriptor 
    pid_t pid; 
    Vals v, pv; 
    char fname[MAX_BUF_LEN] = "Not set"; 

    if(argc > 1) { 
     //fname = malloc(sizeof(argv[1]) + 1); 
     //fname = argv[1]; 
     strcpy(fname, argv[1]); 
    } 

    if((pipe(pd)) == -1) { 
     error_exit("pipe creation"); 
    } 

    if((pid = fork()) == -1) { 
     error_exit("the fork forked up!"); 
    } else if(pid == 0) { 
     printf("In child process! pid = %d\n", getpid()); 
     v.words = 1; 
     v.lines = 2; 
     v.bytes = 3; 
     //v.file = malloc(strlen(fname) + 1); 
     strcpy(v.file, fname); 
     printf("it worked? %s\n", v.file); 
     close(pd[0]); 

     if((write(pd[1], &v, sizeof(v.words) + sizeof(v.lines) + sizeof(v.bytes) + sizeof(v.file) + 1)) == -1) { 
      error_exit("Write from child"); 
     } 

     printf("Done with child process!\n"); 
     close(pd[1]); 
     return 0; //return from child 
    } 
    else 
    { 
     printf("Parent process... should be waiting on child...\n"); 
    } 
    //wait for child 
    while((pid = wait(NULL)) > 0); 

    close(pd[1]); 

    if((read(pd[0], &pv, 2048)) == -1) { 
     error_exit("read not working"); 
    } 

    printf("words = %d\n", pv.words); 
    printf("lines = %d\n", pv.lines); 
    printf("bytes = %d\n", pv.bytes); 
    printf("file = %s\n", pv.file); //locks up here and gives segmentation fault 11 on the command line 

    close(pd[0]); 

    //program ended normally 
    return 0; 

} 

void error_exit(char *err) 
{ 
    printf("exiting because of this section: %s\nerrno = %d", err, errno); 
    exit(1); 
} 

Образец Run


Parent process... should be waiting on child... 
In child process! pid = 7410 
it worked? HelloWorld 
Done with child process! 
words = 1 
lines = 2 
bytes = 3 
file = HelloWorld 
+1

Эй, большое спасибо! Объяснение действительно помогло! Я знал, что у меня что-то не хватает о строках C. Я не использовал malloc в то время и забыл основы о функции. Мне придется снова прочитать их. –

+0

@FrankA. Нет проблем. Кроме того, прочитайте, почему 'strncpy' лучше, чем' strcpy', и почему вы, вероятно, не хотите использовать даже 'strncpy', и вместо этого используйте' strlcpy', если это возможно. Если вы спросите меня, я могу рассказать вам об этом в автономном режиме. https://randomascii.wordpress.com/2013/04/03/stop-using-strncpy-already/ – DevNull

0

Этот код имеет несколько вопросов, которые по каким-то причинам не были упомянуты. Отсюда и мой прием.

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <string.h> 
#include <errno.h> 

Ну, НКУ -Wall -Wextra говорит мне:

предупреждение: неявная декларация функции «ожидания»

Как вы компиляции это? Вы видели эту ошибку и проигнорировали ее? Если да, то никаких конфет в течение недели.

void error_exit(char *); 

typedef struct total { 

    int words, lines, bytes; 
    char *file; 

} Vals; 

Странные названия. 'Всего'? 'Vals'?

int main(int argc, char *argv[]) 
{ 

    int pd[2]; //pipe descriptor 

Весьма бесполезный комментарий.

pid_t pid; 
    Vals v, pv; 
    char *fname = "Not set"; 

    if(argc > 1) 

Если проверить ARGC == 2 и бросать оскорбления, если> 2.

{ 
    fname = malloc(strlen(argv[1])); 
    strcpy(fname, argv[1]); 

Неправильные. strlen возвращает длину без завершающего нулевого символа. Вместо этого рассмотрите возможность использования strdup (нестандартного). Отсутствует проверка NULL.

} 

    if((pipe(pd)) == -1) 
    { 
    error_exit("pipe creation"); 
    } 

    if((pid = fork()) == -1) 
    { 
    error_exit("the fork forked up!"); 
    } 
    else if(pid == 0) 
    { 

    printf("In child process! pid = %d\n", getpid()); 
    v.words = 1; 
    v.lines = 2; 
    v.bytes = 3; 
    v.file = malloc(strlen(fname)); 
    strcpy(v.file, fname); 
    printf("it worked? %s\n", v.file); 

    close(pd[0]); 

Обычно вы закрываете ранее.

if((write(pd[1], &v, sizeof(v.words) + sizeof(v.lines) + sizeof(v.bytes) + strlen(v.file))) == -1) 
    { 
     error_exit("Write from child"); 
    } 

Этот код это не работает, но вы можете захотеть использовать «файл обугленного [BIGNUM];» упомянутый в других комментариях, поэтому давайте украдим образец, который должен был работать:

if((write(pd[1], &v, sizeof(v.words) + sizeof(v.lines) + sizeof(v.bytes) + sizeof(v.file) + 1)) == -1) { 
     error_exit("Write from child"); 
    } 

Неверный. Предположим, что это добавляет до размера структуры - тогда найденный здесь «+1» вызывает чтение 1 байт после структуры. Но размеры всех структурных элементов не гарантируются, чтобы добавить к размеру всей структуры из-за заполнения. Если используется 'char file [BIGNUM];' просто sizeof (v). Если вы играете с символом char *, вы должны убедиться, что файл всегда последний, и для простоты просто используйте offsetof для указателя файла.

//return; //return from child 
    printf("Done with child process!\n"); 
    close(pd[1]); 
    return 0; 

Неверный. Вместо этого следует использовать _Exit (2).

} 
    else 
    { 
    printf("Parent process... should be waiting on child...\n"); 
    } 

Что случилось с предложением else, которое только что-то печатает и выполняет выполнение ниже?

//wait for child 
    while((pid = wait(NULL)) > 0); 

Неверный. ожидание может вернуться из-за сигнала.

close(pd[1]); 

Необходимо закрыть перед отсрочкой.

//Vals pv = {0, 0, 0, "pv.file not set"}; 

    //just assign anything to file to see if it fixes 
    //pv.file = malloc(strlen(fname)); 

    if((read(pd[0], &pv, 2048)) == -1) 
    { 
    error_exit("read not working"); 
    } 

У pv нет 2048 байт, так что это может случиться, только случайно.

printf("words = %d\n", pv.words); 
    printf("lines = %d\n", pv.lines); 
    printf("bytes = %d\n", pv.bytes); 
    printf("file = %s\n", pv.file); //locks up here and gives segmentation fault 11 on the command line 

    close(pd[0]); 

    //program ended normally 
    return 0; 

} 

void error_exit(char *err) 
{ 
    printf("exiting because of this section: %s\nerrno = %d", err, errno); 
    exit(1); 
} 

Рассмотрите возможность использования функций perror или err-family (не переносных).

Наконец, я рекомендую найти менее жестокий стиль (от linux или KNF).

Смежные вопросы