Strcat генерирует ошибку сегментации при простом вводе пароля по принципу getch - PullRequest
3 голосов
/ 04 ноября 2010

Я использую Linux, и есть пользовательская функция, которая возвращает ASCII int текущего ключа вроде getch(). При попытке привыкнуть к нему и как сохранить пароль у меня возникла проблема, мой код выглядит так:

int main() {
    int c;
    char pass[20] = "";

    printf("Enter password: ");
    while(c != (int)'\n') {
        c = mygetch();
        strcat(pass, (char)c);
        printf("*");
    }

    printf("\nPass: %s\n", pass);

    return 0;
}

К сожалению, я получаю предупреждение от GCC:

pass.c:26: warning: passing argument 2 of ‘strcat’ makes pointer from integer without a cast
/usr/include/string.h:136: note: expected ‘const char * __restrict__’ but argument is of type ‘char’

Я попытался использовать указатели вместо массива char для pass, но во втором случае я набираю букву segfaults. Функция работает сама по себе, но не в цикле, по крайней мере, как getch () в системе Windows.

Что вы видите не так с моим примером? Мне нравится изучать это.

РЕДАКТИРОВАТЬ: Благодаря ответам я придумал следующий глупый код:

int c;
int i = 0;
char pass[PASS_SIZE] = "";

printf("Enter password: ");
while(c != LINEFEED && strlen(pass) != (PASS_SIZE - 1)) {
    c = mygetch();
    if(c == BACKSPACE) {
        //ensure cannot backspace past prompt
        if(i != 0) {
            //simulate backspace by replacing with space
            printf("\b \b");
            //get rid of last character
            pass[i-1] = 0; i--;
        }
    } else {
        //passed a character
        pass[i] = (char)c; i++;
        printf("*");
    }
}
pass[i] = '\0';
printf("\nPass: %s\n", pass);

Ответы [ 3 ]

3 голосов
/ 04 ноября 2010

Проблема в том, что strcat ожидает char * в качестве второго аргумента (он объединяет две строки).У вас нет двух строк, у вас есть одна строка и одна char.

Если вы хотите добавить c в конец pass, просто сохраните int i, в котором хранятсятекущий размер pass, а затем выполните что-то вроде

pass[i] = (char) c.

Убедитесь, что pass завершен на ноль, когда закончите (установив последнюю позицию в 0).

1 голос
/ 04 ноября 2010

Один символ не совпадает со строкой, содержащей один символ.

Другими словами, «а» и «а» - это очень разные вещи.

Строка в C - это массив символов с нулем в конце. Ваш «проход» - это массив из 20 символов - блок памяти, содержащий место для 20 символов.

Функция mygetch () возвращает символ.

Что вам нужно сделать, это вставить c в один из пробелов.

Вместо «strcat (pass, c)» вы хотите сделать «pass [i] = c», где i начинается с нуля и увеличивается на единицу при каждом вызове mygetch ().

Затем вам нужно выполнить pass [i] = '\ 0', когда цикл завершится, где i равно числу вызовов mygetch (), чтобы добавить нулевой терминатор.

Другая проблема в том, что вы не установили значение для c, когда вы в первый раз проверяете, есть ли это \ n. Вы хотите вызвать mygetch () перед сравнением:

int i = 0;
for (;;)
{
    c = mygetch();
    if (c == '\n')
        break;

    c = mygetch();
    pass[i++] = c;
}
pass[i] = '\0';
0 голосов
/ 04 ноября 2010

Помимо правильно диагностированной проблемы с strcat(), берущей две строки - почему вы проигнорировали предупреждения компилятора, или если не было предупреждений, почему у вас не включены предупреждения?Как я уже говорил, помимо этой проблемы вам также необходимо учитывать, что произойдет, если вы получите EOF, и вам также нужно беспокоиться о начальном значении 'c' (которое может случайно быть '\ n', хотя, вероятно, это не так.'t).

Это приводит к следующему коду:

int  c;
char pass[20] = "";
char *end = pass + sizeof(pass) - 1;
char *dst = pass;

while ((c = getchar()) != EOF && c != '\n' && dst < end)
    *dst++ = c;
*dst = '\0';  // Ensure null termination

Я переключился с' mygetch () 'на' getchar () '- главным образом потому, что то, что я говорю, относится к этому иможет не относиться к вашей функции mygetch ();у нас нет спецификации того, что эта функция делает с EOF.

В качестве альтернативы, если вы должны использовать strcat(), вам все равно нужно отслеживать длину строки, но вы можете сделать:

char c[2] = "";
char pass[20] = "";
char *end = pass + sizeof(pass) - 1;
char *dst = pass;

while (c[0] !=  '\n' && dst < end)
{
    c[0] = mygetch();
    strcat(dst, c);
    dst++;
}

Не так элегантно, как все это - использование strcat() в контексте является излишним.Вы могли бы, я полагаю, сделать простой подсчет и многократно использовать strcat(pass, c), но это имеет квадратичное поведение, так как strcat() должен пропускать 0, 1, 2, 3, ... символов на последующих итерациях.Напротив, решение, в котором dst указывает на NUL в конце строки, означает, что strcat() не должно ничего пропускать.Однако при добавлении фиксированного размера в 1 символ вам, вероятно, будет лучше с первым циклом.

...