Найти первые повторяющиеся буквы в каждой строке данного набора


Первый вход-это количество строк, например: 5
Второй вход представляет собой набор строк, например: Привет, как ты

Выходная буква в строке, например: 'L' в строке 1

Ниже мой код:

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

void find_first_recurring_letter(char **str,int r,int c);

int main()
{
    int r,i;
    printf("Enter the number of strings to be entered");
    scanf("%d",&r);
    /*dynamic allocation for str*/
    char **str=(char**)malloc(r*sizeof(char*));
    for(i=0;i<r;i++)
        str[i]=(char*)malloc(50*sizeof(char));
    for(i=0;i<r;i++)
    {
        printf("Enter the string %d",i+1);
        gets(str[i]);
    }
    for(i=0;i<r;i++)
        printf("%s\n",str[i]);
    find_first_recurring_letter(str,r,50);
    for(i=0;i<r;i++)
       free(str[i]);
    return 0;
}


void find_first_recurring_letter(char **str,int r,int c)
{
    char *ptr,*sptr,ch[r];
    int indx[r];
    int i;
    for(i=0;i<r;i++)
    {
        indx[i]=0;
        ch[i]='\0';
        for(ptr=&str[i][0];*ptr!='\0';ptr++)
        {
            for(sptr=&ptr[1];*sptr!='\0';sptr++)
            {
                if(*ptr==*sptr)
                    ch[i]= *ptr;
                    indx[i]=1;
            }
        }
    }
    for(i=0;i<r;i++)
    {
        if(ch[i]!='\0')
            printf("'%c' in string %d\n",ch[i],indx[i]+1);
    }

}


506
6
задан 7 февраля 2018 в 09:02 Источник Поделиться
Комментарии
2 ответа

Лучше имена

Имена переменных слишком коротка, чтобы быть значимым. Это часто используется i в качестве индекса в for-петли, но r не расскажите своей цели. Имена number_of_strings само-описательный, поэтому мы должны использовать те.

Неиспользуемые переменные

Мы никогда не используем c в find_first_recurring_letterпоэтому мы должны удалить параметр в целом.

Строго говоря, мы также никогда не использовать indx[i]. Если ch[i] есть '\0',INDX, с[я]will be1(see "always use braces" below), and1` иначе, так что мы можем заменить

        printf("'%c' in string %d\n",ch[i],indx[i]+1);

по

        printf("'%c' in string %d\n", ch[i], 2);

без изменения логики программы.

Проще логика указатель

Вместо ptr = &str[i][0], который ptr = &(*(str[i])) использовать ptr = str[i]. Вместо sptr = &ptr[1]просто используйте sptr = ptr.

Опять же, мы могли бы назвать их current и next или похожие.

Кстати, все indx[i] являются 1 (см. "неиспользуемые переменные" выше и "всегда использовать фигурные скобки" ниже). Это звучит не очень хорошо. Также имейте в виду, что переменная длины массива на заказ по С11.

Избавиться от дополнительной памяти

Если мы printf повторяющийся характер, мы можем избавиться от ch и indx:

            if(*ptr==*sptr)
printf("....");
indx[i]=1;

Всегда используйте фигурные скобки

Обратите внимание, что приведенный выше код содержит ошибку. indx[1] будет установлено 1 независимо от того, *ptr == *sptr. Вмятие сообщают Здесь.

Вы, наверное, добавила indx[i] позже и забыл добавить скобки, так что мы должны всегда использовать фигурные скобки, чтобы убедиться, что ошибки такой не будет.

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

Предпочитаю поздно С99 заявления, если это возможно

Таким образом, мы можем сохранить объем наших переменных короткое, например

for(int i = 0; i < number_of_strings; ++i) {
for(char *current = str[i]; *current != '\0'; current++) {
for(char *next = current + 1; *next != '\0'; next++) {
if(*current == *next) {
printf("'%c' in string %d\n", *current, i);
}
}
}
}

Это теперь невозможно использовать next за пределами своего контура. Кроме того, мы должны попытаться инициализировать переменные, когда это возможно.

Использовать const type* для входов, которые не должны меняться

Таким образом, мы не можем случайно изменить значения входных параметров, например

str[i][k] = '\0'

не будет компилироваться, если str был const char**.

Проверить mallocвозврата

Мы должны действительно проверить malloc возвращает NULL.

Разделение функций

find_first_recurring_letter не следует его название полностью. Мы находим первые повторяющиеся буквы на набор строки на строку основу. Это звучит идеально подходит для раскола:

const char * find_first_recurring_letter(const char * haystack) {
for(const char * current = haystack; *current != '\0'; current++) {
for(const char * next = current + 1; *next != '\0'; next++) {
if(*current == *next) {
return current;
}
}
}
return NULL;
}

void find_first_recurring_letters(const char ** strings, int number_of_strings) {
for(int i = 0; i < number_of_strings; i++) {
const char * result = find_first_recurring_letter(strings[i]);

if(result) {
printf("'%c' in string %d\n", *result, i);
}
}
}

Мы можем теперь использовать find_first_recurring_letter на любом null-завершенной строку. Мы можем повторно использовать функциональность. Обратите внимание, что обе функции очень легко проверить вручную.

10
ответ дан 7 февраля 2018 в 09:02 Источник Поделиться

Ответить @ "Зета" очень хороший, но я хотел бы идти вперед и улучшать код, создав несколько функций для улучшения читабельности:

void allocMemoryForStrings(char** arrayOfStrings, int numOfStrings){
for(int i = 0; i < numOfStrings; i++){
arrayOfStrings[i] = malloc(sizeof(*arrayOfStrings[i]) * 50);
}
}

void printStrings(char** arrayOfStrings, int numOfStrings){
for(int i = 0; i < numOfStrings; i++){
printf("%s\n", arrayOfStrings[i]);
}
}

void freeStrings(char** arrayOfStrings, int numOfStrings){
for(int i = 0; i < numOfStrings; i++){
free(arrayOfStrings[i]);
}
}

С. П.: код может понадобиться некоторые хитрости, чтобы скомпилировать/работы. Использовать ее в качестве справочника.

3
ответ дан 7 февраля 2018 в 01:02 Источник Поделиться