2013-10-05 2 views
2

Я пытаюсь написать программу, которая принимает несколько аргументов во время выполнения, чтобы добавить текст в файл.Как скопировать содержимое argv [] в строку стиля c?

Программа производит ошибку сегментации во время выполнения. Вот код:

int main(int argc, char* argv[]) 
{ 
    //error checking 
    if (argc < 1 || argc > 4) { 
     cout << "Usage: -c(optional - clear file contents) <Filename>, message to write" << endl; 
     exit(EXIT_FAILURE); 
    } 

    char* filename[64]; 
    char* message[256]; 

    //set variables to command arguments depending if -c option is specificed 
    if (argc == 4) { 
     strcpy(*filename, argv[2]); 
     strcpy(*message, argv[3]); 
    } else { 
     strcpy(*filename, argv[1]); 
     strcpy(*message, argv[2]); 
    } 

    int fd; //file descriptor 

    fd = open(*filename, O_RDWR | O_CREAT, 00000); //open file if it doesn't exist then create one 
    fchmod(fd, 00000); 

    return 0; 
} 

Я все еще довольно новичок, и у меня возникли проблемы с пониманием строк. В чем разница между char * и char [] и char * []?

UPDATE:

Код по-прежнему бросает ошибку сегментации, вот мой пересмотренный код:

using std::cout; 
using std::endl; 

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

//error checking 
if (argc < 1 || argc > 4) { 
cout << "Usage: -c(optional - clear file contents) <Filename>, message to write"  << endl; 
exit(EXIT_FAILURE); 
} 

char filename[64]; 
char message[256]; 

//set variables to command arguments depending if -c option is specificed 
if (argc == 4) 
{ 
strncpy(filename, argv[2], 64); 
strncpy(message, argv[3], 256); 
} 
else 
{ 
strncpy(filename, argv[1], 64); 
strncpy(message, argv[2], 256); 
} 

int fd; //file descriptor 

fd = open(filename, O_RDWR | O_CREAT, 00000); //open file if it doesn't exist then create one 
fchmod(fd, 00000); 


return 0; 

} 
+0

Вы получаете очки для обеспечения полной попытки программы; много, чтобы учиться, но вы были близки. – ChuckCottrill

ответ

6

char* filename[64] создает массив из 64 указателей. Вы намерены создать пространство для строки с 64 символами - это будет char filename[64]. Поскольку вы выделили место для указателей и не указали указатели на какую-либо память, вы получите ошибку seg.

Решение: использовать char filename[64];

Это создает блок из 64 байт для вашей строки; значение filename указывает на начало этого блока и может быть использован в операции копирования

strcpy(filename, argv[2]); 

Я бы настоятельно рекомендовал не с помощью «COPY не более п символов» функция - это предотвращает действительно длинный аргумент от вызывающего буфера переполнение. Таким образом,

strncpy(filename, argv[2], 64); 

будет безопаснее. Еще лучше

strncpy(filename, argv[2], 63); 
filename[63] = '\0'; 

Это гарантирует, что скопированная строка имеет нулевое завершение.

У вас такая же проблема с message. Я не думаю, что вам нужен код, повторяющийся ...

Дайте мне знать, если вам нужна дополнительная информация.

UPDATE
Сегодня я узнал о существовании strlcpy - см this answer. Он позаботится о включении ограничителя строки NUL, даже если исходная строка была длиннее выделенного пространства.См. this для более полного обсуждения, включая причины, по которым эта функция недоступна для всех компиляторов (что, конечно же, является серьезным недостатком, если вы пытаетесь написать переносимый код).

+0

Отличный ответ! Я понимаю. Каким будет выход * filename? Это все немного запутанно, поскольку синтаксис для состояний strcpy (char * dest, char * src), поэтому я предполагаю, что так вы объявляете строки c. – Scholar

+0

«Вывод имени файла»?Символьная строка (блок памяти, на которую указывает указатель 'filename', будет содержать символы, на которые указывал' argv [2] ', вплоть до и заканчивающийся' '\ 0''. Синтаксис' strcpy 'is' strcpy (char * dest, const char * source); 'который не совсем то, что вы только что написали ... См. например, http://www.cplusplus.com/reference/cstring/strcpy/ – Floris

+1

Что касается" как вы объявляете строки C "- строка C ссылается на _pointer_ на _block memory_ (что вам нужно, чтобы убедиться, что выделено и достаточно большое), _terminated с символом' '\ 0'' (для которого вы также требуется пространство). Существуют разные методы выделения пространства: 'имя_файла [64]' одно (примечание - это достаточно большое для 63-символьной строки _plus завершающее '' \ 0''_) или 'const char myString = "hello world"; 'если вы не собираетесь его изменять (выделена память для вас), или вы начинаете с' char myString; 'и следуете с помощью 'myString = malloc (100);' для создания пространства. – Floris

2

Ваши переменные filename и message являются charуказатель массивы, а не строки C-типа (которые должно быть завершено нулем char массивов). Таким образом, вы должны объявить их тип как:

char filename[64]; 
char message[256]; 

и использовать strcpy как:

strcpy(filename, argv[2]); 
strcpy(message, argv[3]); 

вызов open похож:

fd = open(filename, O_RDWR | O_CREAT, 00000); 
+0

Итак, в основном у меня был массив, полный указателей, указывающих на NULL? – Scholar

+1

@Revoo У вас был полный набор ** неинициализированных ** указателей 'char'. –

2

>>> Я все еще довольно новичок, и у меня возникли проблемы с пониманием строк. В чем разница между char и char [] и char * []? *

Указатели трудно понять в первый раз, когда вы их встретите.

  • символ представляет собой один байт в памяти
  • символ * представляет собой указатель на память (может быть один байт или массив символов)
  • символ [] представляет собой массив символов, можно указать в полукокса *
  • полукокса * [] представляет собой массив указателей на символ

Если у вас есть переменная имя файла, * имя файла разыменовывает переменная, которая означает, что это не указатель, но вещь указал на ,

  • * имя файл типа полукокса, не допустимый параметр для зЬгсра, который где ваша выдаст ошибка сегментация происходит
  • * сообщение типа полукокса, а не действительного параметр для зЬгсра, который где ваша следующая выдаст ошибка сегментация будет происходить
  • открыт (* имя файл снова символ, который не является допустимым параметром для открытого

Вы в основном имели право программы. проблема была ваше отсутствием ясности относительно того, как использовать указатель. Вот ваш код , переработал немного, чтобы работать. Я прокомментировал разбитые части, чтобы вы могли сравнить сломанные n до фиксированного.

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
int 
main(int argc, char* argv[]) 
{ 
    //char* filename[64]; 
    //char* message[256]; 
    char filename[64]; //declare filename, point it at char[64] 
    char message[256]; //declare message, point it at char[256] 
    int fd; //file descriptor 

    printf("argc %d\n",argc); 
    //error checking 
    if ((argc < 1) || (argc > 4)) 
    { 
     //cout << "Usage: -c(optional - clear file contents) <Filename>, message to write" << endl; 
printf("Usage: -c(optional - clear file contents) <Filename>, message to write\n"); 
     exit(EXIT_FAILURE); 
    } 

    int argi=1; 
    if(!strcmp(argv[argi],"-c")) { argi++; } //clear 
    //set variables to command arguments depending if -c option is specificed 
    if (argc == 4) 
    { 
     //strcpy(*filename, argv[argi++]); 
     //strcpy(*message, argv[argi++]); 
     strcpy(filename, argv[argi++]); 
     strcpy(message, argv[argi++]); 
    } 
    else 
    { 
     //strcpy(*filename, argv[argi++]); 
     //strcpy(*message, argv[argi++]); 
     strcpy(filename, argv[argi++]); 
     strcpy(message, argv[argi++]); 
    } 

    //fd = open(*filename, O_RDWR | O_CREAT, 00000); //open file if it doesn't exist then create one 
    if(!(fd = open(filename, O_RDWR | O_CREAT, 00000))) //open file if it doesn't exist then create one 
    { 
     //always check for failure to open 
     //and emit error if file open fails 
     exit(EXIT_FAILURE); 
    } 
    //fchmod(fd, 00000); 
    write(fd,message,strlen(message)); 

    return 0; 
} 
+0

Очень хорошее объяснение. – Floris

+0

После изменения кода он по-прежнему выбрасывает segfault. – Scholar

+0

, когда аргументы не указаны. исправлено. – ChuckCottrill

0

Я еще совсем новичок, и у меня возникают огромные проблемы с пониманием гр строки. В чем разница между char * и char [] и char * []?

Короткий ответ на ваш явный вопрос в том, что char* и char[] оба могут быть использованы в качестве C-строк. char* [], с другой стороны, представляет собой массив C-strings.

2

Поскольку вы отметили это как C++ (и никто до сих пор не говорил об этом):

argv уже массив C-стиле, так что нет необходимости копировать его на другой (если вы просто хотите место для отходов). Если вы действительно хотите, чтобы скопировать его в чем-то, std::string объект будет лучше подход:

int main(int argc, char* argv[]) 
{ 
    // assuming your conditional checks are already done here ... 
    std::string filename = argv[1]; 
    std::string message = argv[2]; 
    // do something 
    return 0; 
} 
+0

+1 за то, что вы сделали очевидный момент: «вы на самом деле не пытаетесь копировать« argv », чтобы ваша программа работала! – Floris

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