В массиве вроде int a[5]
мы можем хранить 5 значений от [0] до [4]. не это..?
у меня есть char mobile[10]
переменная в моем class
и я хранил ровно 10 символов строки в этой переменной. Но когда я читаю его из файла, несколько символов из следующей переменной (объявленной сразу после этой переменной в классе) добавляются в переменную mobile
, Потребовались часы, чтобы выяснить, что не так.
Я перепробовал все, что мог, изменив порядок переменных и т. Д.
Наконец я бы установил размер mobile
до 11 (char mobile[11]
), а затем сохранить его в двоичном файле. Тогда все идет хорошо.
Здесь я создал демонстрационную программу, которая может продемонстрировать мое исследование:
#include <iostream.h>
#include <conio.h>
#include <string.h>
#include <fstream.h>
#include <stdio.h>
class Test
{
public:
char mobile[10], address[30];
};
void main()
{
clrscr();
Test t;
// uncoment below to write to file
/*strcpy(t.mobile, "1234567890");
strcpy(t.address, "Mumbai");
fstream f("_test.bin", ios::binary | ios::out | ios::app);
f.write((char*)&t, sizeof(t));*/
// uncomment below to read from file
/*fstream f("_test.bin", ios::binary | ios::in);
f.read((char*)&t, sizeof(t));
cout << t.mobile << "\t" << t.address;*/
f.close();
getch();
}
Верно ли мое предположение, что я не могу хранить n символов в массиве char[n]
при работе с файлами более конкретно с двоичными файлами ..?
Должен ли я всегда брать 1 дополнительный размер необходимого размера .. ??
Мой компилятор — Turbo C ++ (может быть 3.0). Это очень старый и снятый с производства продукт.
символьные указатели в C / C ++ должны заканчиваться нулем. Это означает, что вы должны выделить другой символ со значением ‘\ 0’ в конце.
Также обратите внимание, strcpy
Функция копирует все символы из одной строки в другую, пока \0
встречается, если только не является константной строкой (например, «hello world»), которая хранится как «hello world \ 0» во время компиляции.
Попробуйте этот код:
#include <iostream.h>
#include <conio.h>
#include <string.h>
#include <fstream.h>
#include <stdio.h>
class Test
{
public:
char mobile[11], address[30];
};
void main()
{
clrscr();
Test t;
// uncoment below to write to file
strcpy(t.mobile, "1234567890");
strcpy(t.address, "Mumbai");
t.address[10] = '\0';
fstream f("_test.bin", ios::binary | ios::out | ios::app);
f.write((char*)&t, sizeof(t))
// uncomment below to read from file
fstream f("_test.bin", ios::binary | ios::in);
f.read((char*)&t, sizeof(t));
cout << t.mobile << "\t" << t.address;
f.close();
getch();
}
Строки в стиле C (массивы символов) заканчиваются нулем. Вам не нужно хранить нулевой терминатор в вашем файле, но он вам нужен при печати строки.
В вашем примере вы используете strcpy
скопировать 10-символьную строку в char[10]
, Это неопределенное поведение, потому что strcpy
добавляет нулевой терминатор к строке назначения. Вам нужно использовать char[11]
,
В вашем примере вы читаете 10 символов из файла и распечатываете их, используя cout
, cout
определяет длину строки нулевым терминатором. Так как у вас его нет, cout
читает за концом вашей строки. Это также неопределенное поведение, но в большинстве случаев работает, считывая символы из следующего поля в структуре. Вам нужен нулевой терминатор для этого массива, что означает, что вам также нужно увеличить размер массива до 11 для этого.
Строковый литерал "1234567890"
занимает 11 байтов, а не 10!
printf("%d", sizeof("1234567890"));
// 11
Это потому, что компилятор молча добавляет \0
символ — конец строкового маркера — в конце строковых литералов. Этот маркер используется различными функциями для работы со строками, в том числе strcpy
,
Теперь следующая строка:
strcpy(t.mobile, "1234567890");
пытается скопировать строку — 10 символов плюс \0
— в t.mobile
, поскольку t.mobile
длиной 10 байт, \0
переполнится в пространство, используемое пространством других переменных (или хуже).
В вашем примере:
strcpy(t.mobile, "1234567890")
копирует строку, как и ожидалось, но \0
перетекает в пространство, используемое t.address
strcpy(t.address, "Mumbai")
копирует строку, как и ожидалось, \0
перезаписываетсяt.mobile
должно быть "1234567890Mumbai"
Мораль истории: всегда учитывайте \0
байт при использовании строковых функций Си. Невыполнение этого требования приведет к неожиданный проблемы, включая повреждение переменных, ошибки во время выполнения или хуже (например, выполнение данных).