Проблема с печатью char * argv [n] после вызова функции в C - PullRequest
0 голосов
/ 01 декабря 2010
int readOptions(char *argv[]){
        FILE * infile;
        char line_buf[BUFSIZ];
        int i = 0, j = 0 ; 
        infile = fopen("options","r");
            if(!infile){

                     fprintf(stderr,"File Read failure\n");
                        exit(2);
            }

        while( i < 10 && fgets(line_buf,sizeof(line_buf),infile)!=0){

             printf("Line buf : %s",line_buf); 
             argv[i] =  line_buf;                                   

             i++;                               
}

}

int main(){

int j ; 

char *options[10]; 

for(j = 0 ; j< 10 ; j++){

        options[j] = malloc(len * sizeof (char));
    } 

 readOptions(options);
for(j=0; j<10 ; j++)
         printf("%s %d\n",options[j], j );

}

Проблема в том, что я всегда вижу - программа печатает только последнюю прочитанную строку в файле.Где ошибка?и мне не хватает какой-либо важной концепции указателя с этим кодом?

Ответы [ 3 ]

3 голосов
/ 01 декабря 2010

Каждый элемент argv указывает на одно и то же line_buf. Вместо этого используйте strdup() для создания новых строк (которые позже вам придется освободить).

1 голос
/ 01 декабря 2010

A char* не является строкой.Это указатель.В вашем цикле вы устанавливаете каждый char* в вашем char*[] так, чтобы он указывал на начало массива line_buf.Таким образом, каждый ссылается на одни и те же данные (которые, кроме того, больше не доступны после возврата из функции; в этот момент вы получаете неопределенное поведение, и вам просто «везет» - на самом деле очень неудачно, потому что это затрудняет диагностикупроблема в том, что кажется, что он «работает» так же, как и он.)

Существует нет реального типа строки в C. Вы должны установить отдельные фрагменты памяти, которые будут содержатьперсонажи, и указывают на эти куски.Если вы распределяете их динамически, вам также придется их освободить.Если вы хотите иметь возможность изменять их размер или вообще обрабатывать вещи неизвестного размера, это также на вас.

Вы написали код для выделения некоторого пространства, но не копируете данные впробел - вместо этого вы переопределяете указатели на локальный буфер.Как уже отмечалось, мы используем strcpy для копирования из одного буфера в другой.Но в этом нет никакого смысла, если вы собираетесь передавать выделенные буферы и в любом случае ограничивать себя их размерами;вместо этого просто fgets непосредственно в буферы, на которые указывают указатели в массиве argv, вместо локального.

0 голосов
/ 01 декабря 2010

argv[i] являются не строками сами по себе, а указателями на области памяти, которые содержат текстовые строки.Это то, что вы делаете, когда говорите options[j] = malloc(...) - вы выделяете область памяти, на которую указывает указатель.Но эта область памяти - просто область памяти, она не имеет ничего общего с указателем, за исключением того, что указатель указывает на нее.

Так что, когда вы говорите argv[i] = line_buf, этоне означает копировать саму строку.Это означает изменение указателя, так что argv[i] теперь указывает на ту же область памяти, где начинается line_buf[].Затем на следующей итерации цикла for вы перезаписываете ту же область памяти.К концу цикла все десять ваших указателей указывают на line_buf, который содержит последнюю строку вашего файла, поэтому вы получаете десять копий этой строки.

(Что также стоит отметитьявляется то, что когда readOptions () возвращает, та область памяти, на которую указывают все ваши указатели, считается неопределенной, потому что line_buf[] только «существует» в функции readOptions (). Только благодаря удаче ваша программа печатает последнюю строкудесять раз вместо печати мусора или сбоя.)

Теперь, чтобы скопировать строку из одного места в другое, вы можете использовать функцию strcpy(), которую можно добавить в вашу программу, поставив #include <string.h>на вершине.Затем вы должны написать strcpy(argv[i], line_buf).

Вот как будет выглядеть простая версия strcpy (), чтобы вы могли увидеть, что она делает:

char *strcpy(char *dest, char *source) {
    int i = 0;
    while (source[i] != '\0') {  /* a zero (or "null") byte means end of string */
        dest[i] = source[i];
        i=i+1;
    }
    dest[i] = source[i];
    return dest;
}

Обратите внимание, что strcpy ()нет никакого способа узнать, сколько места есть, чтобы скопировать в!Если у вас недостаточно свободного места, оно пройдет сразу за конец вашего пространства и покажет, кто знает, в каких областях памяти может произойти сбой вашей программы или странное поведение.Это называется переполнением буфера, и это одна из самых распространенных ошибок безопасности.Поэтому убедитесь, что у вас достаточно места перед вызовом strcpy ().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...