C код застревает, если я не вызову функцию printf () - PullRequest
2 голосов
/ 12 марта 2019

У меня есть код, который читает текстовый файл, маркирует слова в нем, затем выбирает только уникальные слова из текста, объединяет их и печатает их с помощью функции put (). Вот полный код:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char str_array[100][100];
char output[100];

void concatenate(int index)
{
  // compares output with empty string
  if (!strcmp(output, "")) 
  {
    strcpy(output, str_array[index]);
  }

  else //else existing string is contcatenated
  {
    strcat(output, " "); // add space
    strcat(output, str_array[index]);
  }
}

void unique_selection(char file[])
{
  FILE *F = fopen(file, "r");
  char ch; char str[100];
  int i=0, j=0;

  while ((ch=getc(F)) != EOF) 
  {
    // if space or newline is detected i.e. word is finished
    if (ch == ' ' || ch == '\n') 
    {
      //traverse array of strings
      for(int x=0; x<j; x++)
      {
        //if current str is already in array, skip appending
        if (!strcmp(str_array[x], str)) goto ELSE; 
      }
      strcpy(str_array[j], str);
      j++;
    ELSE:
      i=0;
      memset(str, 0, strlen(str));
    }
    else //otherwise chars of a word get appended to string array
    {
      str[i] = ch;
      i++;
    }
  }

  for(int k=0; k<j; k++)
  {
    concatenate(k);
  }
  puts(output);
  fclose(F);
}

int main(void) {
  char file[] = "test.txt";
  //printf("Output:");
  unique_selection(file);
  return 0;
}

Код работает отлично, но я сталкивался со странной проблемой, каждый раз, когда я пытался напечатать выходную строку (используя puts() или printf("%s"), программа зависала, подобно тому, что происходит, когда цикл повторяется вечно. как ни странно, эта проблема была исправлена ​​путем помещения printf перед вызовом функции. Если я удаляю puts() из функции, код работает как обычно, даже с или без printf в main().

Почему это происходит?

1 Ответ

3 голосов
/ 12 марта 2019

Здесь вы ошибаетесь:

else //otherwise chars of a word get appended to string array
{
  str[i] = ch;
  i++;
}

Когда вы впервые входите в основной цикл, str не инициализируется. Это означает, что когда вы добавляете символы в str[i], в конце строки нет завершающего нулевого байта. Это приводит к тому, что строковые функции, такие как strlen и strcpy, потенциально читают за конец массива, вызывая неопределенное поведение .

Это можно исправить, инициализировав str для всех нулей:

char str[100] = {0};

Вызов memset после копирования строки очищает ее для последующих слов.

Кроме того, это не лучшее использование goto:

  for(int x=0; x<j; x++)
  {
    //if current str is already in array, skip appending
    if (!strcmp(str_array[x], str)) goto ELSE; 
  }
  strcpy(str_array[j], str);
  j++;
ELSE:
  i=0;
  memset(str, 0, strlen(str));

Было бы правильнее установить флаг, если ваш поиск был успешным, и действовать по нему при выходе из цикла:

  int found = 0;
  for(int x=0; x<j; x++)
  {
    //if current str is already in array, skip appending
    if (!strcmp(str_array[x], str)) {
        found = 1;
        break;
    }
  }
  if (found) {
    strcpy(str_array[j], str);
    j++;
  }
  i=0;
  memset(str, 0, strlen(str));
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...