Как узнать, является ли строковый символ делимым на числа или нет на языке Си

#c #string

Вопрос:

Итак, вот в чем проблема:

  • Введите строку, содержащую числа от 0 до 9 (максимальная длина-15).
  • Если самый левый символ делится на 3, удалите его из строки
  • Если самый правый символ делится на 3, удалите его из строки
  • Если строка не соответствует двум вышеуказанным условиям и если сумма самого левого символа и самого правого символа делится на 3, удалите их из строки.
  • Продолжайте делать это до тех пор, пока строка не станет НУЛЕВОЙ или не будет соответствовать вышеуказанным условиям. Пример: ввод: «312248» —> вывод: 2. Ввод: «366936363» —>> вывод: «» Итак, вот мой код:
 #include <stdio.h>
#include <stdbool.h>
#include <conio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>

char* truncateString(char* s)
{
  char *p = amp;s[0];
  int n = strlen(s);
  p = calloc(n,sizeof(char));
  int flag = 1;
do{
  for (int i = 0; i < strlen(s); i  )
      {
        if ((s[0]-'0') % 3 == 0)
            {
              for(int j = 0; j < strlen(s); j  )
                  {
                    s[j] = s[j 1];
                  }
              p = realloc(p, (strlen(s)-1)*sizeof(char));
            }
        else if ((s[strlen(s)-1]-'0') % 3 == 0)
            {
              p = realloc(p, (strlen(s)-1)*sizeof(char));
            }
        else if (((s[strlen(s)-1]-'0') (s[0]-'0')) % 3 == 0)
            {
              for(int j = 0; j < (strlen(s)-1); j  )
                  {
                    s[j] = s[j 1];
                    p = realloc(p, (strlen(s)-2)*sizeof(char));
                  }
            }
        else
            {
              flag = 0;
            }
      }
    } while (strlen(s) != 0 || flag != 0);
    free(p);
return s;
}

int main()
{
  char s[100];
  gets(s);
  printf("Result:%s", truncateString(s));
getch();
return 0;
}
 

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

Комментарии:

1. Это не возвращает результат, я не знаю, почему

2. я получил его, поэтому я не могу использовать другое, если в этом случае, но я должен использовать, если

3. Вы указываете p на s, а затем сразу же указываете его в другое место, выделенное calloc, а затем изменяете кучу p, даже ничего в нее не помещая, а затем освобождаете ее и, наконец, возвращаете неизмененный s. Вам не нужны все эти перераспределения и все такое. Вопрос в том, хотели ли вы вернуть измененный s или вернуть выделенную строку, содержащую данные, без изменения s?

4. Все эти звонки на strlen(s) … что в данном случае ничего не меняет. Просто поместите его уже в vraiable !

5. @QuanLeAnh Я не думаю, что проблема в другом — потому что вы находитесь в цикле, если вы не поймаете это на этой итерации, вы поймаете это на следующей — я думаю, что это будет работать с другим.

Ответ №1:

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

(s[0]-'0') % 3 == 0 это прекрасный способ проверить делимость, поскольку s[0]-'0' обеспечивает текстовое char int значение.

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

strlen() нужно позвонить только один раз. Обновите длину по мере необходимости. Это позволяет избежать повторяющихся вызовов strlen() , каждый из которых обходится в O(len).

 char* truncateString(char *s) {
  char *start = s;
  size_t len = strlen(s);

  // Keep doing so until the string is "NULL"
  while (len > 0) {
    char left = s[0] - '0';
    bool left_remove = left % 3 == 0;
    char right = s[len - 1] - '0';
    bool right_remove = right % 3 == 0;
    bool right_differ_from_left = len > 1;

    // If the left most character divisible by 3, remove it from the string
    if (left_remove) {
      s  ;
      len--;
    }

    // Only consider the 'right' if the string was more than 1.
    if (right_differ_from_left) {
      // If the right most character divisible by 3, remove it from the string
      if (right_remove) {
        len--;
        s[len] = '';
      }

      // If the string does not match the above two conditions,
      // and if the summary of the left most character and
      // the right most character is divisible by 3,
      // remove them from the string.
      if (!left_remove amp;amp; !right_remove amp;amp; (left   right) % 3 == 0) {
        s  ;
        len -= 2;
        s[len] = '';
        left_remove = right_remove = true;
      }
    }

    // Keep doing so until the string is ... not meet the above conditions.
    if (!left_remove amp;amp; !right_remove) {
      break;
    }
  }

  // Move string to its original beginning.
  return memmove(start, s, len   1);
}
 

Если цели кодирования стабильны, существуют упрощения. Тем не менее, обратите внимание, что это может быть быстрее, сложнее увидеть, что это соответствует целям кодирования, чем вышеописанное.

 char* truncateString2(char *s) {
  char *start = s;
  size_t len = strlen(s);
  size_t len_at_loop_start;
  do {
    len_at_loop_start = len;
    while (len > 0 amp;amp; (s[0] - '0') % 3 == 0) {
      s  ;
      len--;
    }
    while (len > 0 amp;amp; (s[len-1] - '0') % 3 == 0) {
      len--;
    }
    while (len > 1 amp;amp; (s[0] - '0'   s[len-1] - '0') % 3 == 0) {
      s  ;
      len -= 2;
    }
 } while (len < len_at_loop_start);
  s[len] = '';
  return memmove(start, s, len   1);
}
 

Ответ №2:

У вас тоже проблемы с перераспределением. Попробуйте это, это может упростить дело

 char* truncateString(char* s)
{

  int n = strlen(s);
  int flag = 1;
while (strlen(s) != 0 amp;amp; flag != 0){
        if ((s[0]-'0') % 3 == 0)
          s  ;

        else if ((s[strlen(s)-1]-'0') % 3 == 0)
            s[strlen(s)-1] = '';
        else if (((s[strlen(s)-1]-'0') (s[0]-'0')) % 3 == 0)
        {
          s  ;
          s[strlen(s)-1] = '';
        }
        else
            flag = 0;
    }

return s;
}
 

Краткое объяснение: когда вы объявляете s , что вы точно удаляете первый элемент массива, а с помощью s[strlen(s)-1] = '' удаляете последний элемент.

Редактировать:

Здесь есть еще одно решение, которое будет работать быстрее. Вместо того, чтобы звонить s[strlen(s)-1] каждый раз, вы можете просто отслеживать начальный n=strlen(s); номер , также удалив -'0' , потому ASCII что коды для номеров начинаются 48 , поэтому они находятся в правильном положении для проверки делимости на 3. Благодаря @chux-ReinstateMonica . Вот код:

 char* truncateString(char* s)
    {

      int n = strlen(s);
      int flag = 1;
    while (n != 0 amp;amp; flag != 0){
            if ((s[0]) % 3 == 0){
              s  ;
              n--;
            }
            else if ((s[n-1]) % 3 == 0)
                s[--n] = '';
            else if (((s[n-1]) (s[0])) % 3 == 0)
            {
              s  ;
              n--;
              s[--n] = '';
            }
            else
                flag = 0;
        }
    return s;
    }
 

Комментарии:

1. Код без объяснения проблем или того, как они были исправлены, не является хорошим ответом.

2. Я написал объяснение в конце

3. вау, спасибо тебе ! Я наконец-то лучше понимаю это!

4. @chux-переустановите приложение, вы правы. Я исправил ответ. Спасибо

5. robbinc91, Примечание: s ; s[strlen(s)-1] = ''; имеет недостатки в производительности. Этот код проходит вниз по строке, чтобы найти ее длину., делая это решение O(n*n). Серьезное воздействие с большой n . Отслеживание n сэкономило бы много времени.