2010-04-16 3 views
3

Я пишу код C для класса. Этот класс требует, чтобы наш код компилировался и запускался на школьном сервере, который является машиной с солярием. Я запускаю Linux x64.Strcpy() повреждает скопированную строку в Solaris, но не Linux

У меня есть эта линия для синтаксического анализа (ЭТО НЕ АКТУАЛЬНО КОД, НО ВХОД В моей программе):

while (cond1){ 

мне нужно, чтобы захватить «а» и «COND1» на отдельные строки. Я использовал strtok() для этого. В Linux, следующие строки:

char *cond = NULL; 
cond = (char *)malloc(sizeof(char)); 
memset(cond, 0, sizeof(char)); 
strcpy(cond, strtok(NULL, ": \t\(){")); //already got the "while" out of the line 

правильно захватить строку «COND1» .Running это на Солярис машине, однако, дает мне строку «cone1».

Обратите внимание, что во многих других случаях в моей программе строки копируются правильно. (Например, «while») было зафиксировано правильно.

Кто-нибудь знает, что здесь происходит?

ответ

11

Линия:

cond = (char *)malloc(sizeof(char)); 

выделяет ровно один char для хранения, в которую вы затем копирование более одного - strcpy потребности поставить на минимум, для нулевой терминатор, но в вашем случае, также результаты вашего strtok.

Причина, по которой она может работать в другой системе, заключается в том, что некоторые реализации malloc будут выделяться с определенным разрешением (например, кратным 16 байтам) независимо от того, какое фактическое значение вы запрашиваете, поэтому у вас может быть свободное место там в конце вашего буфера. Но то, что вы пытаетесь, по-прежнему остается очень неопределенным поведением.

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

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

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

Нечто подобное (если instr ваша оригинальная входная строка):

cond = (char*)malloc(strlen(instr)+1); 

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

В качестве альтернативы sizeof(char) всегда по определению, поэтому вам не нужно его умножать.

+0

Сделайте что-то вроде 'char * token = strtok (NULL," stuff ");' затем выделите свой новый буфер как 'cond = (char *) malloc (strlen (токен) +1);' then 'strcpy (cond , токен); 'Вы сохраняете некоторую память в зависимости от того, как долго сохраняются эти жетоны, и если входная строка оказывается монстром. – John

+0

Проблема в том, что вы выполняете разделение и освобождение для каждого отдельного токена вместо каждой строки ввода (скорее всего, строки). Я подозреваю, что удар производительности за это перевешивает любой выигрыш в меньшей используемой памяти, если только линии не будут действительно огромными. Но это субъективная вещь и зависит от ваших потребностей, поэтому я не буду спорить слишком много. – paxdiablo

+0

Напиши свой собственный strdup! –

1

Вы выделили память только для 1 символа, но вы пытаетесь сохранить не менее 6 символов (вам нужно место для завершения \ 0).Быстрый и грязный способ решить это просто сказать

обугленного конд [128]

вместо таНос.

2

cond выделяется один байт. strcpy копирует по крайней мере два байта в это выделение. То есть вы пишете больше байтов в распределение, чем есть место.

Один из способов исправить это, чтобы использовать char *cond = malloc (1000); вместо того, что у вас есть.

+0

Хороший звонок. Неужели просто удача, что другие строки, которые намного длиннее этого, копируются правильно? –

+0

@ strictrude27: Да, чистое совпадение. –