2016-10-20 5 views
0

У меня возникла проблема при удалении гласного из связанного списка. Программа принимает аргументы командной строки, объединяет их в одну строку и добавляет каждый символ в связанный список как узел.Не удается удалить гласные из одноуровневого списка

Когда я пытаюсь запустить программу с аргументом командной строки «лимон», успешно удаляет гласные. то есть программа успешно удаляет гласные, если аргумент не содержит последовательных гласных. С другой стороны, если я попытаюсь сделать то же самое с аргументом командной строки «aeiou», программа выйдет из строя с сообщением «Ошибка сегментации» (ядро сбрасывается). Я не понимаю, как это сделать.

Программа не должна создавать глобальные переменные, поэтому я использовал двойной указатель. Все функции работают исправно, эта проблема может возникнуть из-за некоторых ошибок в функции locate() и removeVowels(), но я не могу понять, что это за ошибка.

можно решить эту проблему, используя двойной указатель ?? Я не могу понять, что не так в этой программе. Я новичок в программировании, пожалуйста, помогите мне с этим .. Пожалуйста, исправьте меня .. Заранее спасибо.

Полный код приведен ниже:

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

struct linkedList { 
    char ch; 
    struct linkedList *node; 
}; 
void printMenu(void); 
char* combineWithNoSpaces(int, char *[]); 
void addTolinkedList(char *, struct linkedList **, int *); 
void printLinkedList(struct linkedList **); 
struct linkedList *locate(struct linkedList**); 
int delHead(struct linkedList **); 
void removeVowels(struct linkedList**); 
int isEmpty(struct linkedList **); 

int main(int argc, char *argv[]) { 
    int choice, indexer = 0; 
    struct linkedList *s; 
    char *string; 
    if (argc == 1) { 
     printf("Parse a sentence"); 
    } else { 
     s = (struct linkedList *) malloc(sizeof(struct linkedList)); 
     string = combineWithNoSpaces(argc, argv); 
     addTolinkedList(string, &s, &indexer); 
     while (1) { 
      printMenu(); 
      scanf("%d", &choice); 
      if (choice == 1) { 
       printLinkedList(&s); 
      } else if (choice == 2) { 
       if (!delHead(&s)) 
        printf("Failed.Empty linked list"); 
      } else if (choice == 3) { 
       removeVowels(&s); 

      } else if (choice == 4) { 
       if(isEmpty(&s)){ 
        printf("Empty LinkedList"); 
       } 
       else 
        printf("Not Empty"); 
      } else if (choice == 5) { 
       break; 
      } else 
       printf("Invalic choice"); 
      printf("\n"); 
     } 
    } 
    return 0; 
} 

int isEmpty(struct linkedList **s){ 
    if(*s == NULL) 
     return 1; 
    else 
     return 0; 
} 

struct linkedList *locate(struct linkedList **s) { 
    if ((*s)->node->ch == 'a' || (*s)->node->ch == 'e' || (*s)->node->ch == 'i' 
      || (*s)->node->ch == 'o' || (*s)->node->ch == 'u' 
      || (*s)->node->ch == 'A' || (*s)->node->ch == 'E' 
      || (*s)->node->ch == 'I' || (*s)->node->ch == 'O' 
      || (*s)->node->ch == 'U') { 
     return *s; 
    } else if ((*s)->node->node == NULL) { 
     return NULL; 
    } else 
     return locate(&((*s)->node)); 
} 
void removeVowels(struct linkedList **s) { 
    struct linkedList *temp, *tag; 
    /* Checking whether the first node is null or not */ 
    if ((*s)->ch == 'a' || (*s)->ch == 'e' || (*s)->ch == 'i' 
      || (*s)->ch == 'o' || (*s)->ch == 'u' 
      || (*s)->ch == 'A' || (*s)->ch == 'E' 
      || (*s)->ch == 'I' || (*s)->ch == 'O' 
      || (*s)->ch == 'U') 
     delHead(s); 
    do { 
     tag = locate(s); 
     if (tag != NULL) { 
      temp = tag->node->node; 
      free(tag->node); 
      tag->node = temp; 
     } 

    } while (tag != NULL); 
} 
int delHead(struct linkedList **s) { 
    struct linkedList *temp; 
    if ((*s) == NULL) { 
     return 0; 
    } else { 
     temp = (*s)->node; 
     free(*s); 
     *s = temp; 
     return 1; 
    } 
} 
void printLinkedList(struct linkedList **s) { 
    if ((*s) != NULL) { 
     printf("%c", (*s)->ch); 
     printLinkedList(&(*s)->node); 
    } 
    return; 
} 
void addTolinkedList(char *str, struct linkedList **s, int *indexer) { 
    if (*indexer == strlen(str)) { 
     *s = NULL; 
     return; 
    } else { 
     (*s)->ch = *(str + *indexer); 
     (*s)->node = (struct linkedList *) malloc(sizeof(struct linkedList)); 
     ++*indexer; 
     addTolinkedList(str, &(*s)->node, indexer); 
    } 
} 
char * combineWithNoSpaces(int argc, char *argv[]) { 
    int i, j; 
    int count = 0; 
    int memory = 0; 
    char *str; 
    for (i = 1; i < argc; i++) { 
     for (j = 0; j < strlen(argv[i]); j++) { 
      ++memory; 
     } 
    } 
    str = (char *) malloc(memory * sizeof(char) + 1); 
    for (i = 1; i < argc; i++) { 
     for (j = 0; j < strlen(argv[i]); j++) { 
      *(str + count) = argv[i][j]; 
      ++count; 
     } 
    } 
    return str; 
} 
void printMenu(void) { 
    printf("\n\n" 
      "1. print input arguments (no spaces)\n" 
      "2. remove first character\n" 
      "3. remove vowels\n" 
      "4. is the linked list empty?\n" 
      "5. exit program\n" 
      "Enter your choice>"); 
} 

снимок экрана для вывода является:
Для аргумента лимона argument lemon
Для аргумента AEIOU argument aeiou

+1

Было бы предпочтительнее, если вы покончили с меню и связанного с ним кода и просто показал нам код, который создает списки, удаляет гласные, и печатает результаты - это будет ближе к MCVE ([ MCVE]). Нам не нужно пробираться через код, который не имеет отношения к проблеме. Процесс минимизации также часто решает проблему. –

+0

Прошу прощения, я пытался представить проблему наилучшим образом .. в следующий раз улучшится. – user3213732

+0

Учитесь в следующий раз - это все, что мы просим. Ну, мы спрашиваем. Вы считали функцию 'isvowel()'? Это 5-строчный блок кода, который повторяется; «статическая встроенная функция int isvowel (char c) {...}' улучшит читаемость. –

ответ

1

Этот код работает, к моему удовлетворению , Это больше почти на MCVE (Minimal, Complete, Verifiable Example

Я назвал эту программу rv19 При запуске, как это, это дает результат, показанный:..

$ rv19 apple 
[apple] 
[ppl] 
$ rv19 nutmeg 
[nutmeg] 
[ntmg] 
$ rv19 ply 
[ply] 
[ply] 
$ rv19 aeiou 
[aeiou] 
[] 
$ rv19 aardvark abstemiously facetiously aeiou minions lampoon shampoo 
[aardvarkabstemiouslyfacetiouslyaeiouminionslampoonshampoo] 
[rdvrkbstmslyfctslymnnslmpnshmp] 
$ 

код (rv19.c):

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

struct linkedList 
{ 
    char ch; 
    struct linkedList *node; 
}; 

char *combineWithNoSpaces(int, char *[]); 
void addTolinkedList(char *, struct linkedList **, int *); 
void printLinkedList(struct linkedList **); 
struct linkedList *locate(struct linkedList **); 
int delHead(struct linkedList **); 
void removeVowels(struct linkedList **); 
void freeLinkedList(struct linkedList *); 

int main(int argc, char *argv[]) 
{ 
    int indexer = 0; 
    struct linkedList *s; 
    char *string; 
    if (argc == 1) 
    { 
     printf("Parse a sentence. Usage: %s word [word ...]\n", argv[0]); 
    } 
    else 
    { 
     s = (struct linkedList *) malloc(sizeof(struct linkedList)); 
     printf("s = %p\n", (void *)s); 
     string = combineWithNoSpaces(argc, argv); 
     addTolinkedList(string, &s, &indexer); 
     printLinkedList(&s); 
     removeVowels(&s); 
     printLinkedList(&s); 
     printf("s = %p\n", (void *)s); 
     freeLinkedList(s); 
     free(string); 
    } 
    return 0; 
} 

static inline int isvowel(char c) 
{ 
    return(c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u' || 
      c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U'); 
} 

struct linkedList *locate(struct linkedList **s) 
{ 
    if ((*s)->node == NULL) 
     return NULL; 
    if (isvowel((*s)->node->ch)) 
    { 
     return *s; 
    } 
    else if ((*s)->node == NULL) 
    { 
     return NULL; 
    } 
    else 
     return locate(&((*s)->node)); 
} 

void removeVowels(struct linkedList **s) 
{ 
    struct linkedList *temp, *tag; 
    /* Remove leading vowels */ 
    while ((*s) != NULL && isvowel((*s)->ch)) 
    { 
     //printf("Remove leading '%c'\n", (*s)->ch); 
     struct linkedList *ts = *s; 
     delHead(&ts); 
     *s = ts; 
    } 
    struct linkedList *n = *s; 
    while (n != NULL && (tag = locate(&n)) != NULL) 
    { 
     /* Remove multiple embedded or trailing vowels */ 
     while (tag->node != NULL && isvowel(tag->node->ch)) 
     { 
      temp = tag->node; 
      tag->node = tag->node->node; 
      free(temp); 
     } 
     n = tag->node; 
    } 
} 

int delHead(struct linkedList **s) 
{ 
    struct linkedList *temp; 
    if ((*s) == NULL) 
     return 0; 
    else 
    { 
     temp = (*s)->node; 
     free(*s); 
     *s = temp; 
     return 1; 
    } 
} 

void printLinkedList(struct linkedList **s) 
{ 
    struct linkedList *n = *s; 
    putchar('['); 
    while (n != NULL) 
    { 
     putchar(n->ch); 
     n = n->node; 
    } 
    putchar(']'); 
    putchar('\n'); 
} 

void addTolinkedList(char *str, struct linkedList **s, int *indexer) 
{ 
    if (*indexer == (int)strlen(str)) 
    { 
     free(*s); 
     *s = NULL; 
    } 
    else 
    { 
     (*s)->ch = *(str + *indexer); 
     (*s)->node = (struct linkedList *) malloc(sizeof(struct linkedList)); 
     ++*indexer; 
     addTolinkedList(str, &(*s)->node, indexer); 
    } 
} 

char *combineWithNoSpaces(int argc, char *argv[]) 
{ 
    int argl[argc+1]; 
    int memory = 0; 
    for (int i = 1; i < argc; i++) 
    { 
     argl[i] = strlen(argv[i]); 
     memory += argl[i]; 
    } 
    char *str = (char *) malloc(memory + 1); 
    char *base = str; 
    for (int i = 1; i < argc; i++) 
    { 
     strcpy(base, argv[i]); 
     base += argl[i]; 
    } 
    return str; 
} 

void freeLinkedList(struct linkedList *node) 
{ 
    while (node != NULL) 
    { 
     struct linkedList *next = node->node; 
     free(node); 
     node = next; 
    } 
} 

Это по-прежнему не так отполировано, как могло бы быть. Я изменил печать, чтобы получить маркер перед запуском и после окончания вывода, легче увидеть ненужные пробелы и другие символы, подобные этому. Теперь он итеративный. 'изменить интерфак e для функции тоже, поэтому требуется struct linkedList * вместо struct linkedList **. Код в removeVowels() сложный; он итерации удаляет повторяющиеся начальные гласные; он повторяет удаление повторяющихся гласных после негласного. Функция locate() теперь возвращает указатель на негласный узел, который имеет гласный в следующем узле. Этот код освобождает строку и список (используя новую функцию, freeLinkedList(), чтобы освободить список).

Я проверил его с помощью нескольких отладочных версий malloc(), и, похоже, он не содержит утечек и не имеет коррупции.

я до сих пор не запустить его с valgrind, потому что я не могу заставить его работать должным образом после того, как строить его на MacOS Sierra 10.12:

valgrind: mmap-FIXED(0x0, 253952) failed in UME (load_segment1) with error 12 (Cannot allocate memory). 

Это было с последним кодом, загруженного из SVN (ревизии 16097).

+0

Это сработало отлично .. но я пытаюсь сделать это, не используя assert.h library sir .. – user3213732

+0

(1) 'assert.h' - это заголовок, а не библиотека. (2) Вы можете просто удалить все строки, содержащие 'assert', не изменяя значения или действия программы. –

+0

Я знаю, что вы унаследовали эту логику от OP, но не '' s = NULL; 'в первом разделе' addTolinkedList() 'clobber malloc'd memory из предыдущей рекурсии (и/или' main() '), которые затем не могут быть освобождены? – cdlane

0

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

Несколько основных моментов из многих изменений:

главных: изменили основную структуру управления в switch заявления. Инициализировал указатель linkedList к NULL, а не malloc'd, который вводит пустую строку, приведет к утечке этой памяти addTolinkedList(). Добавлен вызов новой функции freeLinkedList(), когда выбран вариант выхода.

найти: переименован в этот locateVowel() и реструктурирован removeVowel(), чтобы иметь только одно место, которое фактически ищет гласные. Удалена утечка потенциальной памяти.

combWithNoSpaces: переписан это, чтобы быть ориентированным на строку, а не символом.

addTolinkedList: сделал аргумент index (er) простым int, который увеличивается при рекурсии, что упростило ряд проблем.

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

struct linkedList { 
    char ch; 
    struct linkedList *node; 
}; 

void printMenu(void); 
char* combineWithNoSpaces(int, char *[]); 
void addTolinkedList(char *, struct linkedList **, int); 
void printLinkedList(struct linkedList *); 
struct linkedList **locateVowel(struct linkedList **); 
bool delHead(struct linkedList **); 
void removeVowels(struct linkedList **); 
bool isEmpty(struct linkedList *); 
void freeLinkedList(struct linkedList *); 

int main(int argc, char *argv[]) { 
    int choice; 
    char *string; 

    if (argc == 1) { 
     fprintf(stderr, "Enter a sentence\n"); 
     return EXIT_FAILURE; 
    } 

    struct linkedList *s = NULL; 

    string = combineWithNoSpaces(argc, argv); 

    addTolinkedList(string, &s, 0); 

    free(string); 

    while (true) { 
     printMenu(); 
     (void) scanf("%d", &choice); 

     printf("\n"); 

     switch (choice) { 
      case 1: 
       printLinkedList(s); 
       break; 
      case 2: 
       if (!delHead(&s)) { 
        printf("Failed. Empty linked list\n"); 
       } 
       break; 
      case 3: 
       removeVowels(&s); 
       break; 
      case 4: 
       if (isEmpty(s)) { 
        printf("Empty LinkedList\n"); 
       } else { 
        printf("Not Empty\n"); 
       } 
       break; 
      case 5: 
       freeLinkedList(s); 
       return EXIT_SUCCESS; 
      default: 
       printf("Invalid choice\n"); 
     } 
    } 

    return EXIT_SUCCESS; 
} 

bool isEmpty(struct linkedList *s) { 
    return (s == NULL); 
} 

struct linkedList **locateVowel(struct linkedList **s) { 

    if (*s == NULL) { 
     return NULL; 
    } 

    char ch = tolower((*s)->ch); 

    if (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u') { 
     return s; 
    } 

    return locateVowel(&((*s)->node)); 
} 

void removeVowels(struct linkedList **s) { 

    struct linkedList **vowel; 

    while ((vowel = locateVowel(s)) != NULL) { 
     struct linkedList *temporary = (*vowel)->node; 

     if (temporary == NULL) { 
      free(*vowel); // a vowel with nothing following it 
      *vowel = NULL; 
      break; 
     } 

     (*vowel)->ch = temporary->ch; 
     (*vowel)->node = temporary->node; 

     free(temporary); 

     s = vowel; 
    } 
} 

bool delHead(struct linkedList **s) { 

    if (*s == NULL) { 
     return false; 
    } 

    struct linkedList *temporary = (*s)->node; 
    free(*s); 
    *s = temporary; 

    return true; 
} 

void printLinkedList(struct linkedList *s) { 
    printf("\""); 

    while (s != NULL) { 
     printf("%c", s->ch); 
     s = s->node; 
    } 

    printf("\"\n"); 
} 

void addTolinkedList(char *string, struct linkedList **s, int index) { 
    if (index == strlen(string)) { 
     *s = NULL; 
    } else { 
     *s = malloc(sizeof(struct linkedList)); 

     (*s)->ch = string[index]; 
     (*s)->node = NULL; 

     addTolinkedList(string, &(*s)->node, index + 1); 
    } 
} 

char *combineWithNoSpaces(int argc, char *argv[]) { 
    int characters = 0; 

    for (int i = 1; i < argc; i++) { 
     characters += strlen(argv[i]); 
    } 

    char *string = calloc(characters + 1, 1); 

    for (int i = 1; i < argc; i++) { 
     (void) strcat(string, argv[i]); 
    } 

    return string; 
} 

void freeLinkedList(struct linkedList *s) { 
    while (s != NULL) { 

     struct linkedList *temporary = s; 

     s = s->node; 

     free(temporary); 
    } 
} 

void printMenu(void) { 
    printf("\n" 
     "1. print string (no spaces)\n" 
     "2. remove first character\n" 
     "3. remove vowels\n" 
     "4. is the linked list empty?\n" 
     "5. exit program\n" 
     "Enter your choice: "); 
} 
Смежные вопросы