fopen Segfault ошибка на больших файлах - PullRequest
1 голос
/ 18 июля 2011

Привет всем, я новичок в C, но недавно у меня возникла странная ошибка segfault с моим fopen.

   FILE* thefile = fopen(argv[1],"r");

Проблема, с которой я столкнулся, заключается в том, что этот код работает с другими текстовыми файлами меньшего размера, но когда я пытаюсь использовать файл размером около 400 МБ, он даст ошибку по умолчанию. Я даже пытался жестко закодировать имя файла, но это тоже не работает. Может ли быть проблема в остальной части кода, вызывающая segfault в этой строке? действительно получает ошибки.

Спасибо!

РЕДАКТИРОВАТЬ * не хотел связывать это слишком много, но вот мой код

int main(int argc, char *argv[])
{
 if(argc != 3)
{
printf("[ERROR] Invalid number of arguments. Please pass 2 arguments, input_bound_file (column  1:probe, columne 2,...: samples) and desired_output_file_name");
exit(2);
}

int i,j;
rankAvg= g_hash_table_new(g_direct_hash, g_direct_equal);
rankCnt= g_hash_table_new(g_direct_hash, g_direct_equal);
table = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
getCounts(argv[1]);
printf("NC=: %i       nR =: %i",nC,nR);
double srcMat[nR][nC];
int rankMat[nR][nC];
double normMat[nR][nC];
int sorts[nR][nC];
char line[100];

FILE* thefile = fopen(argv[1],"r");
printf("%s\n", strerror(errno));
FILE* output = fopen(argv[2],"w");
char* rownames[100];
i=0;j = 1;
int processedProbeNumber = 0;
int previousStamp = 0;
fgets(line,sizeof(line),thefile); //read file

while(fgets(line,sizeof(line),thefile) != NULL)
{
cleanSpace(line); //creates only one space between entries
  char dest[100];
  int len = strlen(line);
  for(i = 0; i < len; i++)
  {
    if(line[i] == ' ') //read in rownames
    {
    rownames[j] = strncpy(dest, line, i);
    dest[i] = '\0';
    break;
    }
  }

  char* token = strtok(line, " ");
  token = strtok(NULL, " ");
  i=1;

  while(token!=NULL) //put words into array
    {
    rankMat[j][i]= abs(atof(token));
      srcMat[j][i] = abs(atof(token));
    token = strtok(NULL, " ");
    i++;
    }

    // set the first column as a row id
    j++;
  processedProbeNumber++;

    if( (processedProbeNumber-previousStamp) >= 10000)
    {
      previousStamp = processedProbeNumber;
      printf("\tnumber of loaded lines = %i",processedProbeNumber);

    }
}
printf("\ttotal number of loaded lines  = %i \n",processedProbeNumber);
fclose(thefile);

Ответы [ 3 ]

1 голос
/ 18 июля 2011

Как правило, файлы размером 2 ГБ (2 ** 31) или больше - это те, на которые вы можете рассчитывать. Это потому, что вы начинаете исчерпывать пространство в 32-разрядном целом числе для таких вещей, как индексы файлов, и один бит обычно используется для указания относительных смещений.

Предположительно в Linux вы можете обойти эту проблему, используя следующее определение макроса:

#define _FILE_OFFSET_BITS 64

Некоторые системы также предоставляют отдельный вызов API для открытия больших файлов (например: fopen64() в MKS ).

1 голос
/ 19 июля 2011

Откуда вы знаете, что fopen является ошибкой сегмента?Если вы просто добавили в код printf, есть вероятность, что стандартный вывод не будет отправлен на консоль до того, как произойдет ошибка.Очевидно, что если вы используете отладчик, вы будете точно знать, где произошла ошибка.

Глядя на ваш код, nR и nC не определены, поэтому я не знаю, насколько велика rankMat и srcMat есть, но две мысли приходили мне в голову, когда я смотрел на ваш код:

  • Вы не проверяете i и j, чтобы убедиться, что они не превышают nR и nC
  • Если nR и nC достаточно велики, это может означать, что вы используете очень большой объем памяти в стеке (srcMat, rankMat, normMat и sorts все огромные).Я не знаю, в какой среде вы работаете, но некоторые системы не могут работать с большими стеками (Linux, Windows и т. Д. Должны быть в порядке, но я много работаю со встроенными системами).Я обычно выделяю очень большие структуры в куче (используя malloc).
1 голос
/ 18 июля 2011

400Mb в наше время не следует рассматривать как «большой файл». Я бы зарезервировал это для файлов больше, чем, скажем, 2Gb.

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

UPDATE

Я до сих пор не могу точно сказать, что здесь происходит. Есть странные вещи, которые могут быть законными: вы отбрасываете первую строку, а также первый токен каждой строки.

Вы также присваиваете всем rownames[j] (кроме первого) адрес dest, который является переменной, имеющей область видимости блока, и чья связанная память, скорее всего, будет повторно использоваться вне этого блока. Я надеюсь, что вы не полагаетесь на rownames[j], чтобы иметь какое-либо значение (но зачем вам они нужны?), И вы никогда не пытаетесь получить к ним доступ.

C99 позволяет смешивать объявления переменных с фактическими инструкциями, но я бы посоветовал немного очистить, чтобы сделать код более понятным (также помогло бы улучшить отступ).

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

...