Неправильно работает функция с С строкой

Задания- Функция принимает на вход C строчку. В результате она должна создать и вернуть новую строку, содержащую все символы, которые в этой строке встречаются только один раз.

Мой код

сhar* findOneCString(const char* str)
{
   const size_t size = strlen(str);
   char* strNew = new char[size + 1];
   int num = 0;

   for (size_t index = 0; index < size; ++index) 
   {
      for (size_t j = size; j > index; --j)
      {
         if (str[index] == str[j])
         { 
          
         }
         else 
         {
            strNew[num] = str[index];
            ++num;
        }
      }
   }
 strNew[num] = '\0';
 return strNew;
}

У меня ошибки возникли и я не понимаю почему(

  1. утечка памяти
  2. записываются значения в новый массив пару раз.

Я понимаю что для большинства эта задачка легкая.. Но я не могу понять где я не так делаю


Ответы (2 шт):

Автор решения: MarianD

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

char* findOneCString(const char* str)
{
   const size_t size = strlen(str);
   char* strNew = new char[size + 1];
   strNew[0] = '\n';                         // сначала пустая строка
   int num = 0;

   for (size_t index = 0; index < size; ++index) 
   {
      bool no_repeat = true;                 // очередной символ еще не повторился
      for (size_t j = 0; j < strlen(strNew); ++j)
      {
         if (str[index] == strNew[j])
         { 
             no_repeat = false;              // когда он первый раз повторился,
             break;                          // это хватит
         }
      }
      if (no_repeat)
      {
          strNew[num] = str[index];
          ++num;
          strNew[num] = '\0';
      }
   }
   return strNew;
}

Tест:

cout << findOneCString("Abracadabra!");

выводит

Abracd!    

Объяснение:

Не надо сравнивать символы заданной строки (параметра) с символами тот самой строки.

Лучше их сравнивать с символами новой строки strNew, которую сначала сделаем пустой, и затем будем в нее постепенно добавлять символы из строки str, которых в ней затем нет.

→ Ссылка
Автор решения: sibedir

Если выделяем память через new [], то и освобождаем через delete[]. А вообще, возвращать указатель на где-то выделенную память - не самая хорошая идея. Гораздо лучше, когда тот, кто выделяет память, тот её и освобождает. А в функцию можно передать указатель на уже подготовленный буфер.

Выделять под результат strlen(str) + 1 символов нет необходимости. Больше 256 всё равно не получится.

#include <iostream>

void findOneCString(const char* str, char* res) {
    int counter[256]{};

    for (auto ptr = (unsigned char*)(str); *ptr != '\0'; ++ptr) {
        ++counter[*ptr];
    }

    int pos = 0;;
    for (int ch = 0; ch < 256; ++ch) {
        if (counter[ch] == 1) {
            res[pos] = ch;
            ++pos;
        }
    }
    res[pos] = '\0';
}

int main()
{
    //if (!setlocale(LC_ALL, "")) return 1; // опционально

    char buf[256];
    findOneCString("ыфхщHello World!\nqwertyuiop", buf);
    std::cout << buf;

    std::cout << "\n";
    system("pause");
}

Вывод:


 !HWdipqtuwyфхщы

Если нужно сохранить порядок символов:

#include <iostream>

void findOneCString(const char* str, char* res) {
    int counter[256]{};

    for (auto ptr = (unsigned char*)(str); *ptr != '\0'; ++ptr) {
        ++counter[*ptr];
    }

    int pos = 0;;
    for (auto ptr = (unsigned char*)(str); *ptr != '\0'; ++ptr) {
        if (counter[*ptr] == 1) {
            counter[*ptr] = 0;
            res[pos] = *ptr;
            ++pos;
        }
    }
    res[pos] = '\0';
}

int main()
{
    //if (!setlocale(LC_ALL, "")) return 1; // опционально

    char buf[256];
    findOneCString("ыфхщHello World!\nqwertyuiop", buf);
    std::cout << buf;

    std::cout << "\n";
    system("pause");
}

Вывод:

ыфхщH Wd!
qwtyuip
→ Ссылка