Проблема с записью массива двойников в файл

у меня действительно большой массив чисел с двойной точностью... я пытался записать его в файл, используя fprintf()... мне нужно записать эти числа по одному в каждой строке, поэтому я сделал что-то вроде этого.

if((fp2 = fopen("temp", "w")) == NULL) { perror("File cannot be opened"); exit(1); }

for(int k = 0; k < j; k++ )
{
fprintf(fp2, "%0.3lf\n", diff[k]);  
}

Однако есть проблема, что он записывает данные до определенного количества строк, после чего я выдаю все нули. Например

3.040
0.700
-2.740
0.000
0.000
0.000
0.000
0.000
0.000

вообще не могу понять в чем может быть проблема. почему он записывает все значения как 0,000, когда в массиве есть значения.

вот как был реализован diff, если это поможет.

            diff = (double *)malloc(fileSize);

        diff[0] = data[0];


        for(j = 1; j < n; j++ )
        {
            diff[j] = data[j] - data[j-1];
        }

значения из файла были сохранены в data[]. Затем я вычислил разницу между соседними значениями в data[] в diff[] и записал ее обратно в другой файл. fileSize — это размер исходного файла. и я точно знаю, что все значения в diff[] заполнены правильно.


person sfactor    schedule 07.12.2009    source источник
comment
Откуда вы знаете, что есть какие-то ценности? Вы использовали точку останова на fprintf() и действительно проверяли содержимое этого массива?   -  person viraptor    schedule 07.12.2009
comment
Вы уверены, что внутри diff есть как минимум j элементов?   -  person Brian R. Bondy    schedule 07.12.2009
comment
Измените строчную «l» на прописную «L» в спецификаторе формата.   -  person    schedule 07.12.2009
comment
Можете ли вы показать источник, где объявлено diff? А также можете ли вы показать нам источник, где j присвоено значение?   -  person PP.    schedule 07.12.2009
comment
да, я уверен, я проверил это, написав printf(%0.3lf\n, diff[k]) в консоль, он показывает все значения, поэтому я почти уверен, что данные есть... и я знаю, что они размер до j.   -  person sfactor    schedule 07.12.2009
comment
Также откройте файл с текстом '+wt'.   -  person    schedule 07.12.2009
comment
@roygbiv: почему +wt? «t» не распознается Стандартом, это (избыточное) расширение, предоставляемое некоторыми компиляторами.   -  person pmg    schedule 07.12.2009
comment
%lf для длинного двойника, используйте %f для обычного двойника   -  person quinmars    schedule 07.12.2009
comment
@quinmars: %lf не распознается для printf() и используется для двойных значений в scanf(); %f используется для двойных чисел в printf() (у которого нет формата для float) и для чисел с плавающей запятой в scanf().   -  person pmg    schedule 07.12.2009
comment
@pmg - Основная проблема, вероятно, заключается в том, что «l» должна быть заглавной L, которая интерпретирует аргумент как «длинный двойной», а не строчную «l» как «int». Возможно, лучше вообще убрать букву «l».   -  person    schedule 07.12.2009
comment
это действительно проблема из-за этого? ... я получаю все правильные значения при выполнении printf(), но при записи того же в файл с fprintf() возникает проблема.   -  person sfactor    schedule 07.12.2009
comment
%lf — это расширение компилятора. Мы не знаем, какой у вас компилятор и какие расширения он предоставляет. Если вы можете написать свой код, не полагаясь на расширения, тем лучше.   -  person pmg    schedule 07.12.2009
comment
@sfactor - изменить его на L или удалить букву «l», запустить его и сообщить мне?   -  person    schedule 07.12.2009
comment
да, пробовал оба подхода, он все еще записывает эти значения 0,000 после определенных точек.   -  person sfactor    schedule 07.12.2009
comment
+1 за показ определения diff, спасибо. Итак, что такое fileSize и связано ли оно с n? Обратите внимание, что когда вы malloc(fileSize) вы выделяете fileSize БАЙТОВ в памяти. Каждый двойной занимает 8 байт (более или менее в зависимости от платформы), поэтому в вашем массиве будет fileSize / 8 элементов. Вы УВЕРЕНЫ, что n никогда не превышает количество элементов в вашем массиве?   -  person PP.    schedule 07.12.2009
comment
@PP да, это была именно проблема ... спасибо, что указали на это. теперь работает!!!   -  person sfactor    schedule 07.12.2009
comment
у меня сложилось впечатление, что, поскольку массив данных [] имеет это определение, а diff [] имеет одинаковое количество элементов, я могу определить его одинаково.   -  person sfactor    schedule 07.12.2009
comment
Обратите внимание, что вы можете записать свой файл как двоичный, это вполне приемлемо, просто имейте в виду, что окончание строки может не соответствовать вашей платформе.   -  person PP.    schedule 07.12.2009


Ответы (4)


Добавление в качестве официального ответа после комментариев:

У вас есть следующая строка:


diff = (double *)malloc(fileSize);

Обратите внимание, что при malloc(fileSize) вы выделяете в памяти байты для файла fileSize. Каждый двойной занимает 8 байт (более или менее в зависимости от платформы), поэтому в вашем массиве будет элемент fileSize/8. Вы УВЕРЕНЫ, что n никогда не превышает количество элементов в вашем массиве?

Причина, по которой ваша программа может правильно работать с printf, а не с fprintf, заключается в том, что ошибки памяти очень и очень незаметны. Если вы начнете использовать память, которую вы не выделили, тогда все может быть хорошо в течение короткого периода времени, но все пойдет наперекосяк, когда другая часть программы вполне законно решит начать использовать тот кусок памяти, который вы уже используете.

person PP.    schedule 07.12.2009

Правильный спецификатор преобразования для печати значения double — это %f, а не %lf.

C99 не указывает, что принимает %lf. Ваша реализация может предоставить %lf в качестве расширения для long doubles или что-то в этом роде, но вам нужно сопоставить тип переменной со спецификатором преобразования. Проверьте документацию для вашего компилятора.

Если у вас есть long doubles, правильным спецификатором преобразования C99 будет %Lf.


Редактировать после редактирования вопроса

            for(j = 1; j < n; j++ )
            {
                    diff[i] = data[i] - data[i-1];
            }

Переменная цикла — j, индексы для различий и данных — i. Была ли это ошибка копирования/вставки или это ваша настоящая проблема? :)


Второе изменение

Хммм... этот malloc(fileSize) выглядит очень, очень подозрительно.
Разве вы не знаете, сколько элементов вам нужно, исходя из количества элементов в массиве data? Используйте это вместо этого.

diff = malloc(number_of_elements_in_array_data * sizeof *diff);
person pmg    schedule 07.12.2009

Это может быть тот факт, что у вас есть массив, инициализированный нулем, т.е. 0.0 через memset или аналогичный. И при повторении массива он вытащил значение смещения, равное нулю (это может быть то, что вы перераспределили/переоценили размер массива).

if((fp2 = fopen("temp", "wt")) == NULL) { 
   perror("File cannot be opened"); 
   exit(1); 
}

for(int k = 0; k < j; k++ )
{
if (diff[k] > 0.0) fprintf(fp2, "%0.3lf\n", diff[k]);      
}

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

Другое дело, когда вы указываете тип режима доступа в функции fopen(...), он по умолчанию бинарный. На самом деле следует t указать текстовый режим, как показано выше.

Надеюсь, это поможет. С уважением, Том.

person t0mm13b    schedule 07.12.2009
comment
fopen() по умолчанию работает в текстовом режиме. «t» в аргументе режима является (избыточным) расширением компилятора — оно не распознается стандартом C. - person pmg; 07.12.2009
comment
@pmg: Плохо! Спасибо за внимание! Я старая школа... :P - person t0mm13b; 07.12.2009

Если вы просто хотите напечатать первое значение и различия между последовательными значениями, зачем возиться с массивом различий? Почему бы не сделать это простым способом?

fprintf(fp2, "%Lf\n", data[0]);
for(j = 1; j < n; j++ )
{
  fprintf(fp2, "%Lf\n", data[j] - data[j-1]);
}

Как указал другой парень, ваш malloc(), вероятно, является поддельным, и это то, что вас беспокоит.

person John R. Strohm    schedule 07.12.2009