Инициализаторы с операцией new
Другим преимуществом операции new по сравнению с malloc является возможность инициализации. При отсутствии явных инициализаторов объект, создаваемый new, содержит непредсказуемые данные ("мусор"). Объекты, распределяемые new, за исключением массивов, могут инициализироваться соответствующим выражением в скобках:
int_ptr = new int(3);
Для очистки выделенной памяти операцией new можно использовать функцию meset(), объявленную в <mem.h>. Ей передаются 3 параметра: адрес очищаемой памяти, символ для очистки, количество байт.
#include <string.h>
#include <stdio.h>
#include <mem.h>
int main(void) {
char buffer[] = "Hello world\n";
printf("Буфер до memset: %s\n", buffer);
memset(buffer, '*', strlen(buffer) - 1);
printf("Буфер после memset: %s\n", buffer);
return 0;
}
Ошибки при использовании динамичской памяти
1). Недоступные блоки - блоки памяти, указатели на которые потеряны.
2). Висящие ссылки - указатели на освобожденные блоки памяти.
3). Повторное освобождение динамической памяти. Недоступные блоки возникают после выделения памяти при присваивании указателю какого- либо другого значения или при уничтожении локального указателя после выхода из области видимости.
Пример 1:
int *a1, *a2;
a1 = new int[1000]; //выделили память
... //что-то делаем
a1 = a2; //ошибка - присвоение а1 другого
//значения - память недоступна
Пример 2:
void func(void)
{
int * a1;
a1 = new int[1000];
...
} //ошибка - при выходе из функции автоматически
//уничтожен a1,а память, тем не менее, осталась
//занята и недоступна.
Необходимо следить за указателями на выделенную память:
int * c;
void func1(void) {
int * a1;
a1 = new int[1000];
c = a1; //если данные по адресу a1 необходимы вне func1
... //иначе освободить перед выходом из функции
}
void func2(void)
{
...
delete []c;
}
Висящие ссылки возникают при освобождении памяти, на которую указывает более чем 1 указатель:
int *a = new int[1000];
int *a1 = a;
...
delete []a;
d = *(a1+50); //опасно - a1 уже нельзя использовать для обращения к
//массиву!
...
Если нет освобождения памяти, программист в зависимости от конкретной ситуации может посчитать это ошибкой, а может и нет (хотя это в любом случае уменьшает доступные ресурсы памяти), повторное освобождение безусловно ошибочно и скорее всего приведет к зависанию системы. Как правило, подобные ошибки не проявляются немедленно после появления, что затрудняет процесс отладки.
Написать программу учета успеваемости группы. Программа должна считать ср. бал группы и выводить на экран.
#include <stdio.h>
#include <conio.h>
#include <iostream.h>
void main(void) {
int i,j,n;
float varsum=0;
struct stud { char fio[15]; char name[10];
struct exam { int val1; int val2;
int val3; int val4;}estimate;
float midle;
};
puts(«введите кол-во студентов”);
cin>>n;
struct stud *pgroup=new struct stud[n];
for(i=0; i<n; i++) {
printf(“Введите данные по %d студенту\n”,i+1);
cout<< “Фамилия:”;
gets(pgroup->fio);
cout<< “Имя:”;
gets(pgroup->name);
cout<< “Оценка за 1-й экзамен:”;
gets(pgroup->estimate.val1);
cout<< “Оценка за 2-й экзамен:”;
gets(pgroup->estimate.val2);
cout<< “Оценка за 3-й экзамен:”;
gets(pgroup->estimate.val3);
cout<< “Оценка за 4-й экзамен:”;
gets(pgroup->estimate.val4);
pgroup->middle = ( pgroup->estimate.val1+pgroup->estimate.val2+ pgroup->estimate.val3+ pgroup->estimate.val4)/4;
cout<<”Средний бал ”<< pgroup->fio<< pgroup->name<< pgroup->midle<<endl;
varsum+= pgroup->midle;
}
cout<<»Средний балл по группе”<<varsum/n<<endl;
delete[] pgroup;
}
ФАЙЛ
Язык Си "рассматривает" файл как структуру. В stadio.h содержится определение структуры файла. Определен шаблон и директива препроцессора #defile FILE struct iobuf
FILEкраткое наименование шаблона файла. Некоторые системы используют директиву typedef для установления этого соответствия.
typedef struct iobuf FILE
Открытие файла fopen()
Функцией управляют три параметра.
FILE *in; //указатель потока
Для связывания указателя с файлом служит функция открытия файла fopen(), которая объявлена в заголовочном файле <stdio.h>.
in = fopen("test", "r");
1 параметр - имя открываемого файла
2 параметр -
"r"-по чтению "r+"-чтение и запись
"w"-по записи "w+"-запись и чтение, если файл уже был, он перезаписываетя
"a"-дозапись "a+"-чтение и дозапись, если файла еще не было, он создается
"b"-двоичный файл
"t"-текстовый файл
in является указателем на файл "test". Теперь будем обращаться к файлу через этот указатель.
Если файл не был открыт (его нет, нет места на диске), то возвращается в указатель 0.
if((in=fopen("test", "r"))==0)
puts("Ошибка открытия файла");
Можно по другому
in=fopen("test", "r");
if (!in)
puts("Ошибка открытия файла");
Закрытие файла fclose()
fclose(FILE *stream); //Если файл закрыт успешно, то возвращается 0 иначе -1.
19.3 Функции ввода/вывода одного символа fgetc(), fputc()
1. Чтение из файла посимвольно
int fgetc(FILE *stream);
2. Запись в файл посимвольно
int fputc(int c, FILE *stream);
Код этого же символа и возвращается.
ch=fgetc(in);
fputc(ch,out);
# include <stadio.h>
void main(void){
FILE *in,*out;
char ch;
if((in=fopen("prog1", "r"))==0)
fputs("Ошибка открытия prog1");
if((out=fopen("prog2", "w"))==0)
fputs("Ошибка открытия prog2);
while((ch=getc(in))!=EOF) //”End Оf File” константа определенная в dos.h
fputc(ch, out);
fclose(in);
fclose(out);
}
19.4 Функции форматированного ввода/вывода в файл
1. Форматированный вывод в текстовый файл
int fprintf(FILE *stream,”управл.cтрока”,arg1,…)
Возвращает количество записанных байтов.
2. Форматированный ввод из текстового файла
int fscanf(FILE *stream,”управл.cтрока”,&arg1,…)
Возвращает количество прочитанных байтов.
# include<stadio.h>
void main(void){
FILE*in;
int age;
in=fopen("prog1", "r");
fscanf(in,"%d",&age);
fclose(in);
in=fopen("prog2", "w");
fprintf(in,"число %d\n",age);
fclose(in);
}
Модификаторы и спецификаторы, те же, что и в printf().
19.5 Функции ввода/вывода строки символов в файл
1. Чтение текстовой строки из файла.
char* fgets(char *str, int n, FILE *stream);
Читает до перевода строки или n-1 байт и к концу строки присоединяет 0 байт, если прочитан \n.
void main(void){
FILE*in;
char string[80];
in=fopen("story", "r");
while(fgets(string,80, in)!=0)
puts(string);
}
Считывается до конца строки '\n' или 80-1 байт. При встрече EOF возвращает 0.
2. Запись текстовой строки в файл
int fputs(char *str,FILE *stream);
y=fputs(“Это строка”,in);
y-целое число, которое устанавливается в EOF, если fputs() встре-чает EOF или ошибку. fputs не добавляет '\n' в конeц строки.
Все эти функции работают с текстовыми файлами и называются функциями последовательного доступа к файлу. Указатель внутри файла перемещается автоматически при чтении или записи.
Существуют функции прямого доступа к файлу.