Use scanf instead of fgets and fputs in my program in C? - c

#include <stdio.h>
#include <ctype.h>
int isPalindrome( char *str, int length )
{
if ( length < 1 )
{
return 1; /* no more chars to compare, its a palindrome */
}
if ( str[0] == str[length-1] ) /* Are the two ends same? */
{
return isPalindrome( str+1, length-2 ); /* continue checking */
}
else
{
return 0; /* comparison failed, not a palindrome */
}
}
void strToUpper( char *src )
{
/* convet to upper case any letter */
while( ( *src = toupper( *src ) ) != '\0' )
{
++src;
}
}
int main( void )
{
int result = 0;
char str[40] = { '\0' };
printf( "Please type the string to identify Palindrom or not: ", stdout );
fflush( stdout );
fgets( str, sizeof str, stdin );
strToUpper( str ); /* make all letters the same for comparison */
result = isPalindrome( str, ( strlen( str ) - 1 ) ); /* recursive starts here */
if( result == 1 )
{
printf( "1" );
}
else
{
printf( "0" );
}
getchar();
return 0;
}
I wrote this code which identifies palidromes in C, but I want to use scanf instead of fputs or fgets, so I can understand the other way to solve this problem.

There is no fputs and only a single call to fgets in this code.
The method of input here really don't affect "way to solve this problem". It's the same code - changing one line won't change lot. scanf not a safe function. You can do scanf("%s", str) but fgets is better and recommended. If you need to analyze string after fgets, you can use sscanf.

Related

Using fgets and strtok() to read a text file -C

I’m trying to read text from stdin line by line using fgets() and store the text in a variable “text”. However, when I use strtok() to split the words, it only works for a couple lines before terminating. What should I change to make it run through the entire text?
#define WORD_BUFFER_SIZE 50
#define TEXT_SIZE 200
int main(void) {
char stopWords[TEXT_SIZE][WORD_BUFFER_SIZE];
char word[WORD_BUFFER_SIZE];
int numberOfWords = 0;
while(scanf("%s", word) == 1){
if (strcmp(word, "====") == 0){
break;
}
strcpy(stopWords[numberOfWords], word);
numberOfWords++;
}
char *buffer = malloc(sizeof(WORD_BUFFER_SIZE)*TEXT_SIZE);
char *text = malloc(sizeof(WORD_BUFFER_SIZE)*TEXT_SIZE);
while(fgets(buffer, WORD_BUFFER_SIZE*TEXT_SIZE, stdin) != NULL){
strcat(text, buffer);
}
char *k;
k = strtok(text, " ");
while (k != NULL) {
printf("%s\n", k);
k = strtok(NULL, " ");
}
}
char *buffer = malloc(sizeof(WORD_BUFFER_SIZE)*TEXT_SIZE);
char *text = malloc(sizeof(WORD_BUFFER_SIZE)*TEXT_SIZE);
sizeof(WORD_BUFFER_SIZE) is a constant, it's the size of integer. You probably mean WORD_BUFFER_SIZE * TEXT_SIZE. But you can find the file size and calculate exactly how much memory you need.
char *text = malloc(...)
strcat(text, buffer);
text is not initialized and doesn't have a null-terminator. strcat needs to know the end of text. You have to set text[0] = '\0' before using strcat (it's not like strcpy)
int main(void)
{
fseek(stdin, 0, SEEK_END);
size_t filesize = ftell(stdin);
rewind(stdin);
if (filesize == 0)
{ printf("not using a file!\n"); return 0; }
char word[1000] = { 0 };
//while (scanf("%s", word) != 1)
// if (strcmp(word, "====") == 0)
// break;
char* text = malloc(filesize + 1);
if (!text)
return 0;
text[0] = '\0';
while (fgets(word, sizeof(word), stdin) != NULL)
strcat(text, word);
char* k;
k = strtok(text, " ");
while (k != NULL)
{
printf("%s\n", k);
k = strtok(NULL, " ");
}
return 0;
}
According to the information you provided in the comments section, the input text is longer than 800 bytes.
However, in the line
char *text = malloc(sizeof(WORD_BUFFER_SIZE)*TEXT_SIZE);
which is equivalent to
char *text = malloc(800);
you only allocated 800 bytes as storage for text. Therefore, you did not allocate sufficient space to store the entire input into text. Attempting to store more than 800 bytes will result in a buffer overflow, which invokes undefined behavior.
If you want to store the entire input into text, then you must ensure that it is large enough.
However, this is probably not necessary. Depending on your requirements, it is probably sufficient to process one line at a time, like this:
while( fgets( buffer, sizeof buffer, stdin ) != NULL )
{
char *k = strtok( buffer, " " );
while ( k != NULL )
{
printf( "%s\n", k );
k = strtok( NULL, " " );
}
}
In that case, you do not need the array text. You only need the array buffer for storing the current contents of the line.
Since you did not provide any sample input, I cannot test the code above.
EDIT: Based on your comments to this answer, it seems that your main problem is how to read in all of the input from stdin and store it as a string, when you do not know the length of the input in advance.
One common solution is to allocate an initial buffer, and to double its size every time it gets full. You can use the function realloc for this:
#include <stdio.h>
#include <stdlib.h>
int main( void )
{
char *buffer;
size_t buffer_size = 1024;
size_t input_size = 0;
//allocate initial buffer
buffer = malloc( buffer_size );
if ( buffer == NULL )
{
fprintf( stderr, "allocation error!\n" );
exit( EXIT_FAILURE );
}
//continuously fill the buffer with input, and
//grow buffer as necessary
for (;;) //infinite loop, equivalent to while(1)
{
//we must leave room for the terminating null character
size_t to_read = buffer_size - input_size - 1;
size_t ret;
ret = fread( buffer + input_size, 1, to_read, stdin );
input_size += ret;
if ( ret != to_read )
{
//we have finished reading from input
break;
}
//buffer was filled entirely (except for the space
//reserved for the terminating null character), so
//we must grow the buffer
{
void *temp;
buffer_size *= 2;
temp = realloc( buffer, buffer_size );
if ( temp == NULL )
{
fprintf( stderr, "allocation error!\n" );
exit( EXIT_FAILURE );
}
buffer = temp;
}
}
//make sure that `fread` did not fail end due to
//error (it should only end due to end-of-file)
if ( ferror(stdin) )
{
fprintf( stderr, "input error!\n" );
exit( EXIT_FAILURE );
}
//add terminating null character
buffer[input_size++] = '\0';
//shrink buffer to required size
{
void *temp;
temp = realloc( buffer, input_size );
if ( temp == NULL )
{
fprintf( stderr, "allocation error!\n" );
exit( EXIT_FAILURE );
}
buffer = temp;
}
//the entire contents is now stored in "buffer" as a
//string, and can be printed
printf( "contents of buffer:\n%s\n", buffer );
free( buffer );
}
The code above assumes that the input will be terminated by an end of file condition, which is probably the case if the input is piped from a file.
On second thought, instead of having one large string for the whole file, as you are doing in your code, you may rather want an array of char* to the individual strings, each representing a line, so that for example lines[0] will be the string of the first line, lines[1] will be the string of the second line. That way, you can easily use strstr to find the " ==== " deliminator and strchr on each individual line to find the individual words, and still have all the lines in memory for further processing.
I don't recommend that you use strtok in this case, because that function is destructive in the sense that it modifies the string, by replacing the deliminators with null characters. If you require the strings for further processing, as you stated in the comments section, then this is probably not what you want. That is why I recommend that you use strchr instead.
If a reasonable maximum number of lines is known at compile-time, then the solution is rather easy:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LINE_LENGTH 1024
#define MAX_LINES 1024
int main( void )
{
char *lines[MAX_LINES];
int num_lines = 0;
char buffer[MAX_LINE_LENGTH];
//read one line per loop iteration
while ( fgets( buffer, sizeof buffer, stdin ) != NULL )
{
int line_length = strlen( buffer );
//verify that entire line was read in
if ( buffer[line_length-1] != '\n' )
{
//treat end-of file as equivalent to newline character
if ( !feof( stdin ) )
{
fprintf( stderr, "input line exceeds maximum line length!\n" );
exit( EXIT_FAILURE );
}
}
else
{
//remove newline character from string
buffer[--line_length] = '\0';
}
//allocate memory for new string and add to array
lines[num_lines] = malloc( line_length + 1 );
//verify that "malloc" succeeded
if ( lines[num_lines] == NULL )
{
fprintf( stderr, "allocation error!\n" );
exit( EXIT_FAILURE );
}
//copy line to newly allocated buffer
strcpy( lines[num_lines], buffer );
//increment counter
num_lines++;
}
//All input lines have now been successfully read in, so
//we can now do something with them.
//handle one line per loop iteration
for ( int i = 0; i < num_lines; i++ )
{
char *p, *q;
//attempt to find the " ==== " marker
p = strstr( lines[i], " ==== " );
if ( p == NULL )
{
printf( "Warning: skipping line because unable to find \" ==== \".\n" );
continue;
}
//skip the " ==== " marker
p += 6;
//split tokens on remainder of line using "strchr"
while ( ( q = strchr( p, ' ') ) != NULL )
{
printf( "found token: %.*s\n", (int)(q-p), p );
p = q + 1;
}
//output last token
printf( "found token: %s\n", p );
}
//cleanup allocated memory
for ( int i = 0; i < num_lines; i++ )
{
free( lines[i] );
}
}
When running the program above with the following input
first line before deliminator ==== first line after deliminator
second line before deliminator ==== second line after deliminator
it has the following output:
found token: first
found token: line
found token: after
found token: deliminator
found token: second
found token: line
found token: after
found token: deliminator
If, however, there is no reasonable maximum number of lines known at compile-time, then the array lines will also have to be designed to grow in a similar way as buffer in the previous program. The same applies for the maximum line length.

Strlwr function - getting an error in xcode 9.2

I'm trying to convert a string from upper case to lower case to check if it is a palindrome, however I keep getting the error:
"function declaration is not a prototype"
I already added #include <string.h> in the header, but it still doesn't work. How do I get around this issue?
This is the code:
int main (void)
{
char *user_string, *user_string_rev;
/* the malloc function is used to make sure that enough memory is allocated for the string and that it does not overwrite memory boxes of other variables. */
user_string= (char*)malloc(BUFF_SIZE*sizeof(char));
user_string_rev= (char*)malloc(BUFF_SIZE*sizeof(char));
printf("Please enter a string:");
fgets(user_string,BUFF_SIZE, stdin); /* fgets function take the string the user inputs and stores it into user_string. */
user_string_rev=strcpy(user_string_rev, user_string); /*the strcpy takes the string the user inputs and copies it to user_string_rev. */
strlwr(user_string_rev);
palindrome_check(user_string,user_string_rev); /*this is the palindrome function used to check if the two strings are palindromes, it intakes two arguments, the two strings and does not return anything. */
return 0;
}
Replace :
strlwr(user_string_rev);
which is not a standard function with:
int i = 0;
while (user_string_rev[i])
{
if (isalpha(user_string_rev[i]))
user_string_rev[i] |= 32;
++i;
}
Don't forget to add the ctype header at the top of your .c file to use isalpha:
#include <ctype.h>
the following proposed code:
incorporates the comments to the question
cleanly compiles
properly checks for errors
will treat a string that is nothing but a newline as NOT a palindrome
And now the proposed code:
#include <stdio.h> // getline(), printf()
#include <stdlib.h> // free()
#include <ctype.h> // tolower()
#include <string.h> // strlen(), strchr()
// prototypes
void palindrome( char *, size_t length );
int main( void )
{
char *inputStr = NULL;
size_t lengthStr = 0;
printf("Please enter a string:");
if( -1 != getline( &inputStr, &lengthStr, stdin ) )
{
size_t length = strlen( inputStr );
for( size_t i = 0; i < length; i++ )
{
inputStr[i] = (char)tolower( inputStr[i] );
}
char *newline = strchr( inputStr, '\n' );
if( newline )
{
*newline = '\0';
length--;
}
palindrome( inputStr, length );
}
free( inputStr );
return 0;
}
void palindrome( char stringToCheck[], size_t length )
{
size_t index = length - 1; // don't check NUL terminator byte
size_t i;
for( i = 0; i < index; i++ )
{
if( stringToCheck[i] != stringToCheck[ index ] )
{
break;
}
index--;
}
if( i < index )
{
printf( "%s is not a palindrome\n", stringToCheck );
}
else
{
printf( "%s is a palindrome\n", stringToCheck );
}
}

How to copy part of text file into a string in C?

I have a text file with:
recipName=Fork friend=Cup sonName=Spork feature=hair sendName=Spoon"
What I want to do is copy all the words before an = sign to one character array, and copy the stuff to the right of the = to another character array or string.
This is my code so far:
int main (int argc, char * argv[])
{
char data[100];
char line[5][100];
char key[5][100];
char value[5][100];
FILE * fdata = fopen(argv[1], "r"); //read data.txt file
FILE * ftemp = fopen(argv[2], "r"); //read and write to template.txt file
if (fdata == NULL)
{
printf("could not read file.\n");
}
int i = 0;
while (fgets(data, 100, fdata) != NULL)
{
printf("data: %s", data);
//this is where i get stuck, idk how to utilize this loop to copy the variable and variable names from the data.txt file i was given...thanks for the help
++i;
}
fclose(fdata);
fclose(ftemp);
return 0;
}
there might be some better functions that will do more of what you want in string.h
you will have to work out the logistics and count the number of '=' characters and decide how to handle that.
#include <string.h>
char *ptr1, *ptr2;
char tempstring[100];
char before[100];
char after[100];
/* you already have data[] filled... where you get stuck */
ptr1 = strchr( data, '=' ); /* find first occurence of = */
ptr2 = strrchr( data, '=' ); /* find last occurence of = */
if ( *ptr1 == '\0' )
{
/* did not find '=' print error message and stop */
}
if ( *ptr2 == '\0' )
{
/* did not find '=' print error message and stop */
}
/* below is what you are interested in */
strcpy( tempstr, data );
ptr1 = strchr( tempstr, '=' );
*ptr1 = '\0'; /* turn = into null */
strcpy( before, tempstr );
printf("everything before = character is %s\n", tempstr ); /* watch out if = is first character, nothing before it */
strcpy( tempstr, data );
ptr2 = strchr( tempstr, '=' );
ptr2++;
if ( *ptr2 != '\0' ) /* = might have been last character */
{
strcpy( after, tempstr );
printf("everything after = character is %s\n", tempstr );
}
so for the first strchr call,
before[] will have "recipName"
and after[] will have "Fork friend=Cup sonName=Spork feature=hair sendName=Spoon"
you can do a
sscanf( after, "%s", after2 );
to get just "Fork" into after2[] array assuming there will always be a space character separating things.
for chqrlie
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
# define MAX 5
int Count_Token ( char str[], char token )
{
char *p;
int cnt = 0;
/* str must be null terminated with '\0' otherwise infinite loop will happen */
p = str;
while ( *p != '\0' )
{
if ( *p == token )
cnt++;
p++;
}
return cnt;
}
void Get_KeyValue_at_Position( char str[], char token, int position, char k[], char v[] )
{
char *ptr;
char temp_str[100];
int i;
ptr = str;
/* assumes str[] passed in does not have leading space before first key */
/* this for loop puts ptr on start of key at position */
for ( i = 0; i < position; i++ }
{
/* move ptr to next space */
while (( *ptr != ' ' ) && ( *ptr != '\0' ))
ptr++;
/* account for more than one space separating key/value pairs and put ptr on beginning of next key */
while ( *ptr == ' ' )
ptr++;
}
/* get key */
strcpy( temp_str, ptr )
ptr_token = strchr( temp_str, token );
*ptr_token = '\0';
strcpy( k, tempstr );
/* get value */
strcpy( temp_str, ptr );
ptr_token = strchr( temp_str, token );
ptr_token++;
strcpy( v, ptr_token );
}
int main ( int argc, char * argv[] )
{
char data[100];
char key[MAX][100]; /* has string before token */
char value[MAX][100]; /* has string afte token */
FILE *fdata;
fdata = fopen(argv[1], "r"); //read data.txt file
if ( fdata == NULL )
{
printf("could not read file %s\n", argv[1] );
exit( 0 );
}
fgets( data, 100, fdata );
while ( ! feof( fdata ) )
{
printf("data: %s", data);
//this is where i get stuck, idk how to utilize this loop to copy the variable and variable names from the data.txt file i was given...thanks for the help
/* count how many token characters there are in data[] string */
num_token = Count_Token( data, '=' );
if ( num_token > MAX )
{
printf(" num token is %d, MAX is %d, stopping program.\n", num_token, MAX );
fclose( fdata );
exit( 0 );
}
for ( i = 0; i < num_token; i++ )
{
/* make sure i index does not exceend declaration size of key and value */
Get_KeyValue_at_Position( data, token, i, key[i], value[i] );
}
fgets( data, 100, fdata );
}
fclose(fdata);
return 0;
}

Issues with Pointer Arithmetic - Trying to tokenize input String

Currently I am working on a program that allows a user to enter a string that is then tokenized, then the tokens are printed to the screen by using an array of pointers. It is "supposed" to do this by calling my tokenize function which reads the input string until the first separator ( ' ', ',', '.', '?', '!'). It then changes that separator in my string to a NULL char. It then should return a pointer to the next character in my string.
In main after the string has been input, it should keep calling the tokenize function which returns pointers which are then stored in a array of pointers to later print my tokens. Once the tokenize() returns a pointer to a NULL character which is at the end of my string it breaks from that loop. Then I print the tokens out using my array of pointers.
//trying to be detailed
#include <stdio.h>
#include <string.h>
char *tokenize ( char *text, const char *separators );
int main ( void )
{
char text[30];
char separators[6] = { ' ','.',',','?','!','\0'};
char *pch = NULL;
int tokens[15];
int i = 0;
int j = 0;
printf("Enter a string: \n");
fgets( text, 30, stdin );
printf("%s", text );
pch = tokenize ( text, separators );
do
{
pch = tokenize ( pch, separators );
//printf("%c", *pch);
tokens[i] = pch;
i++;
}
while( *pch != NULL );
i--;
while( j != i )
{
printf("%s", tokens[i] );
j++;
}
return 0;
}
char *tokenize ( char *text, const char *separators )
{
while( text != NULL )
{
if( text != NULL )
{
while( separators != NULL )
{
if( text == separators )
{
text = '\0';
}
separators++;
}
}
text++;
}
return text;
}
3 big known problems currently.
1.When I compile, it reads the string then prints it, then gets stuck in a endless loop with nothing printing, still trying to get input.
2. Im pretty sure I am using the " * " for my pointers in the wrong place.
3. My function passes in a reference to my arrays, so I assumed i could just increment them as is.
I appreciate any feedback! I will be watching this post constantly. If i left something unclear, I can respecify. Thanks.
You had right idea for approaching the problem, but you had numerous pointer/int errors throughout your code. Make sure you compile your code with Warnings enabled, this will tell you where you have problems in your code. (don't expect your code to run correctly until you address and eliminate all warnings). At a minimum, compile with -Wall -Wextra options in your build command.
There are a lot easier ways to do this, but for the learning experience, this is a great exercise. Below is your code with the errors corrected. Where possible, I have left your original code commented so you can see where the issues were. I also include a bit of code to remove the newline included by fgets at the end of text. While this isn't required, it is good practice not to have stray newlines filter through your code.
Let me know if you have questions:
#include <stdio.h>
#include <string.h>
char *tokenize ( char *text, const char *separators );
int main ( void )
{
char text[30];
char separators[6] = { ' ','.',',','?','!','\0'};
char *pch = NULL;
char *tokens[15] = {0}; /* declare array of pointers */
int i = 0;
int j = 0;
printf("Enter a string: \n");
fgets( text, 30, stdin );
size_t len = strlen (text);
if (text[len-1] == '\n') /* strip newline from text */
text[--len] = 0;
pch = text; /* pch pointer to next string */
char *str = text; /* str pointer to current */
do
{
pch = tokenize ( str, separators ); /* pch points to next */
tokens[i++] = str; /* save ptr to token */
str = pch; /* new start of str */
}
while (pch != NULL && *pch != 0); /* test both pch & *pch */
printf ("\nTokens collected:\n\n");
while (tokens[j]) /* print each token */
{
printf(" token[%d]: %s\n", j, tokens[j] );
j++;
}
printf ("\n");
return 0;
}
char *tokenize ( char *text, const char *separators )
{
const char *s = separators; /* must use pointer to allow reset */
//while( text != NULL )
while( *text != '\0' )
{
s = separators; /* reset s */
while( *s != 0 ) /* 0 is the same as '\0' */
{
//if( text == separators )
if( *text == *s )
{
//text = '\0';
*text = '\0';
return ++text;
}
s++;
}
text++;
}
return text;
}
Example output:
$ ./bin/tokenizestr
Enter a string:
This is a test string
Tokens collected:
token[0]: This
token[1]: is
token[2]: a
token[3]: test
token[4]: string
Maybe you will want to take a look at
strsep and this post Split string with delimiters in C
If you need more reference points try searching "split string" it is what you want to do if I understood correctly.

Unable to get string using gets() in C

I wanted to write a program to check which string has a greater length without using string functions. I tried to get the two strings as input using gets() but my program keeps on crashing. Please help! Thanks!
Here's my code:
#include <stdio.h>
int l1,l2;
char *st1,*st2;
void accept()
{
gets(st1);
gets(st2);
}
void length()
{
int i = 0;
while (st1[i] != '\0')
{
l1++; i++;
}
i = 0;
while (st2[i] != '\0')
{
l1++; i++;
}
}
int main()
{
accept();
length();
if (l1 > l2)
printf("String #1 is greater in length.\n");
else
printf("String #2 is greater in length.\n");
}
you have not allocated space to st1 or st2 nor have you initialized them... so they are both pointing to some unknown place in memory. Try...
char st1[1024];
char st2[1024];
That said, realize that gets is inherently unsafe as it is subject to buffer overrun attack; there's nothing to stop someone from entering a string longer than 1024 and crashing your program.
You can also greatly simplify the length() function as follows...
void length()
{
for (l1 = 0; st1[l1] != '\0'; l1++ );
for (l2 = 0; st2[l2] != '\0'; l2++ );
}
Expanding on this and your question about what's an alternative to gets(), the answer is to use something like fgets() -- for example...
int main( int argc, char** argv )
{
if( fgets( st1, sizeof( st1 ), stdin ) != NULL )
{
if( fgets( st2, sizeof( st2 ), stdin ) != NULL )
{
length();
if (l1 > l2) printf("String #1 is greater in length.\n");
else if (l2 > l1) printf("String #2 is greater in length.\n");
else printf( "Both strings are the same length.\n" );
}
else printf( "could not read second string\n" );
}
else printf( "could not read first string\n" );
return( 0 );
}
In this case, fgets() will not allow the user to overflow st1 or st2 and it will ensure they are always null terminated strings.
use l2 in the second while loop,
l1=0;
while (st1[l1] != '\0')
{
l1++;
}
l2 = 0;
while (st2[l2] != '\0')
{
l2++;
}

Resources