Как сделать, чтобы символ обратной косой черты не экранировался

Я не знаю, название правильно решает мою проблему или нет. Итак, я просто пойду с ним. Вот проблема, мне нужно ввести массив символов пути к файлу (в Windows), содержащий множество обратных косых черт, например. "C:\myfile.txt" и вернуть беззнаковый массив символов путей к файлам в стиле C, например. "C:\myfile.txt".

Я попытался написать функцию.

unsigned char* parse_file_path(char *path);
{
   unsigned char p[60];
    int i,j;
    int len = strlen(path);
    for(i=0,j=0; i<len; i++, j++)
    {
        char ch = path[i];
        if(ch==27)
        {

            p[j++]='\\';
            p[j]='\\';
        }
        else
            p[j] = path[i];
    }
    p[j]='\0';
    return p;
}

Странная вещь (для меня), с которой я сталкиваюсь, заключается в том, что здесь путь содержит только одну обратную косую черту «\». Чтобы получить одну обратную косую черту, я должен поставить «\» в пути. Это невозможно, потому что путь не может содержать '\'. Когда я вызываю его вот так parse_file_path("t\es\t \it), он возвращает t←s it. Но parse_file_path("t\\es\\t \\it") возвращает t\es\t \it.

Как я могу выполнить свою задачу? Заранее спасибо.


person muntasir2000    schedule 02.07.2013    source источник
comment
Спецификация языка C гласит, что для того, чтобы получить одну обратную косую черту в литеральной строке, вы должны ее экранировать.   -  person Some programmer dude    schedule 02.07.2013
comment
Кажется, вы ожидаете, что обратная косая черта во входных данных будет экранирована фактическим экранированием (ASCII 27), что, вероятно, неверно.   -  person unwind    schedule 02.07.2013
comment
@JoachimPileborg Строка каким-то образом уже содержит несколько одиночных экранированных символов обратной косой черты. Как сделать каждую обратную косую черту двойной?   -  person muntasir2000    schedule 02.07.2013
comment
Нет, строковый литерал "t\es\t \it" не содержит обратную косую черту, потому что компилятор проверяет их во время компиляции и заменяет, например, \t в строке с табуляцией. Для несуществующих управляющих кодов (например, \i в вашей строке) компилятор выдаст предупреждение и удалит обратную косую черту. В файле есть только обратная косая черта, а не после того, как код прошел через компилятор.   -  person Some programmer dude    schedule 02.07.2013
comment
Возможный дубликат Как мне печатать escape-символы как символы?   -  person jww    schedule 22.12.2014


Ответы (1)


Если я могу просто упомянуть еще одну проблему с вашим кодом.

Вы возвращаете локальную переменную (ваш unsigned char p). Это неопределенное поведение. Рассмотрите возможность объявления char* p, которому вы назначаете память динамически, используя malloc, а затем возвращаете p, как и вы. Например. что-то типа:

char* p = malloc(60);

Обычной практикой является использование sizeof при выделении памяти с помощью malloc, но здесь я передал 60 напрямую, поскольку стандарт C гарантирует, что char будет 1 байтом на всех платформах.

Но вам нужно free память, назначенную с помощью malloc.

Или, в качестве альтернативы, вы можете изменить функцию, чтобы она принимала буфер в качестве входного аргумента, в который она затем записывает. Таким образом, вы можете передать обычный массив, в котором вы бы вызвали эту функцию.

Что касается вашей проблемы с косой чертой, здесь:

p[j++]='\\';
p[j]='\\';

Позиция j в p будет изменена на \\, затем j будет увеличена, и в самой следующей строке вы сделаете то же самое для следующей позиции char. Вы уверены, что хотите получить два задания?

Кстати, если вы вводите путь из командной строки, об экранировании позаботятся за вас. Например. рассмотрим следующий код:

#include <stdio.h>
#include <string.h> /* for strlen */
#include <stdlib.h> /* for exit */

int main() 
{
    char path[60];

    fgets(path, 60, stdin); /* get a maximum of 60 characters from the standard input and store them in path */

    path[strlen(path) - 1] = '\0'; /* replace newline character with null terminator */

    FILE* handle = fopen(path, "r");

    if (!handle)
    {
        printf("There was a problem opening the file\n");
        exit(1); /* file doesn't exist, let's quite with a status code of 1 */
    }

    printf("Should be good!\n");

    /* work with the file */

    fclose(handle);

    return 0; /* all cool */
}

Затем вы запускаете его и вводите что-то вроде:

C:\cygwin\home\myaccount\main.c

Он должен печатать «Должно быть хорошо!» (при условии, что файл существует, вы также можете проверить его с помощью «C:\»).

По крайней мере, в Windows 7 с cygwin это то, что я получаю. Нет необходимости в каких-либо побегах, так как это обрабатывается за вас.

person Nobilis    schedule 02.07.2013
comment
Может быть, вы можете добавить эти вещи в свой пост выше: Наряду с free сделайте так, чтобы p указывал на NULL, иначе это будет оборванный указатель. - person ; 02.07.2013
comment
+1, но char *p = malloc(60); достаточно, sizeof(char) гарантированно равен 1 байту - person David Ranieri; 02.07.2013
comment
@DavidRF Спасибо, я обновлю свой ответ и объясню, почему нет необходимости в sizeof, просто подумал, что это может быть немного менее запутанным, но, тем не менее, плохой привычкой :) - person Nobilis; 02.07.2013
comment
@Nobilis Извините, если я не смог ясно изложить свой вопрос. Подумайте об этом, вы вводите путь к файлу в консоли и хотите, чтобы он открылся в программе. Насколько я знаю, вам нужно изменить фактический путь, чтобы использовать его с fopen или чем-то подобным. Например, если вы введете C:\myfile.txt, то в fopen вам придется использовать C:\\myfile.txt. Как бы вы это сделали? Это именно то, что я пытаюсь сделать. Спасибо - person muntasir2000; 02.07.2013
comment
@muntasir2000 См. редактирование моего поста, это проверено в Windows 7 с помощью cygwin, я смог успешно открыть файл после передачи ему правильного пути. Нет необходимости бежать. Можете ли вы попробовать это и сообщить мне, какие результаты вы получили? - person Nobilis; 02.07.2013
comment
@Nobilis Это сработало! Большое спасибо. Я думаю, проблема была в том, что я использовал строковые литералы, а не переменные. Итак, компилятор экранировал escape-символы и доставил мне много неприятностей. Если бы я использовал переменную, этого бы не произошло. И это то, что я хочу в моей реальной программе. Итак, проблема решена. Спасибо еще раз. - person muntasir2000; 02.07.2013
comment
@muntasir2000 Пожалуйста, я рад, что это работает для вас :) - person Nobilis; 02.07.2013