Страницы

Поиск по вопросам

пятница, 20 декабря 2019 г.

Почему при превышении размера символьного массива и передаче его в функцию не возникает ошибка?

#cpp #массивы #char


Когда отправляю символьный массив размера 20 в функцию, которая принимает символьный
массив размером до 5, не срабатывает ошибка, вроде того, что размер превышен, или что
нибудь подобное. Он пропускает и при этом он принимает всю строку, а не только первые
5 символов.

Почему это происходит?

#include 

#define DL_FIO 20

using namespace std;
void checkup(char str[20], int* fl);
int main()
{
    int k;
    char word[DL_FIO];
    cin >> word;
    int f1 = 1;
    checkup(word, &f1);
    cout << word;
}
void checkup(char str[5], int* fl)
{
    cout << str[9];
    int x, i, n, flag1 = 1;
    //для цифр
    if (*fl != 0)
    {
        for (n = 0; n < 5; n++)
        {
            if ((str[n] >= 'a' && str[n] <= 'z') || (str[n] >= 'A' && str[n] <= 'Z'))flag1 = 0;
        }
        while (strlen(str) > 5 || flag1 == 0)
        {
            puts("\nOnly numeral can be entered. Try again.");
            cin>>str;
            flag1 = 1;
            for (n = 0; n < 5; n++)
            {
                if ((str[n] >= 'a' && str[n] <= 'z') || (str[n] >= 'A' && str[n]
<= 'Z'))flag1 = 0;
            }
        }
    }
    //для фамилии
    else
    {
        for (n = 0; n < DL_FIO; n++)
        {
            if (str[n] >= '0' && str[n] <= '9')flag1 = 0;
        }
        while (strlen(str) > DL_FIO || flag1 == 0)
        {
            puts("\nOnly letters can be entered. Try again.");
            cin>>str;
            flag1 = 1;
            for (n = 0; n < DL_FIO; n++)
            {
                if (str[n] >= '0' && str[n] <= '9')flag1 = 0;
            }
        }
        (*fl)++;
    }
}

    


Ответы

Ответ 1



В объявлениях вида void checkup(char str[20], int* fl); размер массива не имеет никакого значения и никак не учитывается языком. Все объявления параметров типа "массив" в языках C и C++ всегда сразу автоматически трансформируются в параметры типа "указатель". Ваше вышепроцитированное объявление эквивалентно объявлениям void checkup(char str[123], int* fl); void checkup(char str[], int* fl); и в конечном итоге все они эквивалентны объявлению void checkup(char *str, int* fl); Никакого контроля размера массива тут нет и быть не может. Если в языке С++ вы хотите потребовать от вызывающего кода передачи массива какого-то однозначно заданного размера, то передавайте ваш массив по ссылке void checkup(char (&str)[20], int* fl);

Ответ 2



Для того, чтобы понять почему так происходит достаточно посмотреть в скомпилированной проге ее функции. Вот что вывел nm: 0000000000004060 B __bss_start 0000000000004298 b completed.7325 U __cxa_atexit@@GLIBC_2.2.5 w __cxa_finalize@@GLIBC_2.2.5 0000000000004050 D __data_start 0000000000004050 W data_start 00000000000010e0 t deregister_tm_clones 0000000000001150 t __do_global_dtors_aux 0000000000003db8 t __do_global_dtors_aux_fini_array_entry 0000000000004058 D __dso_handle 0000000000003dc0 d _DYNAMIC 0000000000004060 D _edata 00000000000042a0 B _end 00000000000014d4 T _fini 0000000000001190 t frame_dummy 0000000000003da8 t __frame_dummy_init_array_entry 0000000000002224 r __FRAME_END__ 0000000000004000 d _GLOBAL_OFFSET_TABLE_ 0000000000001458 t _GLOBAL__sub_I_main w __gmon_start__ 000000000000206c r __GNU_EH_FRAME_HDR 0000000000001000 t _init 0000000000003db8 t __init_array_end 0000000000003da8 t __init_array_start 0000000000002000 R _IO_stdin_used w _ITM_deregisterTMCloneTable w _ITM_registerTMCloneTable 00000000000014d0 T __libc_csu_fini 0000000000001470 T __libc_csu_init U __libc_start_main@@GLIBC_2.2.5 0000000000001195 T main U puts@@GLIBC_2.2.5 0000000000001110 t register_tm_clones 00000000000010b0 T _start U strlen@@GLIBC_2.2.5 0000000000004060 D __TMC_END__ 000000000000140f t __static_initialization_and_destruction_0(int, int) 00000000000011e4 T checkup(char*, int*) U std::ios_base::Init::Init()@@GLIBCXX_3.4 U std::ios_base::Init::~Init()@@GLIBCXX_3.4 0000000000004180 B std::cin@@GLIBCXX_3.4 0000000000004060 B std::cout@@GLIBCXX_3.4 0000000000002008 r std::piecewise_construct 0000000000004299 b std::__ioinit U std::basic_ostream >& std::operator<< >(std::basic_ostream >&, char)@@GLIBCXX_3.4 U std::basic_ostream >& std::operator<< >(std::basic_ostream >&, char const*)@@GLIBCXX_3.4 U std::basic_istream >& std::operator>> >(std::basic_istream >&, char*)@@GLIBCXX_3.4 обратите внимание на 38 строчку: 00000000000011e4 T checkup(char*, int*) Тобишь ваша функция принимает char * а не char[5] или char[20] хотя это и разные типы (но char[n] автоматом приводится к char *). Таким образом компилятор не видит никакой разницы между определением и реализацией этих функций (вы можете попробовать реализовать две функции принимаещией char[5] и char[20] и компилятор ругнется на то, что функции не могут иметь одинаковых сигнатур при том же названии)

Комментариев нет:

Отправить комментарий