I am trying to capture a user input string, then display that string in reverse order next to the initial string. My code is as follows:
char str[300], revstring[300];
int i, strlen;
int main(void) {
printf("Enter a string: "); //Prompt user for input string
gets(str);
for (i = 0; str[i] != NULL; i++) { //Get length of string
strlen += 1;
}
for (i = 0; i <= strlen; i++) {
revstring[i] = str[strlen - i];
}
printf("\n\nThe palindrome of your input is %s%s\n\n\n", str, revstring);
return 0;
}
When I run the program however, I see nothing after the initial string. I come from a python background so maybe I am thinking about this in too much of a python mindset, but I feel like this should work.
After this loop
for (i = 0; str[i] != NULL; i++) { //Get length of string
strlen += 1;
}
str[strlen] is equal to the terminating zero '\0'. And the next loop starts from writing this zero in the first element of the array revstring when i is equal to 0.
for (i = 0; i <= strlen; i++) {
revstring[i] = str[strlen - i];
}
As result nothing is displayed.
Also you should not forget to append the result string with the terminating zero.
Take into account that the function gets is unsafe and is not supported any more by the C Standard. It is better to use the standard function fgets. But using it you should remove the appended new line character.
The program can be written the
#include <stdio.h>
#define N 300
int main( void )
{
char str[N], revstring[N];
printf( "Enter a string: " );
fgets( str, N, stdin );
size_t length = 0;
while ( str[length] != '\0' && str[length] != '\n' ) ++length;
if ( str[length] == '\n' ) str[length] = '\0';
size_t i = 0;
for ( ; i != length; i++ ) revstring[i] = str[length - i - 1];
revstring[i] = '\0';
printf("\n\nThe palindrome of your input is %s%s\n\n\n", str, revstring);
return 0;
}
Its output might look like
Enter a string: Hello, Froobyflake
The palindrome of your input is Hello, FroobyflakeekalfyboorF ,olleH
The string is a null-terminated string. You are copying the null character to the beginning of the reversed string. This tells the system that they string is terminated at the first character.
You could use this code instead.
for (i = 0; i < strlen; i++)
{
revstring[i] = str[(strlen - 1) - i];
}
revstring[strlen] = 0;
Here only the characters before the null character are copied and then the null character is added at the end.
Related
Question:Find the largest number and smallest created by digits from n (n<10 ^50) .
I have tried like the below but in some cases, it's wrong
For example:
Case 1: Input 2015 Output 5210
Case 2: Input 47356359122 Output(Wrong answer)
Help me please, I don't know why I got the wrong answer!!!
#include <stdio.h>
#include <string.h>
void max(char s[]) {
int l = strlen(s);
int i, key, j;
for (i = 1; i < l; i++) {
key = s[i];
j = i - 1;
while (j >= 0 && s[j] > key) {
s[j + 1] = s[j];
j = j - 1;
}
s[j + 1] = key;
}
s[l - 1] = '\0';
printf("%s\n", s);
}
int main() {
char s[100];
fgets(s, sizeof(s), stdin);
max(s);
}
Your approach is correct: sorting the digits in decreasing order produces the largest number from these digits.
Your implementation is flawed:
you actually sort them in increasing order. You should change while (j >= 0 && s[j] > key) to
while (j >= 0 && s[j] < key)
the null terminator is set at the wrong position: you clear the last character in s. If the line read from stdin ends with a newline, this may erase it, unless the user typed a TAB character, but if the input consists only of digits, the last one will be removed. Change the code to:
s[l - 1] = '\0';
Here is an alternative using counting sort:
#include <stdio.h>
void max_number(char s[]) {
/* array to store the number of occurrences of each digit */
int count[10] = { 0 };
int i, d, c;
/* enumerate all characters from the string, stop at the null terminator */
for (i = 0; s[i]; i++) {
/* only count digits from '0' to '9' */
if (s[i] >= '0' && s[i] <= '9') {
/* increase the digit count for this digit */
count[s[i] - '0']++;
}
}
/* output the digits from highest to lowest */
for (i = 0, d = 10; d --> 0;) {
for (c = count[d]; c --> 0;)
s[i++] = '0' + d;
}
if (i == 0) {
/* there were no digits in the string: store a 0 */
s[i++] = '0';
}
if (s[0] == '0') {
/* there were only zeroes in the string: keep a single 0 */
i = 1;
}
/* set the null terminator */
s[i] = '\0';
printf("%s\n", s);
}
int main() {
char s[100];
if (fgets(s, sizeof(s), stdin))
max_number(s);
return 0;
}
User chqrlie already provided an excellent general answer. Here is an addition with a simpler, slightly less efficient approach.
Observing that it is not necessary to actually store the result in a new string, you could also print the digits - high to low - as you find them. This program loops over the input string 10 times, first printing all 9s, then all 8s, etc.
#include <stdio.h>
void max(char *str) {
for (char digit = '9'; digit >= '0'; --digit) // Assume ASCII
for (char *strCp = str; *strCp != '\0' ; ++strCp)
if (*strCp == digit)
putchar(digit);
putchar('\n');
}
int main(void) {
char s[100];
if (fgets(s, sizeof(s), stdin) != NULL)
max(s);
}
Note:
No strlen function is used, so the string.h header is no longer needed.
Changed the main signature to int main(void), which is suggested by the standard in case the parameters are not used.
Checking the return value of fgets, so the program can handle empty input and input failure.
For starters the function should not output any message. It is the caller if the function that decides whether to output a message.
The function should return a modified string characters of which are sorted as digit in the descending order.
Your function can invoke undefined behavior when an empty string is passed to the function
void max(char s[]) {
int l = strlen(s);
int i, key, j;
//...
s[l - 1] = '\0';
printf("%s\n", s);
}
because in this statement
s[l - 1] = '\0';
there is an attempt to access memory beyond the passed string. And in general the statement is wrong because the terminating zero must be present in the position l .
There is no need to set the terminating zero character '\0' because it is already present in the string. So the above statement is just redundant.
In fact you are trying to sort characters of the string using the insertion sort method in the ascending order due to the condition in this if statement.
while (j >= 0 && s[j] > key) {
In this case the new line character '\n' that is present in the string after calling the function fgets will be moved at the beginning of the string.
You have to sort the string in the descending order.
And the new line character '\n' should be removed from the string before calling the function.
The function can be declared and defined for example the following way as it is shown in the demonstrative program below.
#include <stdio.h>
#include <string.h>
char * max_number( char *s )
{
if ( *s )
{
for ( char *p = s + 1; *p; ++p )
{
char c = *p;
char *q = p;
for ( ; q != s && *( q - 1 ) < c; --q )
{
*q = *( q - 1 );
}
if ( q != p ) *q = c;
}
}
return s;
}
int main(void)
{
char s[100];
fgets( s, sizeof( s ), stdin );
s[ strcspn( s, "\n" ) ] = '\0';
puts( max_number( s ) );
return 0;
}
If to enter the number 47356359122 using fgets then the program output will be
97655433221
#include <stdio.h>
#include <ctype.h>
int main()
{
char str[100];
char splitStrings[10][10];
int i, j, cnt;
printf("Enter a sentence, up to 255 charcters: \n");
fgets(str, sizeof str, stdin);
j = 0; cnt = 0;
for (i = 0; i <= (strlen(str)); i++)
{
if (!ispunct(str[i]) == ' ' || isalpha(str[i]) == '\0')
{
splitStrings[cnt][j] = '\0';
cnt++; //for next word
j = 0; //for next word, init index to 0
}
else
{
splitStrings[cnt][j] = str[i];
j++;
}
}
for (i = 0; i < cnt; i++)
printf("\n%s %d \n", splitStrings[i], strlen(splitStrings[i]));
return 0;
}
Here is my code, I am trying to input a sentence and it will spilt up the string by words and count the number of letter. But it appear there an additional 0 in my output? And how do I get rid of it
output
fgets() will put a newline character it read into the buffer when the input is short enough to fit (as in the example data).
The newline character is not an alphabet, so isalpha(str[i]) == '\0' will become true and it moves on next word.
Then, the next charcter is terminating null-character. (it is processed because the loop condition is i <= (strlen(str)))
It is also not an alphabet, so it also moves on next word.
There are no characters between the newline character and the terminating null-character, so it is printed as zero-character word.
I'm writing code which checks if an array is palindrome or not:
Write a program that reads a message, then checks whether it's a palindrome
(the letters in the message are the same from left to right as from right to left):
Enter a message: He lived as a devil, eh?
Palindrome
Enter a message: Madam, I am Adam.
Not a palindrome
When I have entered He lived as a devil, eh?,
it gives me the output Not a palindrome,
but the real output should be palindrome.
Below code is what I have tried so far.
#include <stdio.h>
#include <ctype.h>
#define MAX_LEN 100
int main(void) {
char message[MAX_LEN];
char c, *p = message, *q;
printf("Enter a message: ");
while ((c = toupper(getchar())) != '\n' & p < message + MAX_LEN) {
if (isalpha(c))
*p++ = c;
}
p--;
for (q = message; q < p; q++, p--) {
if (*p != *q) {
printf("Not a palindrome\n");
return 0;
}
}
printf("Palindrome\n");
return 0;
}
For starters you should declare the variable c as having the type int. The user can interrupt the input process in which case the function getchar returns integer value EOF and you should check whether this occurred.
char *p = message, *q;
int c;
There is a bug in the condition of the while statement
while ((c = toupper(getchar())) != '\n' & p < message + MAX_LEN) {
Instead of the bitwise operator & you have to use the logical AND operator &&.
As I already have said you should check in the condition of the while statement whether the user interrupted the input. For example
while ( p < message + MAX_LEN && ( c = toupper(getchar())) != EOF && c != '\n') {
if (isalpha(c))
*p++ = c;
}
The argument of a call of toupper or isalpha should be converted to the type unsigned char. Otherwise in general without the casting such a call can invoke undefined behavior.
It is desirable not to exclude from an entered string numbers. SO it is better at least to call the function isalnum instead of the function isalpha.
The user can enter an empty string in this case this decrement of the pointer
p--;
also can invoke undefined behavior.
And it is better when a program has one point to exit.
The program can look the following way
#include <stdio.h>
#include <ctype.h>
#define MAX_LEN 100
int main(void)
{
char message[MAX_LEN];
printf( "Enter a message: " );
char *p = message;
for ( int c; p < message + MAX_LEN && ( c = getchar() ) != EOF && c != '\n'; )
{
if( isalnum( ( unsigned char )c ) )
{
*p++ = toupper( ( unsigned char )c );
}
}
int palindrome = 1;
if ( p != message )
{
for ( char *q = message; palindrome && q < --p; ++q )
{
palindrome = *q == *p;
}
}
printf( "The entered message is %spalindrome\n",
palindrome ? "" : "not " );
return 0;
}
Its output might look for example like
Enter a message: He lived as a devil, eh?
The entered message is palindrome
or like
Enter a message: Madam, I am Adam
The entered message is not palindrome
Pay attention to that instead of using a loop with numerous calls of the function getchar you could use only one call of the function fgets
fgets( message, sizeof( message ), stdin );
or
if ( fgets( message, sizeof( message ), stdin ) != NULL )
{
// check whether the entered string is a palindrome
}
Before check the palindrome you have to remove white spaces and punctuation marks. For an example if you use civic?, it is not palindrome because of ?. In the other hand if you use civ ic, it is not palindrome because of white space. There for
Convert all letters to uppercase or lowercase.
Remove white spaces.
remove punctuation marks.
Check palindrome or not.
You can do it by using # include <string.h>
First thing is you have to use scanf() which accept string with white space.
printf("Enter a string = ");
scanf("%[^\n]%*c", word);
Then you have to convert that string to Uppercase or Lowercase because a != A. We know civic is a palindrome but Civic is not a palindrome('Civic != civiC) because Uppercase letters have different ASCII values and Lowercase letters have different ASCII values.
(a - z) -: 97 - 122
(A - Z) -: 65 - 90
In my case I have converted lowercase to uppercase.
while(strlen(word) >= i)
{
if(word[i] >= 97 && word[i] <= 122)
{
word[i] = word[i] - 32;
}
i++;
}
Another case is your if you enter civ ic with white space, it's palindrome word is ci vic. You can see civ ic != ci vic. There for you have to remove white spaces in your program. And also you have to remove punctuation marks because if you use civic, it's reversed word is ,civic'. You can seecivic, != ,civic`.
int len = strlen(word);
while(a < len)
{
for(i = 0; i < len; i++)
{
if(word[i] == ' ' || !(word[i] >= 'A' && word[i] <= 'Z'))
{
for(j = i; j < len; j++)
{
word[j] = word[j+1];
}
len--;
}
}
a++;
}
Final thing is we have to revers our string and need to check if our reversed string is equal to our original string. If it is true our String is palindrome. If it is false our String is not a palindrome.
for(i = 0; i < len; i++)
{
if(word[i] == word[len - 1])
{
len--;
}
else
{
printf("%s is not a palindrome\n", word);
return 0;
}
}
printf("%s is a palindroeme\n", word);
This the full code after you merging above parts
# include <stdio.h>
# include <string.h>
int main (void)
{
char word[100];
int i = 0;
int j, x = 0;
int a = 0;
printf("Enter a string = ");
scanf("%[^\n]%*c", word);
while(strlen(word) >= i)
{
if(word[i] >= 97 && word[i] <= 122)
{
word[i] = word[i] - 32;
}
i++;
}
printf("After converting it to uppercase = %s\n", word);
int len = strlen(word);
while(a < len)
{
for(i = 0; i < len; i++)
{
if(word[i] == ' ' || !(word[i] >= 'A' && word[i] <= 'Z'))
{
for(j = i; j < len; j++)
{
word[j] = word[j+1];
}
len--;
}
}
a++;
}
printf("After removing spaces = %s\n", word);
for(i = 0; i < len; i++)
{
if(word[i] == word[len - 1])
{
len--;
}
else
{
printf("%s is not a palindrome\n", word);
return 0;
}
}
printf("%s is a palindroeme\n", word);
return 0;
}
First test Output -:
Enter a string = He lived as a devil, eh?
After converting it to uppercase = HE LIVED AS A DEVIL, EH?
After removing spaces = HELIVEDASADEVILEH
HELIVEDASADEVILEH is a palindroeme
Second test Output -:
Enter a string = Madam I am Adam.
After converting it to uppercase = MADAM I AM ADAM.
After removing spaces = MADAMIAMADAM
MADAMIAMADAM is not a palindrome
I am working through Kochan's programming in C book and I am working on an exercise which requires a function to insert one character string inside another string, with the function call including where the string is to be inserted.
I have written the below code but I receive a segmentation fault whenever I enter the inputs. I think it's because the 'input' string is defined to the length of the user's input and then the insertString function tries to add additional characters to this string. I just can't see a way of defining the string as large enough to be able to take in additional characters. Do you think that this is the reason I am receiving a segmentation fault? Are there any other ways to go about this problem?
#include<stdio.h>
#include <string.h>
insertString(char input[], const char insert[], int position)
{
int i, j;
char temp[81];
j = strlen(input);
for(i = 0; i < position - 1; i++)
{
temp[i] = input[i];
}
for(j = 0; insert != '\0'; i++, j++)
{
temp[i] = insert[j];
}
for(j = i - j; input != '\0'; i++, j++)
{
temp[i] = input[j];
}
for(i = 0; temp[i] != '\0'; i++)
{
input[i] = temp[i];
}
input[i] = '\0';
}
void readLine(char buffer[])
{
char character;
int i = 0;
do
{
character = getchar();
buffer[i] = character;
i++;
}
while(character != '\n');
buffer[i - 1] = '\0';
}
int main(void)
{
char input[81];
char insert[81];
int position;
printf("Enter the first string: ");
readLine(input);
printf("Enter the insert string: ");
readLine(insert);
printf("Enter placement position int: ");
scanf("%i", &position);
insertString(input, insert, position);
printf("The adjusted string is %s\n", input);
return 0;
}
There might be other reasons as well, but the following fragment will crash for sure:
for(j = 0; insert != '\0'; i++, j++)
{
temp[i] = insert[j];
}
The reason is that - since insert will not be increased or manipulated - this is an endless loop writing "indefinitely" long into temp. Once exceeding its length 80 (or a bit later) it will crash. I suppose you meant for(j = 0; insert[j] != '\0'; i++, j++), right?
Check all for loop conditions in insertString function. For example:
for(j = 0; insert != '\0'; i++, j++)
{
temp[i] = insert[j];
}
is infinite loop. Because of it you access memory out of temp array bounds. It causes UB and segmentation fault. Looks like you need insert[j] != '\0' condition here.
I'm familiar with this book. The author, Stephen Kochan, has a website with answers to the odd-numbered end of chapter exercises.
The website is at classroomm.com but you'll need to look around some to find the information.
Here is the info from that site related to this exercise:
Programming in C, exercise 10-7 (3rd edition) and 9-7 (4th edition)
/* insert string s into string source starting at i
This function uses the stringLength function defined
in the chapter.
Note: this function assumes source is big enough
to store the inserted string (dangerous!) */
void insertString (char source[], char s[], int i)
{
int j, lenS, lenSource;
/* first, find out how big the two strings are */
lenSource = stringLength (source);
lenS = stringLength (s);
/* sanity check here -- note that i == lenSource
effectively concatenates s onto the end of source */
if (i > lenSource)
return;
/* now we have to move the characters in source
down from the insertion point to make room for s.
Note that we copy the string starting from the end
to avoid overwriting characters in source.
We also copy the terminating null (j starts at lenS)
as well since the final result must be null-terminated */
for ( j = lenSource; j >= i; --j )
source [lenS + j] = source [j];
/* we've made room, now copy s into source at the
insertion point */
for ( j = 0; j < lenS; ++j )
source [j + i] = s[j];
}
There's an error somewhere in your insertString function where it goes out of bounds. By the way your insertString function doesn't start with the word void.
If I substitute the insertString function which I wrote for the exercise then the program works.
#include<stdio.h>
#include <string.h>
void insertString (char source[], const char s[], int start)
{
int stringLength (const char s[]);
int lenSource = strlen (source);
int lenString = strlen (s);
int i;
if ( start > lenSource ) {
printf ("insertion point exceeds string length\n");
return;
}
// move the characters in the source string which are above the
// starting point (including the terminating null character) to make
// room for the new characters; to avoid overwriting characters the
// process begins at the end of the string
for ( i = lenSource; i >= start; --i )
source[i + lenString] = source[i];
// insert new characters
for ( i = 0; i < lenString; ++i )
source[start + i] = s[i];
}
void readLine(char buffer[])
{
char character;
int i = 0;
do
{
character = getchar();
buffer[i] = character;
i++;
}
while(character != '\n');
buffer[i - 1] = '\0';
}
int main(void)
{
char input[81];
char insert[81];
int position;
printf("Enter the first string: ");
readLine(input);
printf("Enter the insert string: ");
readLine(insert);
printf("Enter placement position int: ");
scanf("%i", &position);
insertString(input, insert, position);
printf("The adjusted string is %s\n", input);
return 0;
}
This is my code:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
void splitString(char s[]) {
char firstHalf[100] = { 0 };
char secndHalf[100] = { 0 };
for (int i = 0; i < strlen(s) / 2; i++){
firstHalf[i] = s[i];
}
for (int i = strlen(s) /2; i < strlen(s); i++){
secndHalf[i - strlen(s) / 2] = s[i];
}
printf("The string split in two is '%s, - %s' \n", firstHalf, secndHalf);
}
void upperCase(char s[]){
//String in upper case
for (size_t i = 0; i < strlen(s); i++)
s[i] = toupper(s[i]);
printf("The string in uppercase is '%s'", s);
}
void lowerCase(char s[]){
//String in lower case
for (size_t i = 0; i < strlen(s); i++)
s[i] = tolower(s[i]);
printf("The string in lowercase is '%s'", s);
}
int main() {
char s[200];
char splitS[200];
printf("Type a string: ", sizeof( s));
if (fgets(s, sizeof(s), stdin) != 0){
printf("The string is '%s'", s);
}
strcpy(splitS, s);
upperCase(s);
lowerCase(s);
splitString(splitS);
return 0;
}
The correct way it's supposed to print is like this:
The string is 'Hello world'
The string in uppercase is 'HELLO WORLD'
The string in lowercase is 'hello world'
The string split in two is 'Hello, - world'
But instead it prints like this:
The string is 'Hello world
'The string in uppercase is 'HELLO WORLD
'The string in lowercase is 'hello world
'The string split in two is 'Hello , - world
'
You need to read the documentation for fgets() (my emphasis):
fgets() reads in at most one less than size characters from stream and stores them into the buffer pointed to by s. Reading stops after an EOF or a newline. If a newline is read, it is stored into the buffer. A terminating null byte ('\0') is stored after the last character in the buffer.
Since you are typing in these lines with line break characters at the end, you need to remove them in your code.
You have to put null terminator
void splitString(char s[]) {
char firstHalf[100] = { 0 };
char secndHalf[100] = { 0 };
// u need to add null terminator '\0' at the end of string
// so u can add it in for loop or set i outside of loop
for (size_t i = 0; i < strlen(s) / 2; i++){
firstHalf[i] = s[i];
**firstHalf[i+1] = '\0';**
}
for (size_t i = strlen(s) /2; i < strlen(s); i++){
secndHalf[i - strlen(s) / 2] = s[i];
**secndHalf[i+1] = '\0';**
}
printf("The string split in two is '%s, - %s' \n", firstHalf, secndHalf);
}
The fgets function will read a newline and append it to the input string of there's room for it.
You need to check if the last character in the string is \n and if so set it to zero to trim it.
This is happening because fgets retains a newline at the end of the input string, and also because you do not printf a newline yourself.
So the result, is that newline is being printed in the wrong place, splitting your message, and the ' appears on the next line.
An easy way to remove the newline from the entry is with
s [ strcspn(s, "\r\n") ] = 0;
but don't forget to add the \n to the end of the printf formatting strings.
I thing use scanf with format specifier %[^\n]s so you can skip the new line instated of fgets and add \n in every printf.
Complete working code :
#include <stdio.h>
#include <string.h>
#include <ctype.h>
void splitString(char s[]) {
char firstHalf[100] = { 0 };
char secndHalf[100] = { 0 };
int i;
for ( i = 0; i < strlen(s) / 2; i++){
firstHalf[i] = s[i];
}
for ( i = strlen(s) /2; i < strlen(s); i++){
secndHalf[i - strlen(s) / 2] = s[i];
}
printf("\n The string split in two is '%s, - %s' \n", firstHalf, secndHalf);
}
void upperCase(char s[]){
//String in upper case
int i;
for (i = 0; i < strlen(s); i++)
s[i] = toupper(s[i]);
printf("\n The string in uppercase is '%s'", s);
}
void lowerCase(char s[]){
//String in lower case
int i;
for ( i = 0; i < strlen(s); i++)
s[i] = tolower(s[i]);
printf("\n The string in lowercase is '%s'", s);
}
int main() {
char s[200];
char splitS[200];
printf("Type a string: %ld", sizeof( s));
if (scanf("%200[^\n]s", s)!= 0){ //fgets(s, sizeof(s), stdin)
printf("\n The string is '%s'", s);
}
strcpy(splitS, s);
upperCase(s);
lowerCase(s);
splitString(splitS);
return 0;
}
OR
if you want use fgets only then find new line char in string and make it NULL and add new line char '\n' in every printf .
Code need to change is:
if ( fgets(s, sizeof(s), stdin) != 0){
int i;
for(i = 0 ; i < sizeof( s) ; i++ ){
if(s[i] == '\n'){
s[i] = '\0';
break;
}
}
printf("\n The string is '%s'", s);
}