C sprintf вызывает ошибку сегментации

Я пытаюсь передать аргументы в родительский файл, который должен создать дочерний процесс для каждой пары аргументов. Дочерние процессы суммируют каждую пару и возвращают свою сумму родительскому процессу. Если передано нечетное количество аргументов, я добавляю 0 в конец массива argv, чтобы сделать его четным. Это происходит до тех пор, пока все аргументы не будут сложены и их сумма не будет напечатана в конце.

Все работает нормально, за исключением случаев, когда я передаю четное количество аргументов. Дочерний процесс успешно добавит первые два аргумента и вернет их, но затем, когда родитель выполнит sprintf (строка 58), всегда будет segmentation fault.

Вот код как для родительского, так и для дочернего процессов (я использую pastebin, поэтому здесь он не выглядит очень загроможденным. Срок их действия истечет через один день, поэтому я могу повторно опубликовать их, если это необходимо):

Второй файл должен называться worker при компиляции, чтобы его мог запустить первый файл. Я использую gcc на Ubuntu 9.10

Вот несколько примеров того, как запустить программу:

gcc -o parent parent.c
gcc -o worker worker.c
./parent 1 2 3 4

(Приведенный выше пример заканчивается на segmentation fault, как я объяснил выше). Ответ должен быть 10, потому что (1 + 2) + (3 + 4) = 10.

Этот ниже будет работать нормально, хотя с нечетным количеством переданных аргументов:

./parent 1 2 3

Ответ на этот должен быть 6.

Любая помощь будет принята с благодарностью!


person Dave    schedule 04.03.2010    source источник
comment
У вас ошибка. Ошибка не в sprintf.   -  person Greg Hewgill    schedule 04.03.2010
comment
Это больше, чем ошибка; это непонимание того, как все работает. Программа, кажется, пытается делать именно то, что он хочет, и в этом проблема :-)   -  person Pointy    schedule 04.03.2010
comment
@Alok: я только что сделал ссылки кликабельными (чего не мог сделать ОП, так как у него был только 1 представитель), так что, надеюсь, это облегчит вам жизнь.   -  person Chris Jester-Young    schedule 04.03.2010
comment
Спасибо за помощь. Когда я впервые начал делать эту программу, из любопытства я попытался добавить в художественный лоток, и, похоже, это сработало. Вот почему я попытался пойти дальше, но теперь я понимаю, что мне не следует изменять argv и argc.   -  person Dave    schedule 04.03.2010


Ответы (3)


Стандарт C позволяет изменять строки, на которые указывает argv:

Параметры argc и argv и строки, на которые указывает массив argv, должны изменяться программой и сохранять свои последние сохраненные значения между запуском программы и завершением программы.

Но это не гарантирует, что вы запишите доступное количество аргументов в argv, что вы и делаете, когда сохраняете сумму в конце argv.

Кажется, вы используете argv[i] для char * переменных. Почему бы просто не объявить отдельные переменные для хранения суммы? Вам также не нужно хранить "0" в argv[argc-1], если количество суммируемых чисел нечетное, вы можете легко определить это в своем цикле и передать "0" последнему рабочему процессу.

person Alok Singhal    schedule 04.03.2010
comment
Спасибо, это имеет большой смысл! - person Dave; 04.03.2010

Перезапись списка аргументов — это в лучшем случае серьезное искажение, а в худшем — гарантированная ошибка. Это то, что вы делаете в своем вызове sprintf - первый аргумент, который вы передаете, является одной из строк, переданных в main(). Зачем ты это делаешь?

[править] Я вижу, у вас даже есть комментарий на этот счет. Ну, я не знаю, что, по вашему мнению, должно произойти, когда вы это сделаете; если вы объясните свои мысли, то кто-нибудь сможет объяснить, где вы запутались. Вы не можете добавлять новые данные в массив "argv". Это не имеет никакого смысла. Это то, что выделяется системой при запуске вашего процесса, и вы должны в основном обращаться с ним как с доступом только для чтения (если вы действительно не знаете, что делаете).

person Pointy    schedule 04.03.2010
comment
Спасибо за ваш ответ. Итак, я должен скопировать все новые суммы в отдельный целочисленный массив? Я думал, что могу просто продолжать цикл for, добавляя все новые суммы в конце и увеличивая argc - person Dave; 04.03.2010
comment
Может быть, это доморощенный setproctitle! :-П - person Chris Jester-Young; 04.03.2010
comment
@ Дэйв, что, по-твоему, произойдет, когда ты добавишь строки в список аргументов? Другими словами, какова цель? С чего ты взял, что это хорошая идея? (Я не высмеиваю вас; я пытаюсь докопаться до сути того, чего вы пытаетесь достичь.) - person Pointy; 04.03.2010
comment
Я хотел, чтобы цикл продолжался, просто добавляя все новые суммы в массив argv. Другими словами, я думал, что это будет просто, потому что мне не нужно будет преобразовывать целые числа, возвращаемые дочерним процессом, в строки, а затем добавлять их в новый массив символов. - person Dave; 04.03.2010

        argc++;
        sprintf(argv[argc-1],"%d",tmp);

здесь вы выходите за границы массива. Кстати, какой смысл писать в argv?

person Andrey    schedule 04.03.2010
comment
Здравствуйте, код, который вы написали, — это то, что я использую для добавления значений в массив argv. - person Dave; 04.03.2010
comment
Прелесть C в том, что это просто память. Массив argv не является массивом, как в PHP или javascript, где вы можете динамически добавлять элементы, и он понимает. Все, что делает оператор [], — это доступ к части памяти по заданному смещению. Поскольку размер массива фиксирован, вы пытаетесь получить доступ к части памяти вне его контроля. Это может вызвать любое странное поведение (от segfault до просто странных гейзенбагов). Короче не делай этого!! :) - person jdizzle; 04.03.2010