I am trying to take a char *, which represents a single word and i got the char * from a function, and put it into a 2d array but instead it just repeats the first letter of each word several times. the output looks like this
ttttttttttttttttttttttttttttttttvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvoooooooooooooooooooooooooo
and my input file is
three
versions
of
simple
with
spell
check
checking
program
we
will
write
I am not sure how to correctly transfer a char * into a 2d array
here are all the functions i am using
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <ctype.h>
#include "dict.h"
bool is_valid_entry( int strLength, char entry[] ){
if( entry[0] != '"' && !isalpha(entry[0]) && entry[0] != '\'' ){
return false;
}
strLength--; /* to allow for the zero index of the array*/
for ( int i=1; i < strLength; i++ )
if ( !isalpha( entry[i] ) ){
return false;
}
if (!isalpha( entry[strLength] ) && !ispunct( entry[strLength] ) && entry[strLength] != '"' && entry[strLength] != '\'' ){
return false;
}
return true;/* if the entry passes all of the tests the function will return true meaning the the word is valid*/
}/* ends is_valid_entry( int strlength, char entry[] )*/
char * normalize( int strLength, char entry[], char output[] ){
strLength--;/* to allow for the zero index of an array*/
int j = 0;
for( int i = 0;i < strLength; i++){/* converts all of the elements in the entry[] to lower case*/
if (isupper( entry[i] ) ){
entry[i] = tolower( entry[i] );
}
}
if( ( entry[0] == '"' && entry[strLength] == '"' ) || (entry[0] == '\'' && entry[strLength] == '\'' ) ) {
for(int i=1 ; i < strLength ; i++,j++ ){
output[j] = entry[i];
}
output[j] = '\0';/* removes the last character which is either a '"' ir a '\''*/
return output;/* returns the noramlized word*/
}else if( entry[0] == '"' || entry[0] == '\'' ){
for(int i = 1; j < strLength; i++, j++ ){/*i=1 in order to skip the first element in the entry arrary*/
output[j] = entry[i];
}
output[j] = '\0';
return output;/* returns the noramlized word*/
} else if( entry[strLength] == '"' || ispunct( entry[strLength] ) || entry[strLength] == '\''){
for(int i = 0;j < strLength; i++,j++ ){
output[j] = entry[i];
}
output[j] = '\0';
return output;/* returns the noramlized word*/
}
return entry;/* returns the original array since it does not need to be normalized*/
}/* ends normalize( int strlength, char entry[], char output[] )*/
void load_dict(char *fileName, char dictionary[30000][31]) {
FILE *fdict;
fdict = fopen( fileName, "r" );/* file pointer for the dictionary file*/
char *normDictWord;
char normDict [33];
int strLength,i,j,ch;
if ( fdict == NULL ){
fprintf(stderr,"Could not open file: %s\n", fileName );/*checks to make sure the dictionary file can be opened*/
exit(1);
}
for (i = 0; (ch = fgetc( fdict ) ) != EOF; i++ ) {
char word[33] = "";/* resets the array*/
for (strLength = 0; !isspace( ch ) ; strLength++ ){
word[strLength] = ch;
ch = fgetc( fdict );
}
if (is_valid_entry( strLength , word ) ){
normDictWord = normalize( strLength , word , normDict );/*normalize then do the linear search then print the word if it is not found in the dictionary*/
for(j = 0; j <= 31;j++){
dictionary[i][j] = * normDictWord ;
printf("%c",dictionary[i][j]);
}
}
}
fclose( fdict );
}
I cannot completely understand your code, fix formatting, and add some parts that are missing (otherwise I can't test it). However:
dictionary[i][j] = * normDictWord;
should be something like:
dictionary[i][j] = * (normDictWord + j);
or equivalently:
dictionary[i][j] = normDictWord[j] ;
Key problem (#pez)
for (j = 0; j <= 31; j++) {
// dictionary[i][j] = *normDictWord;
dictionary[i][j] = normDictWord[j];
printf("%c", dictionary[i][j]);
}
Some other problems:
Original code will loop endlessly should the EOF condition occur before a space does. isspace(EOF) is false. This loop also does not prevent overrun.
char word[33] = "";
// for (strLength = 0; !isspace(ch); strLength++) {
for (strLength = 0; !isspace(ch) && ch != EOF && strLength < sizeof word; strLength++) {
word[strLength] = ch;
ch = fgetc(fdict);
}
The following does not "converts all of the elements in the entry[] to lower case", only ellements [0 ]... [original_string_length-2]. Maybe code should do strLength--; after the loop.
strLength--;/* to allow for the zero index of an array*/
...
for (int i = 0; i < strLength; i++) {/* */
...
Related
I have the following code (from K&R Exercise 2-4):
#include <stdio.h>
#define MAXLINE 1000 /* maximum input line size */
void squeeze(char s1[], char s2[]);
/* Exercise 2-4. Write an alternate version of squeeze(s1,s2) that deletes each
character in s1 that matches any character in the string s2. */
main()
{
int c, i;
char line[MAXLINE]; /* current input line */
int len = 0; /* current line length */
char s2[MAXLINE]; /* array of characters to delete */
printf("Characters to delete: ");
for (i = 0; (c = getchar()) != '\n'; ++i)
s2[i] = c;
while ((c = getchar()) != EOF) {
if (c == '\n') {
squeeze(line, s2);
printf("%s\n", line);
for (i = 0; i < len; ++i)
line[i] = 0;
len = 0;
} else {
line[len] = c;
++len;
}
}
return 0;
}
/* squeeze: delete all chars in s2 from s1 */
void squeeze(char s1[], char s2[])
{
int i, j, k;
for (k = 0; s2[k] != '\0'; k++) {
for (i = j = 0; s1[i] != '\0'; i++)
if (s1[i] != s2[k])
s1[j++] = s1[i];
s1[j] = '\0';
}
}
But when I run it and it reads in input, I find that there are garbage characters at the end of s2. Adding the following code after declaring the character arrays:
for (i = 0; i < MAXLINE; ++i)
line[i] = s2[i] = 0;
seems to fix the issue. But don't character arrays come initialized with 0 to begin with? Does anyone know why this is happening?
The problem here is your strings are not null terminated. Local variables (like line and s2) are not automatically initialized with 0. Their content is indeterminate.
Declare line and s2 like this:
char line[MAXLINE] = { 0 }; // initializes all elements of line with 0
char s2[MAXLINE] = {0}; // initializes all elements of s2 with 0
or just null terminate line:
...
if (c == '\n') {
line[len] = 0; // <<< add this: null termninate line
squeeze(line, s2);
...
and null terminate s2:
...
printf("Characters to delete: ");
for (i = 0; (c = getchar()) != '\n'; ++i)
s2[i] = c;
s2[i] = 0; // <<< add this: null termninate s2
while ((c = getchar()) != EOF) {
...
For starters according to the C Standard the function main without parameters shall be declared like
int main( void )
As the function squeze accepts two arrays without their length than it means that the arrays contain strings: sequences of characters terminated by zero character '\0'.
As the second array is not changed within the function then the second parameter should be declared with the qualifier const.
The function declaration will look like
char * squeeze( char s1[], const char s2[] );
Within the function you should check at first whether s1 or s2 contains an empty string.
The function definition can look for example the following way
char * squeeze( char s1[], const char s2[] )
{
if ( *s1 != '\0' && *s2 != '\0' )
{
size_t i = 0;
for ( size_t j = 0; s1[j] != '\0'; ++j )
{
size_t k = 0;
while ( s2[k] != '\0' && s2[k] != s1[j] ) ++k;
if ( s2[k] == '\0' )
{
if ( i != j ) s1[i] = s1[j];
++i;
}
}
s1[i] = '\0';
}
return s1;
}
The nested loops within the function
if ( *s1 != '\0' && *s2 != '\0' )
{
size_t i = 0;
for ( size_t j = 0; s1[j] != '\0'; ++j )
{
size_t k = 0;
while ( s2[k] != '\0' && s2[k] != s1[j] ) ++k;
if ( s2[k] == '\0' )
{
if ( i != j ) s1[i] = s1[j];
++i;
}
}
s1[i] = '\0';
}
can be also rewritten the following way
if ( *s1 != '\0' && *s2 != '\0' )
{
size_t i = 0;
for ( size_t j = 0; s1[j] != '\0'; ++j )
{
if ( strchr( s2, s1[j] ) == NULL )
{
if ( i != j ) s1[i] = s1[j];
++i;
}
}
s1[i] = '\0';
}
In main you need to append entered sequence with the terminating zero character as for example
i = 0;
while ( i + 1 < MAXLINE && ( c = getchar() ) != EOF && c != '\n' )
{
s2[i++] = c;
}
s2[i] = '\0';
and
i = 0;
while ( ( c = getchar() ) != EOF )
{
if ( i + 1 == MAXLINE || c == '\n' )
{
line[i] = '\0';
printf( "%s\n", squeeze( line, s2 ) );
i = 0;
}
else
{
line[i++] = c;
}
}
Basically , I am trying to read a text file and store its content to check the balance of the different bracket-type pairs on command-line. But I keep on getting the same output.
The code is intended to detect the following error cases:
The most recent closed bracket does not match the most recent open bracket.
A closed bracket is encountered when there is no open bracket to be matched.
The end of the source code is reached when there is at least one open brackets to be matched.
Main function :
#include <stdio.h>
#include <stdlib.h>
int main (int argc , char* argv[])
{
char *txt = malloc(sizeof(char) * 300);
readfile (argv[1] , txt) ;
brcheck(txt);
free(txt);
return 0;
}
Read Function :
char *readfile (char *s1 , char *t)
{
FILE *f;
int c;
int length = 0;
f = fopen(s1 , "r");
if (f == NULL)
{
perror("Error opening file.txt");
}
else
{
do
{
c = fgetc(f);
txt[length]=c;
length++;
} while (c != EOF && c != '\0');
}
fclose(f);
return txt;
}
Bracket Function :
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
char stack[50];
int top = -1;
void brcheck(char *c)
{
int i= 0;
while (c[i] != EOF)
{
printf("%c" , c[i]);
if (c[i] == '{')
{
stack[++top] = c[i];
if (stack[i] != '}')
{
printf("\n'}' expected\n");
}
else if (stack[i] == '}')
{
top--;
}
}
else if (c[i] == '[')
{
stack[++top] = c[i];
if (stack[i] != ']')
{
printf("\n']' expected\n");
}
else if (stack[i] == ']')
{
top--;
}
}
else if (c[i] == '(')
{
stack[++top] = c[i];
if (stack[i] != ')')
{
printf("\n')' expected\n");
}
else if (stack[i] == ')')
{
top--;
}
}
else if (c[i] == ')')
{
if (stack[top] != '(')
{
printf("\n'(' expected\n");
}
else if (stack[top] == '(')
{
top--;
}
}
else if (c[i] == ']')
{
if (stack[top] != '[')
{
printf("\n'[' expected\n");
}
else if (stack[top] == '[')
{
top--;
}
}
else if (c[i] == '}')
{
if (stack[top] != '{')
{
printf("\n'{' expected\n");
}
else if (stack[top] == '{')
{
top--;
}
}
i++;
}
if (top-= -1)
{
printf("’}’ expected before End of Code\n");
}
}
INPUT FILE : A text file to read file.txt
#include<stdio.h>
int main(int argc , char**argv]
{
printf("this is my program\n");
return 0;
}
What output I am getting is this which is wrong it starts checking for every open bracket but i actually want to check for (] this brackets since it is wrong :
Actual Output :
#include <stdio.h>
int main(
')' expected
)
{
'}' expected
printf(
')' expected
"this is my program\n");
return 0;
}
Expected output:
#include<stdio.h>
int main(int argc , char**argv]
')' expected
{
printf("this is my program\n");
return 0;
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char stack[50];
int top = -1;
char closer(char c){
if (c == '(') return ')';
else return c+2;
}
void brcheck(char *c)
{
int i= 0;
while (c[i] != EOF)
{
printf("%c" , c[i]);
if (c[i] == '<' )
{
stack[++top] = c[i];
}
else if (c[i] == '{')
{
stack[++top] = c[i];
}
else if (c[i] == '[')
{
stack[++top] = c[i];
}
else if (c[i] == '(')
{
stack[++top] = c[i];
}
else if (c[i] == '>')
{
if (stack[top] != '<')
{
printf("\n'%c' expected\n",closer(stack[top]));
}
top--;
}
else if (c[i] == ')')
{
if (stack[top] != '(')
{
printf("\n'%c' expected\n",closer(stack[top]));
}
top--;
}
else if (c[i] == ']')
{
if (stack[top] != '[')
{
printf("\n'%c' expected\n",closer(stack[top]));
}
top--;
}
else if (c[i] == '}')
{
if (stack[top] != '{')
{
printf("\n'%c' expected\n",closer(stack[top]));
}
top--;
}
i++;
}
if (top >= 0)
{
printf("} expected before End of Code\n");
}
printf("%c",stack[top]);
}
char *readfile (char *s1 , char *t)
{
FILE *f;
int c;
int length = 0;
f = fopen(s1 , "r");
if (f == NULL)
{
perror("Error opening file.txt");
}
else
{
do
{
c = fgetc(f);
t[length]=c;
length++;
} while (c != EOF && c != '\0');
}
fclose(f);
return t;
}
int main (int argc , char* argv[])
{
char *txt = malloc(sizeof(char) * 300);
readfile (argv[1] , txt) ;
brcheck(txt);
free(txt);
return 0;
}
You don't have to post each function separately here
Check your read function txt is undefined, it should be t probably
As for your logic, you don't need to check anything for opening brackets. Simply push them in the stack. When a closing bracket is encountered check if top of stack matches it else print what is expected ie the closing bracket for the top of stack. I have written a function (closer for that). Check ASCII values if you need more info on that
You have the right idea using a stack - but it is simpler if on an opening bracket, you push the corresponding expected closing bracket, then on a closing bracket, you pop of the stack and check that it matches the current character.
I would suggest approaching this first by encapsulating the stack and push/pop operations. This need not be elaborate. For example:
typedef struct
{
char stack[128] ;
int index ;
} sCharStack ;
void push_char( sCharStack* stack, char data )
{
if( stack->index < sizeof( stack->stack ) - 2 )
{
stack->index++ ;
stack->stack[stack->index] = data ;
}
}
int pop_char( sCharStack* stack )
{
int pop = -1 ;
if( stack->index > 0 )
{
pop = stack->stack[stack->index] ;
stack->index-- ;
}
return pop ;
}
That makes the rest of the code clearer and less error prone.
Then I would suggest using a data structure containing bracket pairs, so that your brcheck function might have:
static const struct
{
char open ;
char close ;
} brackets[] = {{'{','}'},
{'[',']'},
{'(',')'} } ;
static const int bracket_type_count = sizeof(brackets) /
sizeof(*brackets) ;
sCharStack expected_stack = { {0},0 } ;
That way you avoid a lot of conditional code; you simply iterate through the pairings. You can even easily add new paired-delimiters by only modifying brackets array initialiser (so you can add the <...> you originally had (though that is problematic for C code).
The complete brcheck() might then be:
#include <stdbool.h>
void brcheck( const char* text, int length )
{
static const struct
{
char open ;
char close ;
} brackets[] = {{'{','}'},
{'[',']'},
{'(',')'} } ;
static const int bracket_type_count = sizeof(brackets) /
sizeof(*brackets) ;
sCharStack expected_stack = { {0},0 } ;
int curpos = 0 ;
for( int i = 0; i < length; i++ )
{
char current_char = text[i] ;
// Maintain cursor position
curpos = current_char == '\n' ? 0 : curpos + 1 ;
// Ouput content
printf( "%c", current_char ) ;
// Check for open bracket...
bool open = false ;
for( int b = 0; !open && b < bracket_type_count; b++ )
{
if( current_char == brackets[b].open )
{
open = true ;
// Push expected closing character
push_char( &expected_stack, brackets[b].close ) ;
}
}
// Check for close bracket
bool close = false ;
for( int b = 0; !close && b < bracket_type_count; b++ )
{
if( current_char == brackets[b].close )
{
close = true ;
// Check for mismatch
char expected_char = pop_char( &expected_stack ) ;
if( expected_char != brackets[b].close )
{
printf( "\n%*c\'%c\' expected\n", curpos - 2, ' ', expected_char ) ;
}
}
}
}
// Check for unterminated brackets
if( expected_stack.index != 0 )
{
printf( "\n\'%c\' expected\n", (char)pop_char( &expected_stack) ) ;
}
}
Note also the use of the curpos variable and the %*c printf format specifier to position the error message in the correct location as indicated in your example.
The following test code:
int main()
{
char* text =
"#include <stdio.h>\n\
int main(int argc , char**argv]\n\
{\n\
printf(\"this is my program\\n\");\n\
return 0;\n\
}\n" ;
brcheck( text, strlen( text ) ) ;
return 0 ;
}
Outputs:
#include <stdio.h>
int main(int argc , char**argv]
')' expected
{
printf("this is my program\n");
return 0;
}
Changing the test text to:
char* text =
"#include <stdio.h>\n\
int main(int argc , char**argv]\n\
{\n\
printf(\"this is my program\\n\"};\n\
return 0;\n\
}\n" ;
results in:
#include <stdio.h>
int main(int argc , char**argv]
')' expected
{
printf("this is my program\n"}
')' expected
;
return 0;
}
See that the error message splits the line. It is not clear from your example where the erroneous bracket is at the end of the line whether that is acceptable. It can be fixed, but it gets more complicated, and a line may have multiple mismatches. I suggest in that case you create FIFO buffer of structures containing the expected bracket and the cursor position, then output the errors in FIFO order in separate lines after the a is found and output in text. So for example given:
struct
{
char expected ;
int curpos ;
} errorlist[32] = {{0,0}} ;
static const int errorlist_len = sizeof(errorlist) /
sizeof(*errorlist) ;
int error_count = 0 ;
Instead of immediatly printing the error you'd have:
if( error_count < errorlist_len )
{
errorlist[error_count].expected = expected_char ;
errorlist[error_count].curpos = curpos ;
error_count++ ;
}
then after the close-delimiter check loop:
// Print errors after newline
if( current_char == '\n' )
{
for( int e = 0; e < error_count; e++ )
{
printf( "%*c\'%c\' expected\n", errorlist[e].curpos - 2, ' ', errorlist[e].expected ) ;
}
error_count = 0 ;
}
That solves both the split line issue and multiple errors on one line.
In full:
void brcheck( const char* text, int length )
{
static const struct
{
char open ;
char close ;
} brackets[] = {{'{','}'},
{'[',']'},
{'(',')'} } ;
static const int bracket_type_count = sizeof(brackets) /
sizeof(*brackets) ;
struct
{
char expected ;
int curpos ;
} errorlist[32] = {{0,0}} ;
static const int errorlist_len = sizeof(errorlist) /
sizeof(*errorlist) ;
int error_count = 0 ;
sCharStack expected_stack = { {0},0 } ;
int curpos = 0 ;
for( int i = 0; i < length; i++ )
{
char current_char = text[i] ;
// Maintain cursor position
curpos = current_char == '\n' ? 0 : curpos + 1 ;
// Ouput content
printf( "%c", current_char ) ;
// Check for open bracket...
bool open = false ;
for( int b = 0; !open && b < bracket_type_count; b++ )
{
if( current_char == brackets[b].open )
{
open = true ;
// Push expected closing character
push_char( &expected_stack, brackets[b].close ) ;
}
}
// Check for close bracket
bool close = false ;
for( int b = 0; !close && b < bracket_type_count; b++ )
{
if( current_char == brackets[b].close )
{
close = true ;
// Check for mismatch
char expected_char = pop_char( &expected_stack ) ;
if( expected_char != brackets[b].close )
{
//printf( "\n%*c\'%c\' expected\n", curpos - 2, ' ', expected_char ) ;
if( error_count < errorlist_len )
{
errorlist[error_count].expected = expected_char ;
errorlist[error_count].curpos = curpos ;
error_count++ ;
}
}
}
}
// Print errors after newline
if( current_char == '\n' )
{
for( int e = 0; e < error_count; e++ )
{
printf( "%*c\'%c\' expected\n", errorlist[e].curpos - 2, ' ', errorlist[e].expected ) ;
}
error_count = 0 ;
}
}
// Check for unterminated brackets
if( expected_stack.index != 0 )
{
printf( "\n\'%c\' expected\n", (char)pop_char( &expected_stack) ) ;
}
}
Again with the test code:
#include <stdio.h>
int main(int argc , char**argv]
')' expected
{
printf("this is my program\n"};
')' expected
return 0;
}
See now how the semi-colon at the end of the printf() statment is now on the same line before the error message.
Note that I have added a length parameter - your code attempts to write EOF to the char array and check for that - EOF is however an int not a char - the code may not behave as expected or the same on all platforms.
Further improvements for handling rule (2):
if( errorlist[e].expected < 0 )
{
printf( "%*c\^ unexpected\n", errorlist[e].curpos - 2, ' ') ;
}
else
{
printf( "%*c\'%c\' expected\n", errorlist[e].curpos - 2, ' ', errorlist[e].expected ) ;
}
Also it is not possible for %*c to output zero characters (apparently) so if the error is in the first column, it will be indicated on the second column. You could handle that by outputting spaces in a loop instead. I'll leave that to you.
For a more robust and complete "bracket check" you might have to encode some language semantics for example to ignore delimiters that occur in literal strings or comments for example.
To load a file passed on the command line to a buffer in order to bracket-check it, I suggest the following:
int main (int argc , char* argv[])
{
char txt[300] = {0} ;
FILE* fp = fopen( argv[1], "rt" ) ;
if( fp != NULL )
{
int length = fread( txt, 1, sizeof(txt), fp ) ;
brcheck( txt, length ) ;
}
return 0;
}
Your readfile() function is overcomplex and unsafe (no buffer overrun protection). Moreover there is little need to use malloc() if you are allocating a fixed size array as small as 300 bytes. You might want to determine the actual length of the file and allocate enough to load the whole file, but that is perhaps a different issue. Note also that opening in text mode will correctly handle CR+LF line ends in Windows text files.
I need to check if a given string is a Palindrome or mini-Palindrome.
Palindrome length will be 2 or more, the function need to ignore spaces and ignore the differences of upper and lower alphabet.
if the string is Palindrome the function will transfer the indexes of the start and the end of him and will return 1 else return 0.
example1: "My gym" the function will transfer low=0 high=5 and 1
example2: "I Love ANNA" the function will transfer low=7 high=10 and 1
example3: "I love Pasta" return 0.
Also i can’t use functions from librarys other then string.h stdlib.h stdio.h.
I tried to write like this:
int i;
int size = strlen(str);
i = 0;
while (str[i] != '\0')
{
if (str[i] == ' ')
{
i++;
continue;
}
//-------------------
if (str[i] >= ‘a’ && str[i] <= ‘z’)
str[i] = str[i] - 32;
if (str[size-1] >= ‘a’ && str[size-1] <= ‘z’)
str[size-1] = str[size-1] - 32;
//-------------------
if (str[i] == str[size-1])
{
*low = i;
*high = size-1;
return 1;
}
else
{
size--;
i++;
}
}
return 0;
But it isnt working well, i cant figure how to do it with the example 2
Here goes. Will this help you
#define LOWER(a) (((a) >=' A' && (a) <= 'Z') ? ((a) - 'A' +'a') : (a))
#define MYCMP(a,b) (LOWER(a) == LOWER(b))
int is_palidrome(char *s) {
int start = 0;
int end = strlen(s) - 1;
for (; s[start] // Not end of line
&& end >=0 // Not run over the from of the line
&& start < end // Still not got to the middle
&& MYCMP(s[start], s[end]) == 1; // They are still equal
start++, end--) { //Nowt }
};
return (start >= end);
}
I made a program. It works only if the string contains letters and spaces. You can modify it to work for other characters.
#include <stdio.h>
#include <string.h>
#define SIZE 100
int isPalindrome( char *s, size_t l );
int main() {
char str[SIZE];
size_t i, j, len, pldrm = 0;
fgets(str, SIZE, stdin);
len = strlen(str);
for(i = 0; i < len; i++) if( str[i] != ' ' && !((str[i] >= 'a' && str[i] <= 'z') || (str[i] >= 'A' && str[i] <= 'Z')) ) goto the_end;
for(i = 0; i < len-1; i++) {
if( str[i] != ' ' ) {
for(j = i+1; j < len; j++) {
if( (pldrm = isPalindrome(&str[i], j-i+1)) ) {
str[j+1] = '\0';
goto the_end;
}
}
}
}
the_end:
pldrm ? printf("A palindrome has been found from the position %zu till the position %zu.\n\nThe palindrome is: %s\n", i, j, &str[i]) : puts("No palindromes");
return 0;
}
int isPalindrome( char *s, size_t l )
{
static const char az[26] = "abcdefghijklmnopqrstuvwxyz", AZ[26] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int isPldrm = 1, spc = 0; // used to skip spaces within the palindrome
for(size_t i = 0; i < l/2; i++) {
for(size_t j = 0; j < 26; j++) {
if( s[i] == az[j] || s[i] == AZ[j] ) {
while( s[l-1-i-spc] == ' ' ) ++spc;
if( s[l-1-i-spc] != az[j] && s[l-1-i-spc] != AZ[j] ) {
isPldrm = 0;
goto thats_it;
}
break;
}
}
}
thats_it:
return isPldrm;
}
Also, it finds only the first palindrome in the input. Doesn't check for further palindromes.
I have a problem, my program in C have to find words with N letters, count them and sort them in lexicographical order and save them to an another file. How could I sort the words in alphabetical order?
this is my code:
#include <stdio.h>
#include <conio.h>
#include <ctype.h>
#include <stddef.h>
#include <string.h>
int main()
{
FILE *r, *fp;
char ch[100],t[100];
int n,i,j,x=0;
r=fopen("text.txt","r");
fp=fopen("text2.txt","w");
fgets(ch, 100, r);
char *start;
int len;
char *s = ch;
char *p = s;
printf("Give the length of word: ");
scanf("%d",&n);
printf("\n\nWords with %d letters: \n\n",n);
while (*p) {
while (*p && isspace(*p))
++p;
start = p;
while (*p && !isspace(*p))
++p;
len = p - start;
if (len == n) {
printf("%.*s\n", len, start);
x++;
fprintf(fp,"%.*s",len, start);
}
}
printf("\nNumber of words: %d ",x);
fclose(fp);
getch();
fclose(r);
}
There's a standard library function for sorting:
https://en.wikipedia.org/wiki/Qsort
It's easy to write a function to sort words alphabeticly it is very similar to sorting alphabetic characters.to sort characters you iterate over the array and compare two characters at a time.if the first is greater than the second,you swap them and loop again until finished.In case of words,you have to iterate over strings,and the iterate over their characters to make the necessary swap.Here is a example :
#include <stdio.h>
int s_bubblesort(int argc,char **argv);
int main(void)
{
char *elements[9] = { "zab","aaaa","bac","zzz","abc","cab","aaa","acc","aaaaaaaaa" };
s_bubblesort(9,elements);
for( int n = 0 ; n < 9 ; n++ )
{
printf("%s\n",elements[n]);
}
}
int s_bubblesort(int argc,char **argv)
{
//loop variables
int i,j;
//p_1 : pointer that points to current string,p_2 : pointer that points to next string
char *p_1 , *p_2 , *tmp;
for( j = 0 ; j < argc ; j++ )
{
for( i = 0 ; i < argc - j - 1 ; i++ )
{
//assign p_1 to current string,and p_2 to next string
p_1 = argv[i] , p_2 = argv[i+1];
//while *p_1 != '\0' and *p_2 != '\0'
while( *p_1 && *p_2 )
{
//if *p_1 less than *p_2,break and move to next iteration
if( *p_1 < *p_2 )
break;
else if( *p_1 > *p_2 || ( ! *(p_2 + 1) && ( *p_1 == *p_2 ) && *(p_1+1) ) ) // if *p_1 > *p_2,or *(p_2 + 1 ) == '\0' and *p_1 == *p_2 and *(p_1 + 1 ) != '\0' { SWAP }
{
tmp = argv[i];
argv[i] = argv[i+1];
argv[i+1] = tmp;
break;
}
p_1++;
p_2++;
}
}
}
return 0;
}
I am trying to create a function that takes in word from a file then normalizes it by deleting any punctuation or quotes. The problem I am having is that when I have a word that has " in the front or both the front and back like "how", I get out put like this:
"howw"
howwETX
"well
"wel
How do I stop this from happening?
char *normalize( int count, char entry[], char output[] ){
count--;/* to allow for the zero index of an array*/
if( entry[0] == '"' && entry[count] == '"' ){
for(int i=1 , j=0;j < count - 1; i++,j++ ){
output[j] = entry[i];
}
output[count + 1 ] = '\0';
return output;
}else if( entry[0] == '"' ){
for(int i = 0 , j=0; j < count; i++, j++ ){
output[j] = entry[i];
}
output[count++] = '\0';
return output;
} else if( entry[count] == '"' || ispunct( entry[count] ) ){
for(int i=0 , j=0;i < count; i++,j++ ){
output[j] = entry[i];
}
output[count] = '\0';
return output;
}
return entry;
}/* ends normalize( int count, char entry[], char output[] )*/
Let's play debugger. Suppose your input is this:
entry == "a"
count == 3
We begin executing, and here's what happens:
count == 2
i == 1
j == 0
output[0] == 'a'
The loop exits and then:
output[3] == '\0'
So now output contains aa", which is incorrect. The solution is to set output[count-1] to null when the loop exits, not count + 1.
You are not counting your indices correctly.
In the case where there are quotes front and back, the length of the output string is count - 1, after count has been updated, so you should set output[count - 1] = '\0' rather than output[count + 1] = '\0'. In fact, you may want to decalre j outside your loop and use output[j] since that will be the correct position in the string (in all three cases).
In the case where only the first character is a quote, you should skip the quote: i = 1, not i = 0.
Try the following. At least it is correct and looks simpler.:)
char * normalize( char output[], const char entry[], size_t n )
{
if ( n != 0 && entry[0] == '"' )
{
++entry;
--n;
}
if ( n != 0 && ispunct( entry[n-1] ) )
{
--n;
}
strncpy( output, entry, n );
output[n] = '\0';
return output;
}