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

Я не могу понять, почему char *ptr = new char[7] не будет усекать ввод данных размером более 7 символов. Также почему eighter char c[7] позволил бы мне вводить более 6 символов (но выдавал ошибку при присвоении ему буквального значения более 6 символов).

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

char qs[7] = "1234567"; //error too many

char qs2[7];
cin >> qs2;             //input 123456789
cout << qs2;            //out same as input, expecting 123456

char *qs3 = new char[7];
cin >> qs3;             //input 123456789
cout << qs3;            //out same as input, expecting 123456

Ответы [ 3 ]

7 голосов
/ 07 ноября 2019

В настоящее время входной поток принимает в качестве аргумента только указатель. Поэтому он не может знать размер буфера, который он заполняет. Поэтому он не может знать, должен ли он урезаться или нет. Чтение строки длиннее буфера приведет к переполнению буфера, и поведение программы будет неопределенным. Не делайте этого.

Начиная с C ++ 20, операнд массива передается по ссылке, и операция знает размер и обрезает ввод. Однако это не поможет в случае qs3, поскольку это всего лишь указатель, а не массив.

Вместо этого вы можете использовать:

std::cin.get(qs3, 6);
qs3[6] = '\0';

. прочитано больше символов, чем помещается в буфер.

Или, если вы предпочитаете не урезать ввод, вы можете прочитать в std::string.


Выполнение с помощью функции mallocМне кажется, что мне немного трудно, поэтому я предпочитаю не использовать его.

Хорошо. Это не решит вашу проблему, и нет необходимости использовать его, равно как и нет никакого преимущества в его использовании.

0 голосов
/ 07 ноября 2019

C-строки заканчиваются нулями, это означает, что вы всегда должны выделять буфер с длиной строки размера + 1.

char qs [7] = "1234567";// ошибка слишком много

В статически размещенных буферах для компилятора очевидно, что в вашем буфере нет места для завершения нуля. Это должно быть char qs [8].

В обоих других примерах оператор принимает указатель на буфер в качестве аргумента, и у него нет способа узнать, насколько он велик. Это просто заполнить его до конца ввода. Вы получаете классическую ситуацию переполнения буфера, и вам повезло, что там нет ничего важного (после границ буфера).

0 голосов
/ 07 ноября 2019

Оба фрагмента кода

char qs2[7];
cin >> qs2;             //input 123456789
cout << qs2;            //out same as input, expecting 123456

char *qs3 = new char[7];
cin >> qs3;             //input 123456789
cout << qs3;            //out same as input, expecting 123456

имеют неопределенное поведение. Память за пределами выделенных массивов перезаписывается. Последствия могут быть любого вида.

Рассмотрим следующую демонстрационную программу.

#include <iostream>

int main() 
{
    char gs1[7] = "123456";
    char gs2[7];
    char gs3[7] = "ABCDEF";

    std::cin >> gs2;

    std::cout << '\n';

    std::cout << gs1 << '\n';
    std::cout << gs2 << '\n';
    std::cout << gs3 << '\n';

    return 0;
}

Если ввести

1234567

, то вывод программы может выглядеть как

123456
1234567

Как видите, строка "ABCDEF" не была выведена. Это результат того, что завершающий ноль '\0', который был добавлен к массиву gs2 после того, как этот оператор

    std::cin >> gs2;

перезаписывает первый символ массива gs3. Теперь его содержимое выглядит как

{ '\0', 'B', 'C', 'D', 'F', '\0' }

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

    std::cout << gs3 << '\n';
...