Please review my tutorial

S

Sathyaish

I had recieved an email sometime ago wherein I was asked to write a
function that parsed a given string for the longest pallindrome it
contained and replaced the pallindrome with another string, given as
its second argument. In finding a pallindrome, however, all the
characters were to be considered equal. Therefore, a space, a comma,
or any punctuation for that matter was to be treated like any other
character.

In solving that question, here's what I came up with after a try or
two:

//File R.h
#ifndef __R__
#define __R__
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define MAX_LEN 1000

int ReplacePallindromes(char**, char*);
int Replace(char**, const int, const int, const
char*);
char* SubString(char*, const int, const int);
void Reverse(char*);

enum MatchTypes
{
None=0,
OddLength=1,
EvenLength=2
};

#endif



//File Globals.h
#include "R.h"

int ReplacePallindromes(char **InStr, char
*ReplaceWith)
{

int Len, LenReplaceWith, MatchFound, LastReplacement;

int Counter;
int ReverseCounter;
int SomeCounter;
int SomeOtherCounter;

char* SubStr1;
char* SubStr2;

LastReplacement=-100;
SubStr1=SubStr2=NULL;
MatchFound=0;

if (*InStr==NULL || ReplaceWith==NULL) return -1;
if (*ReplaceWith==0) return -1;
LenReplaceWith=strlen(ReplaceWith);
Len=strlen(*InStr);
if (Len<2) return -1;

Counter=ReverseCounter=SomeCounter=SomeOtherCounter=0;

for(Counter=0; Counter<Len; Counter++)
{


NextCharFromFront:
for(ReverseCounter=Len-1; ReverseCounter>Counter;
ReverseCounter--)
{
if (*((*InStr)+Counter) == *((*InStr)+ReverseCounter))
{
MatchFound=1;
for(SomeCounter=1, SomeOtherCounter=ReverseCounter-1;
Counter+SomeCounter<=SomeOtherCounter; SomeCounter++,
SomeOtherCounter--)
{
SubStr1=SubString(*InStr, Counter,
Counter+SomeCounter);

SubStr2=SubString(*InStr, SomeOtherCounter,
ReverseCounter);
Reverse(SubStr2);

MatchFound=((strcmp(SubStr1, SubStr2)==0)? 1:0);
if (MatchFound==0)
{
free(SubStr1);
free(SubStr2);
break;
}

free(SubStr1);
free(SubStr2);
}//End of SomeCounter for loop

if(MatchFound==1 && Counter+SomeCounter>=SomeOtherCounter)
{
//This is the largest pallindrome, replace it
LastReplacement=Replace(InStr, Counter,
ReverseCounter, ReplaceWith);
Len=strlen(*InStr);
Counter=LastReplacement+1;
goto NextCharFromFront;
}
}//End of if InStr[Counter] == InStr[ReverseCounter]
}//End of ReverseCounter for loop
}// End of Counter for loop


return 0;

} //end of function



int Replace(char **InStr, const int From,
const int To, const char *ReplaceWith)
{

char* NewString;
int LenReplaceWith, Counter, k, Len;

if(*InStr==NULL || ReplaceWith==NULL) return -1;
Len=strlen(*InStr);
LenReplaceWith=strlen(ReplaceWith);


NewString=NULL;

NewString=(char*)malloc(sizeof(char)*(Len-(To-From+1)+LenReplaceWith+1));
for(Counter=0;
Counter<(Len-(To-From+1)+LenReplaceWith+1); Counter++)
*(NewString+Counter)=0;

for(Counter=0;Counter<=From-1;Counter++)
*(NewString+Counter)=*((*InStr)+Counter);

for(Counter=0;Counter<LenReplaceWith; Counter++)
*(NewString+From+Counter)=*(ReplaceWith+Counter);

for(Counter=To+1, k=0; Counter<Len; Counter++, k++)
*(NewString+From+LenReplaceWith+k)=*((*InStr)+Counter);

*(NewString+From+LenReplaceWith+k)=0;

free(*InStr);
Len=strlen(NewString);
*InStr=(char*)malloc(sizeof(char)*(Len+1));
if((*InStr)==NULL) return -1;
strcpy(*InStr, NewString);
free(NewString);

return (From-1+LenReplaceWith);

}


char* SubString(char* Source, const int From, const
To)
{

int Len, Counter;
char *NewString;
Len=strlen(Source);
if(Source==NULL) return NULL;
if (From<0) return NULL;
if (From>To) return NULL;
if ((From>Len) || (To>Len)) return NULL;
NewString=(char*)malloc(sizeof(char)*(To-From+2));
for(Counter=From; Counter<=To; Counter++)
{
*(NewString+Counter-From)=*(Source+Counter);
}
NewString[Counter-From]=0;
return NewString;
}

void Reverse(char* Str)
{
int i, j, len;
char temp;
i=j=len=temp=0;

if(Str!=NULL)
{
len=strlen(Str);
for (i=0, j=len-1; i<=j; i++, j--)
{
temp=Str;
Str=Str[j];
Str[j]=temp;
}
}
}


//File R.C
#include "R.h"

int main(void)
{

char c, *InStr, *ReplaceWith;
int i;


c=' ';
i=0;

InStr=(char*)malloc(sizeof(char)*(MAX_LEN+1));
if(InStr==NULL) return -1;
ReplaceWith=(char*)malloc(sizeof(char)*(MAX_LEN+1));
if(ReplaceWith==NULL) return -1;

printf("\nEnter a string (1000 characters maximum):");
while(((c=getchar())!=EOF) && (c!='\n') & (i<=MAX_LEN)) InStr[i++]=c;
InStr=0;

c=' ';
i=0;
printf("\n\nEnter the string that you wish to replace\npallindromes
with (1000 characters maximum): ");
while(((c=getchar())!=EOF) && (c!='\n') & (i<=MAX_LEN))
ReplaceWith[i++]=c;
ReplaceWith=0;


if(ReplacePallindromes(&InStr, ReplaceWith)==0)
{
printf("\nThe modified string is:\n\n %s\n", InStr);
}
else
{
printf("An error occured. The program will now end.");
free(InStr);
free(ReplaceWith);
return -1;
}

free(InStr);
free(ReplaceWith);
return 0;
}


I was asked as to why I'd taken a pointer to a pointer as the first
argument of the ReplacePallindrome function. I thought I'd write a
tutorial to explain this thing that I'd arrived at by heuristic
endeavours in the past, when I practiced pointers. So here's a
tutorial I've written. Even at the risk of being laughed at, I present
it to all of you learned people out here, so you may review it,
because, with a few refinements, I intend to get it published if it is
all ok. I am only learning C and thus have written only what I've
coded and tested with my own hands. Please give me your comments as to
how good or bad it is.

http://sathyaishc.tripod.com/Tutorial.doc

(You have to do a right-click and say "Save As" or "Save Target As")

Thanks!
 
A

AngleWyrm

Sathyaish said:
In finding a pallindrome, however, all the
characters were to be considered equal. Therefore, a space, a comma,
or any punctuation for that matter was to be treated like any other
character.

Could you clarify this part? Do you mean that only alphabetic characters {a..z},
ignoring case, will be considered for comparison? Does the end product require
the original non-alphabetical characters?
 
A

AngleWyrm

Does the string "ab!c AB;C 123cba" contain the pallindrome "abccba", and if so,
what string should be returned?
 
A

ahri

Sathyaish scripsit:
I had recieved an email sometime ago wherein I was asked to write a
function that parsed a given string for the longest pallindrome it
contained and replaced the pallindrome with another string, given as
its second argument. In finding a pallindrome, however, all the
characters were to be considered equal. Therefore, a space, a comma,
or any punctuation for that matter was to be treated like any other
character.

What if palindom's length is 7 and replace_string's is 3?
 
W

Willem

Sathyaish wrote:
) I had recieved an email sometime ago wherein I was asked to write a
) function that parsed a given string for the longest pallindrome it
) contained and replaced the pallindrome with another string, given as
) its second argument. In finding a pallindrome, however, all the
) characters were to be considered equal. Therefore, a space, a comma,
) or any punctuation for that matter was to be treated like any other
) character.
)
) In solving that question, here's what I came up with after a try or
) two:

I don't know if it works or not, but it looks horrendously inefficient.
You're copying strings lots of times when that's completely unneccesary,
and why do you write a function to reverse a string, instead of just
writing a function that compares a string with another reversed one ?
Also, why do you have such long, yet non-descriptive names for your
variables ? That's the worst of both worlds, in my opinion.

) I was asked as to why I'd taken a pointer to a pointer as the first
) argument of the ReplacePallindrome function.

Well, that's one of the few things I would not ask about, given that that
is actually a reasonably good thing to do, although returning a char
pointer would also work, you can simply flag failure by returning NULL.
That's how most of the libc functions work.

I see you wrote a 22-page tutorial explaining why you need to pass a double
pointer if you want to be able to reallocate a string, which IMO you can
easily explain in half a page.

P.S. Asking the actual question (on reviewing the tutorial) at the very
end, after a block of code of questionable quality is not the way to get
answers to that question.


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
T

Thad Smith

AngleWyrm said:
Could you clarify this part? Do you mean that only alphabetic characters {a..z},
ignoring case, will be considered for comparison?

I interpret that statement as "all characters will be treated
equally", meaning that alphabetic characters have no special
significance, as opposed to the normal case of palindromic
sentences/phrases. Left unsaid is whether case is significant, but
the implication of "like any other character" is that every character
is unique, so "a" and "A" would be distinct.

Thad
 
J

James Dennett

Sathyaish said:
I had recieved an email sometime ago wherein I was asked to write a
function that parsed a given string for the longest pallindrome it
contained and replaced the pallindrome with another string, given as
its second argument. In finding a pallindrome, however, all the
characters were to be considered equal. Therefore, a space, a comma,
or any punctuation for that matter was to be treated like any other
character.

In solving that question, here's what I came up with after a try or
two:

//File R.h
#ifndef __R__

Stop right here :)

The rules of C say that you must not use names including
double underscores (__) in your own code, for macro names
or identifiers -- they are reserved for use only by people
implementing C (or C++) translators.

I know that this isn't the response you were looking for
(hopefully others will cover other angles), but it's a
simple thing to get right.

-- James
 
P

pete

James said:
Stop right here :)

The rules of C say that you must not use names including
double underscores (__) in your own code, for macro names
or identifiers -- they are reserved for use only by people
implementing C (or C++) translators.

I know that this isn't the response you were looking for
(hopefully others will cover other angles), but it's a
simple thing to get right.

That's a common neophyte mistake which I believe results from
the neophyte reading header files, in order to try to learn C.

Header files use the underscore naming convention
because the programmer is supposed to know that he's
not supposed to do that also.
 
S

Sathyaish

Could you clarify this part? Do you mean that only alphabetic
characters {a..z}, ignoring case, will be considered for comparison?

No, Angle! I did not mean only alphabetic characters would be
considered for comparison. What I meant was that all the characters
that had text symbol representation on the keyboard, were to be
considered equal. So, all alphabets, numbers, symbols, space, tabs,
punctuation are to be considered for comparison, and we are not to
look for palindrome "words" but occurances of larger outermost
palindromes in a given string.

It is not as straight-forward as it sounds. The question is to find
all the occurances of the longest pallindromes in a given string and
replace each occurance with a given word. However, all characters are
to be treated equally. So, in the string,

mom and dad went to the party

there would be three pallindromes:
mom
[space]dad[space]
t[space]t (between went and to)


Similarly the string,

,,,, malayalam ,,,,

would all be one single occurance of a pallindrome.



If it was only to find out palindrome "words" and replace them, the
code would be straight-forward:

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


#define INSIDE_WORD 1
#define OUTSIDE_WORD 0

#define MAX_LEN_STRING 1000
#define MAX_LEN_WORD 50

enum CaseSensitivity
{
CaseSensitive=0,
CaseInSensitive=1
};


int IsPallindrome(const char*, enum CaseSensitivity);
int Replace(char**, const unsigned int, const unsigned int, const
char*);


int main(void)
{


char *Str, *ReplaceWith, *NextWord, NextChar;
int Len, State, Position, WordLen, LenSubstitute;


Str=(char*)malloc((MAX_LEN_STRING+1)*sizeof(char));
if (Str==NULL) return -1;
printf("Enter a string (1000 characters maximum): ");
gets(Str);
if (Str==NULL) return -1;

Len=strlen(Str);
if (Len==0) return -1;

ReplaceWith=(char*)malloc(sizeof(char)*(MAX_LEN_WORD+1));
if (ReplaceWith==NULL) return -1;

printf("Enter the string you want to replace \nthe pallindrome
occurences with (50 characters maximum): ");
gets(ReplaceWith);
if (ReplaceWith==NULL) return -1;

LenSubstitute=strlen(ReplaceWith);
if (LenSubstitute==0) return -1;

State=OUTSIDE_WORD;
NextChar=0;
Position=0;
WordLen=0;
NextWord=malloc((MAX_LEN_WORD+1)*sizeof(char));
do
{
NextChar=*(Str+Position);

if (isspace((int)NextChar) || NextChar==',' || NextChar=='.'
|| NextChar=='?')
{

State=OUTSIDE_WORD;
CheckWordLength:
if(WordLen>1)
{
*(NextWord+WordLen)=0;
if (IsPallindrome(NextWord, CaseSensitive))
{
if (Replace(&Str,Position-WordLen,WordLen,
ReplaceWith)==0)
{
Position+=(LenSubstitute-WordLen);
Len+=(LenSubstitute-WordLen);
}
else
{
printf("There was an error. The program will
now quit.");
return -1;
}
}
}
*NextWord=0;
WordLen=0;
free(NextWord);
NextWord=malloc((MAX_LEN_WORD+1)*sizeof(char));
if (NextWord==NULL)
{
printf("Out of memory.");
return -1;
}
Position++;
}
else
{
*(NextWord+(WordLen++))=NextChar;
State=INSIDE_WORD;
Position++;
if (Position==Len)
goto CheckWordLength;
}

}while(Position<Len);

system("cls");
printf("The modified string is: \n\n%s\n\n", Str);

free(Str);
return 0;
}

int Replace(char** InStr,
const unsigned int AtPosition,
const unsigned int NumChars,
const char* ReplaceWith)
{

char* NewStr;
unsigned int i=0; unsigned int Len=0; unsigned int j=0;


if (*InStr==NULL || ReplaceWith==NULL) return -1;
if (AtPosition<0) return -1;
Len=strlen(*InStr);
if (AtPosition+NumChars > Len) return -1;

NewStr=malloc((Len-NumChars+strlen(ReplaceWith)+1)* sizeof(char));
if (NewStr==NULL) return -1;

strncpy(NewStr,*InStr,AtPosition);
for(i=0; i<strlen(ReplaceWith); i++)
*(NewStr+AtPosition+i)=*(ReplaceWith+i);

for(i=AtPosition+strlen(ReplaceWith), j=0;
i<Len+(strlen(ReplaceWith)-NumChars); i++,j++)
*(NewStr+i)=*(*InStr+AtPosition+NumChars+j);
*(NewStr+i)=0;

free(*InStr);
*InStr=malloc(sizeof(char)*(strlen(NewStr)+1));
strcpy(*InStr,NewStr);
free(NewStr);

return 0;
}

int IsPallindrome(const char* Str, enum CaseSensitivity Sensitivity)
{

int i, j, len;
i=j=len=0;

if (Str==NULL) return 0;
if ((len=strlen(Str))==0) return 0;
if (Sensitivity!=CaseSensitive && Sensitivity!=CaseInSensitive)
Sensitivity=CaseSensitive;

for(i=0, j=len-1; i<=j; i++, j--)
if (Sensitivity==CaseSensitive)
{
if(*(Str+i) != *(Str+j))
return 0;
}
else
{
if(toupper(*(Str+i)) != toupper(*(Str+j)))
return 0;
}

return 1;
}


But it isn't this. The question is to replace all occurances of the
longest palindromes of non-trivial length (>1 char) in a user input
string and replace each occurance with another string.

Again, Willem I think, is going to get mad at my naming convention and
sloppy code. I agree that code is sloppy. But that tutorial is not
about explaining that code.


Does the string "ab!c AB;C 123cba" contain the pallindrome "abccba",
and if so, what string should be returned?

No, Angle. The string "ab!c AB;C 123cba" does not contain the
palindrome "abccba".

Also, the search is to be case-sensitive. So, "dad" will be a
palindrome, whereas "Dad" will NOT be a palindrome.


Left unsaid is whether case is significant, but the implication of
"like any other character" is that every character is unique, so "a"
and "A" would be distinct.

The comparison is to be case-sensitive, Thad.


What if palindom's length is 7 and replace_string's is 3?

Ahri, the comparison of the lengths of the replacement text with the
length of the string that is to be replaced does not matter. You could
have any string that the user wishes to replace in place of
palindromes.

For instance, the original string may be,

"corrocor moonoomdd ddmoonoom"

And the palindromes in the string may be asked to be replaced with a
string entered by the user of any length, greater or lesser in length
than the length of any palindrome occurance. So, if the string to be
replaced be "cool" the new text should be:

"coolor cool"

because "corroc" is the first palindrome occurance. And while
moonooomdd is in intself a palindrome, however, the outermost
palindrome "moonoomdd ddmoonomm" contains it. Hence, only the
outermost palindrome is to be replaced.

I see you wrote a 22-page tutorial explaining why you need to pass a
double pointer if you want to be able to reallocate a string, which
IMO you can easily explain in half a page.

I agree with you, Willem. I wrote it for a friend who is also new and
is learning C on his own, like I am. So, it is quite condescending.

Thank you all for taking the time to read, and for offering your most
valuable inputs.
 
F

Francis Glassborow

James Dennett said:
Stop right here :)

The rules of C say that you must not use names including
double underscores (__) in your own code, for macro names
or identifiers -- they are reserved for use only by people
implementing C (or C++) translators.

Not quite, the rules of C say that a leading double underscore is
reserved for implementers. Only C++ reserves all uses. Of course those
wanting to ensure their C code ports to a C++ compiler will use the more
restrictive rule.
 
C

CBFalconer

pete said:
That's a common neophyte mistake which I believe results from
the neophyte reading header files, in order to try to learn C.

Header files use the underscore naming convention
because the programmer is supposed to know that he's
not supposed to do that also.

No, _system_ header files use it, because they are part of the
system and must not interfere with the users name space.
 
M

Michael Mendelsohn

Sathyaish said:
For instance, the original string may be,

"corrocor moonoomdd ddmoonoom"

And the palindromes in the string may be asked to be replaced with a
string entered by the user of any length, greater or lesser in length
than the length of any palindrome occurance. So, if the string to be
replaced be "cool" the new text should be:

"coolor cool"

because "corroc" is the first palindrome occurance. And while
moonooomdd is in intself a palindrome, however, the outermost
palindrome "moonoomdd ddmoonomm" contains it. Hence, only the
outermost palindrome is to be replaced.


What does your program do with "mamoomum" or, replacing palindrome with
"cool", "mamoockkkk"? I think the problem specification leaves sth. to
be desired.

Michael
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,817
Latest member
DicWeils

Latest Threads

Top