Воссоздайте strrchr (), но получите дополнительные символы в конце строки

#c

Вопрос:

Моя задача состоит в том, чтобы воссоздать функцию strrchr. Я придумал способ выполнить итерацию в обратном направлении от введенных данных и остановиться на символе, на котором мне нужно остановиться, но строка, очевидно, вышла в обратном направлении. Я уже создал функцию для реверса строки, поэтому использовал ее, чтобы вернуть ее в нормальное состояние. Это работает, но где-то в моем цикле while, когда я останавливаюсь на персонаже, он добавляет дополнительные символы. Пожалуйста, помогите! Я не понимаю, почему!

 #include <stdio.h>
#include <string.h>
// #include <stddef.h>
 
int
main () {
 
    char* my_strrchr(char* param_1, char param_2)
    {
        int i = strlen(param_1) - 1;
        int q = 0;
        char new[strlen(param_1)];
        char *new_ptr = new;
 
        while (i >= 0) {
            new[q] = param_1[i];
            printf("%cn", new[q]);
            if (param_1[i] == param_2) {
                i = 0;
            }
            i--;
            q  ;
        }
 
        int size = strlen(new_ptr) - 1;
 
        for (int i = 0, q = size; i < q; i  , q--) {
            char temp = new_ptr[i];
            new_ptr[i] = new_ptr[q];
            new_ptr[q] = temp;
        }
        printf("%s", new_ptr);
        return (char *)new_ptr;
 
    }
 
    char *phrase = "C Language is HARD.";
    char c = 'g';
 
    my_strrchr(phrase, c);
 
    return 0;
}
 

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

1. На первый взгляд кажется, что вы пытаетесь сделать слишком много для простого strrchr . Простым способом было бы заставить итератор исходной строки двигаться в обратном направлении , пока он не найдет param_2 , и если он не сможет найти, то вернется NULL .

2. Нет необходимости делать копию исходной строки. Это просто усложняет ситуацию больше, чем необходимо. Установите указатель на конец строки и переместите указатель назад, уменьшая его до тех пор, пока символ не будет найден или не будет достигнуто начало строки.

3. То, что сказал кайлум, верно. То, как вы это делаете, теперь требует нулевого терминатора в конце строки.

4. return (char *)new_ptr; Это очень неправильно, так как он возвращает указатель на локальную переменную. Локальные переменные выходят за пределы области действия (становятся недопустимыми) при выходе функции. Это также не удовлетворяет определению strrchr , которое требует возврата указателя на что-то в исходной строке.

5. Не расстраивайся. Программирование на самом деле очень сложно, и требуется некоторое время, чтобы осознать это. Даже если это конкретное упражнение было выше вашего понимания, просто продолжайте, и все постепенно начнет обретать смысл. Удачи!

Ответ №1:

Тебе не нужно делать ничего необычного. Просто пройдитесь по строке с самого начала, обновляя переменную с адресом символа, который вы ищете , каждый раз, когда он найден, и возвращайте его, когда вы дойдете до конца строки (в отличие strchr() от того, куда вы возвращаетесь после первого совпадения). Таким образом, вам понадобится только один проход через строку вместо двух раз, которые потребуются, если вы сначала найдете длину, а затем вернетесь назад.

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

// Really should return a const char*. Silly standard. 
char *my_strrchr(const char *s, int c) {
  const char *pos = NULL;
  while (*s) {
    if ((unsigned char)*s == (unsigned char)c) pos = s;
    s  ;
  }
  if (c == 0) {
    // If searching for '', return a pointer to the one
    // at the end of the string
    return (char *)s;
  } else {
    return (char *)pos;
  }
}

int main(void){
  const char *foo = "the quite wet duck quacks a lot";
  puts(my_strrchr(foo, 'q'));
  return 0;
}
 

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

1. Вероятно, было бы лучше начать с конца, чтобы было меньше повторений цикла. Что-то вроде этого .

2. @mediocrevegetable1 Реализация Шона более эффективна, чем ваш связанный код — strlen скрывает полную итерацию по строке, поэтому вы фактически повторяете строку дважды. Код Шона делает это только один раз.

3. @DanielKleinstein ха, это правда. Забыл об этом :p ( 1 от меня тогда)

4. @mediocrevegetable1 Как я уже упоминал в ответе, для этого требуется всего один проход. Тот, кто приносит strlen() , должен делать вдвое больше работы.