问题
I am having an issue while deleting the vowel from a linked List. The program accept command line arguments, combines them in a single string and add each character to a linked list as node.
When i try to run the program with command line argument "lemon", the successfully deletes the vowels. i.e the program deletes the vowels successfully if the argument doesn't contain consequetive vowels. On the other hand, if i try to do the same with command line argument "aeiou", the program crashes with message Segmentation fault(core dumped).. I am not getting any idea how to handle this..
The program must not create any global variables so i've used double pointer. All the functions are working properly this problem may have occured due to some mistakes in locate() and removeVowels() function but i cannot figure out what the mistake is.
can this problem be solved using double pointer?? I cannot figure out what is wrong in this program.. I am new to c programming, please help me with this.. Please rectify me.. Thanks in advance.
The complete code is given below:
#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>");
}
The screen shot for output is :
For argument lemon
For argument aeiou
回答1:
This code works to my satisfaction. It is more nearly an MCVE (Minimal, Complete, Verifiable Example.
I called the program rv19
. When run like this, it gives the output shown:
$ 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]
$
The code (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;
}
}
This is still not as polished as it could be. I changed the printing so as to get a marker before the start and after the end of the output; it is easier to see unwanted blanks and other characters like that. It's now iterative. I'd change the interface to the function, too, so it takes a struct linkedList *
instead of a struct linkedList **
. The code in removeVowels()
is tricky; it iterates to remove repeated initial vowels; it iterates to remove repeated vowels after a non-vowel. The locate()
function now returns a pointer to a non-vowel node that has a vowel in the next node. This code frees both the string and the list (using a new function, freeLinkedList()
to free the list).
I've checked it with a couple of debugging versions of malloc()
, and it seems to be leak free and corruption free.
I still haven't run it with valgrind because I can't get it to run properly after building it on macOS Sierra 10.12:
valgrind: mmap-FIXED(0x0, 253952) failed in UME (load_segment1) with error 12 (Cannot allocate memory).
This was with the latest code downloaded from SVN (revision 16097).
回答2:
I tried to simplify all the functions -- some were taking (pointers to) pointers as arguments when they needn't do so.
A few highlights of the many changes:
main: changed the main control structure to a switch
statement. Initialized the linkedList pointer to NULL instead of a malloc'd one as entering an empty string would cause addTolinkedList()
to leak this memory. Added a call to new function freeLinkedList()
when the exit option is selected.
locate: renamed this locateVowel()
and restructured with removeVowel()
to have only one place that actually looks for vowels. Removed potential memory leak.
combineWithNoSpaces: rewrote this to be string oriented instead of character oriented.
addTolinkedList: made the index(er) argument a simple int that gets incremented on recursion which simplified a number of issues.
#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: ");
}
来源:https://stackoverflow.com/questions/40166045/cannot-delete-vowels-from-singly-linked-list