смотрите этот код =
// my_printf.cpp : Defines the entry point for the console application.
//
/* задача - Реализовать внутренности функции (каждому по 1) в среде разработки Microsoft Visual C++.
Описания функций брать в Microsoft Solution Developers Network(MSDN).
24. fprintf
*/
#include "stdafx.h"
#include < vector >
#include < iterator >
// далее следуют объявления функций.
int welcome();
int my_printf(FILE *stream, char* frm,...);
void testme(); //
// далее реализация
int _tmain(int argc, _TCHAR* argv[])
{
welcome(); // приветствие
testme(); // запускаем тесты
return 0;
}
int my_fprintf(FILE *file, char* frm,...) // это и есть "рабочая часть программы"
{
#define IF_FILE if (file) // для краткости кода - если файл имеется - открываем его или пишем его.
void* next= & frm; /* этот указатель мы будем сдвигать, если окажется, что
в функцию переданы необязательные парамтеры.*/
int i=0; // используем для перебора строки
int prnt=0; // признак того, что текущий символ строки формата напечатан
int j=0; // счётчик для хождения по строкам дополнительных параметров
int ind=0; // признак того, что предыдущий символ был %
char** str1; /* вспомогательный указатель на строку формата(т.е. указатель на указатель на первый символ строки) -
нужен только чтобы переместить next первый раз - "переступить" через строку формата*/
str1=((char**)next); // указатель на обязательную строку формата
str1++;/*переставляем указатель на первый необязательный пареметр(предположительно переданный)*/
next=str1;
if (!file) // если файл для вывода не указан.
{
while (frm[i])
{
if (ind==1) // если предыдущий символ был знаком формата
{
// prnt = 1; // поднимаем флаг,чтобы не печатать символ специфицирующий тип параметра
ind = 0; // сбрасываем признак того, что ранее был знак %
switch (frm[i]) // ВАРИАНТЫ ПАРАМЕТРОВ
{
case 's': // это или иное значение которому может быть равен параметр
{//printf("this's string \n");
char** str;// указатель на строку для работы с необязательными параметрами
str= (char**) next; // приводим указатель к нужному нам типу
char * strt = *str;
j=0;
while (*(*str+j)!='\0') // разыменовываем указатель
{
putchar(*(*str+j));// выводим символ
j++; // чтобы перейти к следующему символу
}
j=0; // обнуляем счётчик.
str++; //?????? какая разница - str++ next= str++ ?????????????
next= str;// "перешагиваем" через обработанный параметр
}
break; // выход из перебора вариантов -иначе будет рассматриваться case 2
case 'i': // если это integer
{
int* value = (int*) next; // если i - значит приводим указаетль к типу int
using namespace std; // пространство имён стандртной библиотеки.
vector< char > charVector; // используем шаблон вектор для типа char например
int val = *value;
// минус для отрицательного числа
if (val<0)
{
val*=-1;
putchar('-');
}
value++;
next= value;// и сразу "перешагиваем" через область памяти размера "указатель на целое"
int dig; // очередная цифра
int small; // после деления на десять
char ch;//получаемый символ
while (val!=0)
{
small =val/10;
dig = val -small*10 ; // получаем ASSCI код символа
ch= dig + 48 ;
charVector.push_back(ch); // получается , что мы записываем целую часть начиная с младшего символа
val = int(val/10);
} // по цикла мы получили все символы - она лежат в charVector в обратной последовательности
// теперь выведем эти символы
// charVector.push_back('0');
typedef vector< char >::iterator char_iterator;
reverse_iterator< char_iterator > rev_end (charVector.begin()); // начало= конец обратного перечислителя // <------
reverse_iterator < char_iterator > rev_iterator (charVector.end());
// j=0; // исользуем в качестве счётчика
while (rev_iterator != rev_end) {
ch = (char) *rev_iterator;
//ch ='1';
putchar(ch); /* Обратите внимание, что доступ к элементу
можно получить посредством разыменования итератора */
++rev_iterator;
}
}
break;
case 'd': // если это double
{
double* value = (double*) next;
double val = *value;
// минус для отрицательного числа
if (val<0)
{
val*=-1;
putchar('-');
}
value++;
next= value;
double v1 = 123.34;
double * va = &v1;
double val3 = * va;
int val1=(int)val; // целая часть числа
double val2=val-val1; // дробная часть числа
// сначала обратываем и выводим целую часть числа
using namespace std; // пространство имён стандртной библиотеки.
vector<char> charVector1; // для цифр целой части числа
int dig; // очередная цифра
int small; // после деления на десять
char ch;//получаемый символ
while (val1!=0) // работаем с целой частью
{
small =val1/10;
dig = val1 -small*10 ; // получаем ASSCI код символа
ch= dig + 48 ;
charVector1.push_back(ch); // получается , что мы записываем целую часть начиная с младшего символа
val1 = int(val1/10);
}
typedef vector < char >::iterator char_iterator;
reverse_iterator < char_iterator > rev_end (charVector1.begin()); // начало= конец обратного перечислителя // <------
reverse_iterator< char_iterato r> rev_iterator (charVector1.end());
// j=0; // исользуем в качестве счётчика
while (rev_iterator != rev_end) {
ch = (char) *rev_iterator;
//ch ='1';
putchar(ch); /* Обратите внимание, что доступ к элементу
можно получить посредством разыменования итератора */
++rev_iterator;
}
putchar('.');// выводим точку которая разделяет целую и дробную часть числа
// далее обратываем и выводим дробную часть числа
vector < char > charVector2; // для цифр дробной части числа
while (val2!=0)
{
dig =(int)( val2*10);
val2 = val2*10 - dig;
charVector2.push_back(dig+48);
}
vector < char >::iterator iter; // инициализируем перечислитель
iter = charVector2.begin();
while (iter != charVector2.end())
{
putchar(*iter);
++iter;
}
}
break;
default: // действия, если ничего выше не встретили
putchar(frm[i]);
}
} else if (frm[i]=='%') ind=1; // если встречаем знак формата
else putchar(frm[i]);
//prnt=0; // опускаем флаг
i++; // переходим к следующему символу строки второго параметра
}
} else // если дескриптор файла передан ВСЁ ТАКИ - ДАЛЕЕ ПОВТОР, НО С ВЫВОДОМ В ФАЙЛ ВМЕСТО КОНСОЛИ
{
while (frm[i])
{
if (ind==1) // если предыдущий символ был знаком формата
{
// prnt = 1; // поднимаем флаг,чтобы не печатать символ специфицирующий тип параметра
ind = 0; // сбрасываем признак того, что ранее был знак %
switch (frm[i]) // ВАРИАНТЫ ПАРАМЕТРОВ
{
case 's': // это или иное значение которому может быть равен параметр
{//printf("this's string \n");
char** str;// указатель на строку для работы с необязательными параметрами
str= (char**) next; // приводим указатель к нужному нам типу
char * strt = *str;
j=0;
while (*(*str+j)!='\0') // разыменовываем указатель
{
fputc(*(*str+j),file);//putchar(*(*str+j));// выводим символ
j++; // чтобы перейти к следующему символу
}
j=0; // обнуляем счётчик.
str++; //?????? какая разница - str++ next= str++ ?????????????
next= str;// "перешагиваем" через обработанный параметр
}
break; // выход из перебора вариантов -иначе будет рассматриваться case 2
case 'i': // если это integer
{
int* value = (int*) next; // если i - значит приводим указаетль к типу int
using namespace std; // пространство имён стандртной библиотеки.
vector< char > charVector; // используем шаблон вектор для типа char например
int val = *value;
// минус для отрицательного числа
if (val<0)
{
val*=-1;
fputc('-',file);
}
value++;
next= value;// и сразу "перешагиваем" через область памяти размера "указатель на целое"
int dig; // очередная цифра
int small; // после деления на десять
char ch;//получаемый символ
while (val!=0)
{
small =val/10;
dig = val -small*10 ; // получаем ASSCI код символа
ch= dig + 48 ;
charVector.push_back(ch); // получается , что мы записываем целую часть начиная с младшего символа
val = int(val/10);
} // по цикла мы получили все символы - она лежат в charVector в обратной последовательности
// теперь выведем эти символы
// charVector.push_back('0');
typedef vector< char >::iterator char_iterator;
reverse_iterator< char_iterator > rev_end (charVector.begin()); // начало= конец обратного перечислителя // <------
reverse_iterator<char_iterator> rev_iterator (charVector.end());
// j=0; // исользуем в качестве счётчика
while (rev_iterator != rev_end) {
ch = (char) *rev_iterator;
//ch ='1';
fputc(ch,file); /* Обратите внимание, что доступ к элементу
можно получить посредством разыменования итератора */
++rev_iterator;
}
}
break;
case 'd': // если это double
{
double* value = (double*) next;
double val = *value;
// минус для отрицательного числа
if (val<0)
{
val*=-1;
fputc('-',file);
}
value++;
next= value;
double v1 = 123.34;
double * va = &v1;
double val3 = * va;
int val1=(int)val; // целая часть числа
double val2=val-val1; // дробная часть числа
// сначала обратываем и выводим целую часть числа
using namespace std; // пространство имён стандртной библиотеки.
vector<char> charVector1; // для цифр целой части числа
int dig; // очередная цифра
int small; // после деления на десять
char ch;//получаемый символ
while (val1!=0) // работаем с целой частью
{
small =val1/10;
dig = val1 -small*10 ; // получаем ASSCI код символа
ch= dig + 48 ;
charVector1.push_back(ch); // получается , что мы записываем целую часть начиная с младшего символа
val1 = int(val1/10);
}
typedef vector< char >::iterator char_iterator;
reverse_iterator< char_iterator > rev_end (charVector1.begin()); // начало= конец обратного перечислителя // <------
reverse_iterator< char_iterator > rev_iterator (charVector1.end());
// j=0; // исользуем в качестве счётчика
while (rev_iterator != rev_end) {
ch = (char) *rev_iterator;
//ch ='1';
fputc(ch,file); /* Обратите внимание, что доступ к элементу
можно получить посредством разыменования итератора */
++rev_iterator;
}
fputc('.',file);// выводим точку которая разделяет целую и дробную часть числа
// далее обратываем и выводим дробную часть числа
vector < char > charVector2; // для цифр дробной части числа
while (val2!=0)
{
dig =(int)( val2*10);
val2 = val2*10 - dig;
charVector2.push_back(dig+48);
}
vector < char >::iterator iter; // инициализируем перечислитель
iter = charVector2.begin();
while (iter != charVector2.end())
{
fputc(*iter,file);
++iter;
}
}
break;
default: // действия, если ничего выше не встретили
fputc(frm[i],file);
}
} else if (frm[i]=='%') ind=1; // если встречаем знак формата
else fputc(frm[i],file);
//prnt=0; // опускаем флаг
i++; // переходим к следующему символу строки второго параметра
}
}
return 1;
}
void testme() // используем для тестирования нашей реалзиации fprintf
{
// просто вывод в консоль
my_fprintf(0,"1) %% string % = %s","THIS IS FIRST TEST \n");
my_fprintf(0,"2) this's text = %s -> this's text continuation))\n","THIS IS STR PARAM");
my_fprintf(0,"3) this's integer = %i -> this's text continuation))\n",123999);
my_fprintf(0,"4) this's double = %d -> this's text continuation after double))\n",123.555);
my_fprintf(0,"5) negative double = %d -> this's text continuation after double))\n",-123.555);
my_fprintf(0,"6)negative int = %i -> this's text continuation negative int ))\n\n",-555);
my_fprintf(0,"7-1)COMPLEX TEST STR = %s INT = %i DOUBLE = %d))\n\n","my_str",-7845,-12.55);
my_fprintf(0,"7-2)COMPLEX TEST INT = %i STR = %s DOUBLE = %d))\n\n",-555,"my_str",-12.55);
// printf("%%");
// опять же тестируем нашу функцию , но теперь попытаемся записать что-нибудь в файл.
FILE* fp = fopen("C:\\samer\\sam.txt","w");
my_fprintf(fp,"2) this's text = %s -> this's text continuation))\n","THIS IS STR PARAM");
my_fprintf(fp,"7-2)COMPLEX TEST INT = %i STR = %s DOUBLE = %d))\n\n",-555,"my_str",-12.55);
fclose(fp); // закрываем файл
getchar(); // чтобы консоль ждала нажатия клавиши
}
int welcome() // это просто)
{
printf(" {{This is the my fprintf realization.}} \n");
//getchar();
return 0;
}