C - Почему массив символов возвращает только последнее значение, которое было в него вставлено? - PullRequest
0 голосов
/ 18 апреля 2019

Я пишу на C. Я пытаюсь прочитать строки из текстового файла, разобрать строку и поместить некоторую информацию в массив строк.Когда я проверяю свой код, каждое значение в массиве кажется последним вставленным значением.Что вызывает это?

int r;
char *users[51]; //given no more than 50 users
for (r = 0; r < 51; r++) {
    int n = 15; //arbitrary guess at length of unknown usernames
    users[r] = malloc((n + 1) * sizeof(char));
}
FILE *fp;
fp = fopen(argv[1], "r");

char *username;

int counter = 0;
char line[100];
while (fgets(line, 100, fp) != NULL) {
    username = strtok(line, ":");

    users[counter] = username;
    printf("%s\n", username);
    printf("%s\n", users[counter]);

    //counter increase for later
    counter += 1;

Ответы [ 4 ]

1 голос
/ 18 апреля 2019

strtok - очень запутанная функция:

  • она изменяет массив, на который получает указатель
  • , возвращает указатель на элемент этого массива.
  • поддерживает внутреннее состояние, что делает его не входящим и не ориентированным на многопотоковое исполнение.

Следовательно username указывает внутри line.Вы сохраняете этот указатель в users[counter].В конце цикла все записи в users указывают на один и тот же массив, который был перезаписан при каждом вызове fgets().

Вы должны продублировать содержимое массива с помощью strdup():

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[) {
    char *users[51]; //given no more than 50 users
    int r;
    FILE *fp;

    if (argc < 2) {
        fprintf(stderr, "missing filename argument\n");
        return 1;
    }
    fp = fopen(argv[1], "r");
    if (fp == NULL) {
        fprintf(stderr, "cannot open file %s\n", argv[1]);
        return 1;
    }
    char line[100];
    int counter = 0;
    while (counter < 50 && fgets(line, 100, fp) != NULL) {
        char *username = strtok(line, ":");
        if (username != NULL) {
            users[counter] = strdup(username);
            //counter increase for later
            counter += 1;
        }
    }
    users[counter] = NULL;

    ...
}
1 голос
/ 18 апреля 2019

Вы помещаете разумное значение в каждую запись в массиве:

users[r] = malloc((n+1) * sizeof(char));

Но затем вы перезаписываете его бессмысленным значением (указатель на line):

users[counter] = username;

Предположительно, вы хотели скопировать строку, указанную username, в пространство, выделенное в users[counter]. Функция strcpy может сделать это.

0 голосов
/ 18 апреля 2019

Решение, которое избегает массива указателей:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define NAMELEN  16
#define MAXUSERS 51
typedef char uarray[MAXUSERS][NAMELEN];

int main() {
    int i;
    uarray * users = malloc(sizeof(uarray));
    memset(users, 0, MAXUSERS*NAMELEN);
    strncpy((*users)[0], "Alice", NAMELEN-1);
    strncpy((*users)[1], "Bob", NAMELEN-1);

    for (i=0; i<2; i++) 
        printf("%d: %s\n", i, (*users)[i]);
    return 0;
}
0 голосов
/ 18 апреля 2019

Я просто хотел бы добавить к ответу Дэвида, что вы также должны проверить, что строка имени пользователя завершена нулем перед использованием strcpy(). Я не могу вспомнить, заканчивается ли strtok() null, но вы все равно не должны на это полагаться.

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