Покрытие строки неизвестной длины для строчных букв - PullRequest
0 голосов
/ 27 января 2012

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

У меня есть цикл While в методе makeLower, который, кажется, проходит часть первой итерации цикла while, а затем происходит сбой EXE-файла. Любые советы будут великолепны, спасибо!

Выход:

C:\Users\Mark\Documents\Visual Studio 2010\Projects\Project 1\Debug>"Project 1.e
xe" ez.txt

Line is #draw a diamond ring

Character is #

Тогда ошибка «проект 1.exe перестал работать»

Код:

void makeLower(char *input[]){
    int i = 0;
    printf("Line is %s\n", *input);

    while(input[i] != "\0"){
        printf("Character is %c\n", *input[i]); 
        if(*input[i] >= 'A' && *input[i] <= 'Z'){
            *input[i] = tolower(*input[i]);
        }
        i++;
    }

}

int main(int argc, char *argv[]) {
    FILE *file = fopen(argv[1], "r");
    char linebyline [50], *lineStr = linebyline;
    char test;

    glutInit(&argc, argv);

    while(!feof(file) && file != NULL){
        fgets(lineStr , 100, file);
        makeLower(&lineStr);
        printf("%s",lineStr);

        //directFile();

    }
    fclose(file);


    glutMainLoop();
}

Ответы [ 4 ]

3 голосов
/ 27 января 2012

Я вижу больше проблем, поэтому я добавляю свои комментарии к ответу:

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

При передаче строки C в функцию вам не нужно передавать адрес указателя на строку (&lineStr), фактический указатель или массив в порядке. Это означает, что вы можете изменить функцию makeLower на void makeLower(char *input) или void makeLower(char input[]). Прямо сейчас аргумент makeLower объявлен как массив или указатели на символы, а не указатель на массив символов.

В новом предложенном выше makeLower, который я предложил, вы можете получить доступ к отдельным символам либо в виде массива (input[i]), либо как указатель плюс смещение (*(input + i)). Как я уже говорил в своем комментарии, последняя версия - это то, что компилятор, вероятно, создаст, если вы используете первое, но первое более читабельно, поэтому я предлагаю это.

Также в makeLower вы делаете сравнение с "\0", который является строкой, а не символом. Это почти правильно на самом деле: вы должны использовать input[i] != '\0'.

И, наконец, вот как я бы это реализовал:

void makeLower(char *input)
{
    while (*input != '\0')  /* "while (*input)" would also work */
    {
        *input = tolower(*input);
        input++;
    }
}

Несколько пояснений по поводу функции:

  • Все массивы char могут быть преобразованы в указатель char, но не наоборот. Передача указателя на символ является наиболее распространенным способом передачи строки, как вы можете видеть из всех стандартных функций, которые принимают строки (например, strlen или strcpy.)
  • Выражение *input разыменовывает (т.е. принимает значение, на которое указывает указатель) строку. Это то же самое, что и *(input + 0), и, следовательно, получить значение первого символа в строке.
  • Хотя первый символ в строке не является '\0' (что технически является нормальным нулем), мы зациклимся.
  • Получить первый символ строки и передать его в функцию tolower. Это будет работать независимо от того, какой это символ, tolower будет переводить только символы верхнего регистра в нижний регистр, все остальные символы будут возвращены, как они уже были.
  • Результат tolower скопирован по первому символу. Это работает, потому что правая часть назначения должна быть выполнена до назначения, поэтому не будет никаких ошибок или проблем.
  • Последнее мы увеличиваем указатель на единицу. Это заставит input указывать на следующий символ в строке. Это работает, потому что input является локальной переменной, поэтому операции с указателем не повлияют ни на что в вызывающей функции.

Эта функция теперь может вызываться так:

char input[100];
fgets(input, sizeof(input), stdin);
printf("before: \"%s\"\n", input);
makeLower(input);
printf("after : \"%s\"\n", input);
1 голос
/ 27 января 2012

Вы пробовали while (* input [i]! = "\ 0") вместо того, что у вас есть? По какой-то причине вы, похоже, передаете своей функции указатель на указатель на char (* input []) и & lineStr, поэтому имеет смысл дважды разыменовываться при проверке символа конца строки "\ 0" ....

Просто мысль, надеюсь, это поможет

0 голосов
/ 27 января 2012

Насколько я понимаю, нормально передавать '\ 0' в tolower(). Это допустимое значение unsigned char, и tolower() просто возвращает вводимый символ, если он не может выполнить какое-либо преобразование.

Таким образом, цикл может быть кратко обозначен как:

while(input[i] = tolower(input[i]))
  ++i;

Это делает еще один вызов tolower(), но он короче и (imo) вполне понятен. Просто хотел упомянуть это как альтернативу.

0 голосов
/ 27 января 2012

Я думаю, проблема в том, что вы не знаете, что строка будет равна '\ 0', когда вы этого захотите. Таким образом, вы можете выходить за пределы, что очень вероятно, что вы не знаете длину строки.

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