2013-10-09 5 views
0

Клянусь, я действительно приличный программист, но мои приключения в программировании на C после программирования на Java в течение многих лет сводят меня с ума.Проблемы с двумерным char массивом

Я пытаюсь заполнить двухмерный массив символов набором пар IP-адресов/портов. Я читаю их из файла. Они извлекаются из файла правильно и должны быть правильно помещены в массив. Проблема в том, что по какой-то причине, когда второй набор помещается в массив, он переписывает первый набор, и я не могу, чтобы жизнь меня определяла, почему.

Первая строка файла - это количество пар IP-адресов/портов в файле (я называю их кортежами). Следующие строки представляют собой IP-адреса и порты, разделенные пробелом.

Вот код:

//read the top line with the number of items 
    fgets(line, sizeof line, fp); 
    numLines = atoi(line); 
    printf("%s %d\n","numLines:",numLines); 
    char* tuples[numLines][2]; 
    char* rawLines[numLines]; 
    //read each line and put it into array 
    for(currentLine=0; currentLine<numLines; currentLine++){ 
    if(fgets(line, sizeof line, fp) == NULL){ 
     perror("fgets"); 
     return -1; 
    } 
    printf("%s %d \n","curentLine: ",currentLine); 
    char* port; 
    tuples[currentLine][0] = strtok(line, " "); 
    printf("%s %s \n", "IP Address: ", tuples[currentLine][0]); 
    //rawLines[currentLine] = line; 
    port = strtok(NULL, " "); 
    size_t ln = strlen(port) - 1; 
    if (port[ln] == '\n') 
     port[ln] = '\0'; 
    tuples[currentLine][1]=port; 
    printf("%s %s\n","port: ", tuples[currentLine][1]); 
    } 
    //list created and stored in tuples 
    //now that list is created choose a random server from the file and strip the value chosen from the list 

    //choose random server 
    srand (time(NULL)); 
    //randomServer = rand()%numLines; 
    randomServer = 0; 
    printf("%s %d\n", "randomServer: ", randomServer); 



    //connect to random server pulled 
    memset(&hints, 0, sizeof hints); // make sure the struct is empty 
    hints.ai_family = AF_UNSPEC;  // don't care IPv4 or IPv6 
    hints.ai_socktype = SOCK_STREAM; // TCP stream sockets 
    hints.ai_flags = AI_PASSIVE;  // fill in my IP for me 
    //setup client socket 
    printf("%s %s \n", "Setting up connection to: ", tuples[randomeServer][0]); 
    printf("%s %s \n", "Setting up connection on port: ", tuples[randomServer][1]); 

Вот результат я получаю:

numLines: 2 
curentLine: 0 
IP Address: 127.0.0.1 
port: 3761 
curentLine: 1 
IP Address: 192.168.0.1 
port: 3762 
randomServer: 0 
Setting up connection to: 192.168.0.1 
Setting up connection on port: 1 

Что я ожидаю получить это: Настройка подключения к: 127.0.0.1 Настройка подключения на порт: 3761

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

Заранее спасибо.

+1

Кажется типичным симптомом назначения указателя на массив, содержимое которого впоследствии изменяется. Кроме того: 1. ** спасибо ** за использование 'fgets()' вместо мозгового мертвого 'scanf()' (который по какой-то причине всем нравится (ab) использовать), 2. но почему 'printf ("% s% d \ n", "numLines:", numLines); '? Более читаемой версией будет 'printf (" numLines:% d \ n ", numLines);'. Кроме того, 'strtol()' является предпочтительным для 'atoi()'. –

+0

Не должно быть 'sizeof (line)'? – John

+0

@ Джон Нет, почему? 'line' - это объект, а не тип. –

ответ

2

Вместо прямого назначения strtok возврата к вашему двумерный массив, скопировать содержимое с strcpy:

char *ipAddress = strtok(line, " "); 
char *tuple0 = malloc(sizeof(char) * (strlen(ipAddress) + 1)); 
strcpy(tuple0, ipAddress); 
tuples[currentLine][0] = tuple0; 
+1

Пара отмечает об этом: вызов malloc требует +1 для нулевого терминатора. Если вы 'strcpy'" abc ", то нужны 4 байта. Во-вторых, 'strcat' не нужен. strcpy уже null завершает результат (и если это не так, то 'strcat' не будет работать, потому что для начала требуется цель с нулевым завершением :). –

+0

@MarkWilkins ты прав. Исправлена. – Mauren

0

Проблема заключается в том, что вы не правильно копировать данные. У вас есть переменная с именем line, которая представляет собой массив из char, и вы используете fgets() для чтения каждой строки ввода в эту переменную. Затем вы токенизируете ввод, и для каждого токена вы храните указатель в массив line на место в массиве tuples, но эти данные будут перезаписаны, как только вы прочтете следующую строку. То, что вам действительно нужно делать, это выделить новую часть хранилища, скопировать данные в нее и сохранить указатель на это новое хранилище в массив tuples.

0

Похоже, вы не выделили память для ваших «сохраненных» строк. Ваши объявления:

char* tuples[numLines][2]; 
char* rawLines[numLines]; 

объявляет массивы указателей на символ. Не «струны». Так что вам не хватает что-то вроде:

tuples[index_value][0] = malloc(number_of_characters); 

И тогда вы должны написать строки, которые вы прочитали в этой памяти либо с зЬгсром или strncpy.

sizeof(char) is always one

+1

'sizeof (char)' всегда один. –

0

Стоит помнить, что нет 2D массивов в С. 2D массива абстрактное понятие, которое может быть реализовано в С (по меньшей мере) два различных бетонными конструкциями. Существуют массивы массивов, и есть массивы указателей.

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

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