C language program that doesn't work? - c

the user enters a secret word and then from the alphabet choses a letter and if the letter is in the secret word it turns into an asterisk. i think the problem is in the two for loops because it does no seem to replace the letter with an asterisk.
int main ()
{
char secretword[20] = {};
char alphabet[27] = {"abcdefghijklmnopqrstuvwxyz"};
char guess;
int i = 0, k = 0;
int length = 0;
length = strlen(secretword);
printf("You Get six chances to guess all of the letters in a phrase\n");
printf("Enter the secret word/phrase: ");
scanf("%s", &secretword);
printf("Past guesses: ");
printf("%s\n", alphabet);
printf("Guess a character: ");
scanf("%s", &guess);
for(i = 0; i < 27; i++)
{
for(k = 0; k < length; k++)
{
if(secretword[k] == alphabet[i])
{
secretword[k] = '*';
}
}
}
printf("%s", secretword);
return 0;
}

First off, there is a big logic error. The two for loops:
for(i = 0; i < 27; i++)
{
for(k = 0; k < length; k++)
{
if(secretword[k] == alphabet[i])
{
secretword[k] = '*';
}
}
}
Says:
for all characters in the alphabet,
iterate over all characters in the string, and then
if that character in the string is equal to the current alphabet character:
replace it with an asterisk.
Because you're iterating over the whole alphabet, you'll replace all of the string with '*'s. What you probably want is something like:
for(k = 0; k < length; k++)
{
if(secretword[k] == guess)
{
secretword[k] = '*';
}
}
instead.
There are some other problems. This needs to be after secretword is read in:
length = strlen(secretword);
Otherwise you'll read the length of the uninitalised word. Change it to something like this:
printf("You Get six chances to guess all of the letters in a phrase\n");
printf("Enter the secret word/phrase: ");
scanf("%s", &secretword);
length = strlen(secretword);
Also, this:
scanf("%s", &guess);
Should probably be:
scanf("%c", &guess);
since you're planning to only read a char rather than a string.
Also, the 27 in this line:
char alphabet[27] = {"abcdefghijklmnopqrstuvwxyz"};
Is correct, because you want to include the null terminator at the end of the string.
However, this:
for(i = 0; i < 27; i++)
Will read up to alphabet[26], which will be a '\0'. You probably don't want to replace these '\0's in the string (and you won't see any if you're only going up to strlen(secretword) characters - since strlen() counts up to the first '\0'). Changing the loop to only go to 26 characters stops you doing an unnecessary pass over the secretword. It should probably be
for(i = 0; i < strlen(alphabet); i++)
Or, even better (as suggested by wildplasser):
char alphabet[] = {"abcdefghijklmnopqrstuvwxyz"};
....
for(i = 0; i < sizeof alphabet -1; i++)
One last thing - your program will crash if you don't have enough space in the secretword array to hold the string read in. You can get around this by asking scanf to read only 19 characters:
scanf("%19s", &secretword);
Note that scanf will terminate the string with a '\0', so %19s may put up to 20 bytes in to the string.

You set the length variable before secretword is initialized with an actual string so the length will always be zero (or garbage depending on how the compiler decides to initaliaze the variable secretword).

Try putting length = strlen(secretword); after scanf("%s", &secretword);. Without entering anything, strlen() will return 0, finishing the for-loop immediately.

Related

Passing an array of characters as function arguments

I am trying to pass a string as an argument to a function and it throws a Segmentation fault(Core Dumped) error. Could you please let me know what mistake I am making here? Here is the code:
replaceChars(char str[], char sChar[], char rChar)
{
int i,j;
printf("rChar is %c", rChar);
printf("sChar is %s", sChar);
for(i = 0; i <= strlen(str); i++)
{
for(j = 0; j <= strlen(sChar); j++)
{
if(str[i] == sChar[j])
{
str[i] = rChar;
//printf("The New String is %c", str[i]);
}
}
}
printf("The New String is %s", str);
}
void main()
{
char myString[36], schar[36], rchar;
printf("Please enter a string:");
scanf("%[^\n]s", &myString);
printf("Which characters to replace?");
scanf(" %[^\n]c", &schar);
printf("With which character?");
scanf(" %[^\n]c", &rchar);
replaceChars(myString, schar, rchar);
}
Two issues here.
First, when you loop through str and sChar:
I am trying to pass a string as an argument to a function and it throws a Segmentation fault(Core Dumped) error. Could you please let me know what mistake I am making here? Here is the code:
for(i = 0; i <= strlen(str); i++)
{
for(j = 0; j <= strlen(sChar); j++)
{
You use <= as your exit condition. Array indexes start from 0, so valid indexes are from 0 to length-1. You're going from 0 to length, so you're stepping of the end of the array. Reading past the end of an array invokes undefined behavior.
Change the conditions to use <:
for(i = 0; i < strlen(str); i++)
{
for(j = 0; j < strlen(sChar); j++)
{
The second problem is in how you're reading the values:
scanf("%[^\n]s", &myString);
...
scanf(" %[^\n]c", &schar);
...
scanf(" %[^\n]c", &rchar);
The %[] format specifier doesn't require any characters after it, and it requires a char * as a parameter which points to the first element of an array of char. In the first two cases, you're passing the address of an array instead of the array itself (which decays to a pointer) and you have an extra character after the %[] format that isn't needed. In the third case you pass a pointer to a single char when a pointer to multiple characters is expected by the format. Because you want to read a single char, you want to use the %c format specifier instead.
scanf("%35[^\n]", myString);
...
scanf(" %35[^\n]", schar);
...
scanf(" %c", &rchar);
Note also that the first two have a field width that limits the number of characters that are read so that you don't overrun the arrays.
Could you please let me know what mistake I am making here?
In addition to #dbush good answer, OP's code is unnecessarily inefficient.
Using the corrected code below, and assume the initial length of the str, sChar are S,C respectively.
for(i = 0; i < strlen(str); i++) {
for(j = 0; j < strlen(sChar); j++) {
if(str[i] == sChar[j]) {
str[i] = rChar;
}
}
}
The for(i = 0; i < strlen(str); i++) { and with the later str[i] = rChar; obliges the code to find the length of str up to S times and each strlen(str) requires O(S) operations.
If S was a non-trivial value, say 1000, this 1000*1000 could readily affect overall performance. A simply solution is to calculate the length once or look for the null character instead.
// for(i = 0; i < strlen(str); i++) {
S = strlen(str);
for(i = 0; i < S; i++) {
// or
for(i = 0; str[i]; i++) {
The same thing happens with the inner loop too. Yet a smart compiler can see that sChar does not change and may take advantage of understanding strlen() has no side effects that would cause for a different result. With such an optimization strlen(sChar) may be truly called once, even if strlen(sChar) in inside the higher for (i...) loop.
Still it is easy and idiomatic to just test for the null character.
// for(j = 0; j < strlen(sChar); j++)
// better as
for(j = 0; sChar[j]; j++)
Yet why does this not apply to the for(i = 0; i < strlen(str); i++) loop?
Within that loop, code can modify str[] and so the compiler cannot make the optimization as with for(j = 0; sChar[j]; j++).
This also begs the question, what should code do if the replacement character rChar is the null character?
As I see it, code could either continue, replacing with a '\0 multiple times or simple return after this first.
str[i] = rChar;
if (rChar == '\0') return; // Possible way to handle \0

removing duplicated chars from string in C

My program has to look for duplicated chars (that comes one after another) and remove them. So my program does work, but in case I put "PLLNSIS", I get "PLNSISS". I overwrite the char that I find out is duplicated, but in the end, i recieve a copy of the last char.
void main()
{
int length;
char *myString;
printf("Enter the length of the string \n");
scanf("%d", &length);
myString = (char*)malloc((length+1) * sizeof(char));
assert(myString);
printf("Now enter the string: (max %d letters) \n", length);
fseek(stdin, 0, SEEK_END); //flushing the buffer
fgets(myString, length+1, stdin); //calling the input function
no_Straight_Letters(myString);
free(myString);
}
void no_Straight_Letters(char *myString)
{
int i, j = 0, length = strlen(myString);
for (i = 1; i < length-1; i++)
{
if (myString[j] == myString[i])
{
myString[j] = myString[i];
myString[i] = '\0';
}
else myString[++j] = myString[i];
}
myString[length] = '\0'; //last char of the string
printf("And the new string is.... --> ");
puts(myString);
}
I found out the cause but when I fix it, I get nothing on the screen.
The problem is
myString[length] = '\0';
It will be
myString[++j] = '\0';
This works because at the end of the looping j points to the last valid character. Then if you increase it and put \0 there - it will make the string.
You can emulate the behavior of having \n with this small addition (which is not likely to be needed).
myString[++j]='\n';
myString[++j]=0;
Also as a small modification you can remove the redundant assignment in your code. it's unnecessary.
if (myString[j] == myString[i])
{
myString[i] = '\0';
}
There are two issues:
First, you miss the last character; you might not have noticed it, because the last character of your fgets-input is probably a newline which you do not see. So you'd iterate like for (i = 1; i <= length-1; i++).
Second, you cut off the string at length, which is larger then the final string; use myString[j+1] = '\0' instead.
Minor issue: The code in your if is useless, you can omit it.
void no_Straight_Letters(char *myString)
{
int i, j = 0, length = strlen(myString);
for (i = 1; i <= length-1; i++)
{
if (myString[j] != myString[i])
myString[++j] = myString[i];
}
myString[j+1] = '\0'; //last char of the string
printf("And the new string is.... --> '%s'",myString);
}
int main()
{
char myString[] = "PLLNSISSSHERBERTTTA";
no_Straight_Letters(myString);
}

wrong result when find the number of digit inside a string

Here is the situation:
First, The input consists of the number of test cases, m, in the first line and followed by m test cases. Each test case consists of a string with less than 256 characters. The String may contain "Space bar". My Programming language is C.
Then, here is my problem. I cannot find any problem in my code and I can perfectly run the example with correct result. However, when I upload it onto online judgement system, it shows "WA(Wrong Answer)".
Here is my code.
#include<stdio.h>
int numberOfDigit(char input[255])
{
int num = 0;
for (int i = 0; input[i] != '\0'; i++) {
if (input[i] >= 48 && input[i] <= 57)
num++;
}
return num;
}
int main()
{
int numberOfTestCase;
char input[255];
int digit[9999];
scanf("%d", &numberOfTestCase);
for (int j = 0; j < numberOfTestCase; j++) {
fseek(stdin, 0, SEEK_END);
gets(input);
digit[j] = numberOfDigit(input);
}
for (int k = 0; k < numberOfTestCase; k++) {
printf("%d\n", digit[k]);
}
return 0;
}
I want to explain something in my process of coding.
Because the input contains space character, I use gets() function so that I can get a string without stopping by typing space.
However, if I don't add fseek(stdin, 0, SEEK_END);, gets() only appears numberOfTestCase-1 times, I asked on stackOverflow, and was advised that fseek(stdin, 0, SEEK_END); can solve the problem, which I don't know why. But when I add it, the problem is solved, but it fails tests in the online judgement system.
What is my mistake?
fgets() would stop reading input if it sees a newline. Also fseek() may not work on stdin and it's unnecessary for your purpose. Instead you can fgets() to read the first line too instead of scanf(). And then you can use sscanf() to read the input number.
Something like:
fgets(input, sizeof input, stdin);
sscanf(input, "%d", &numberOfTestCase);
for (int j = 0; j < numberOfTestCase; j++) {
fgets(input, sizeof input, stdin);
digit[j] = numberOfDigit(input);
}
for (int k = 0; k < numberOfTestCase; k++) {
printf("%d\n", digit[k]);
}
You can also use the chracter constants instead of hard-coding ASCII values, which is more readable and portable:
for (int i = 0; input[i] != '\0'; i++) {
if (input[i] >= '0' && input[i] <= '9')
num++;
}

Unwanted characters after word in output

I created a program that asks the user for a word and then it arranges the letters in that word in alphabetical order and stores it in another string.
#include <stdio.h>
main()
{
char in[100],out[100],ch;
int i,len,j=0;
//ask user for a word
printf("Enter a word: ");
scanf("%s",in);
//arrange that word in alphabetical order
for(ch = 'a'; ch <= 'z'; ++ch)
for(i = 0; i < strlen(in); ++i)
if(in[i] == ch)
{
out[j] = ch;
++j;
}
//print the word
printf("%s",out);
fflush(stdin);
getchar();
}
The problem is when word is stored in the other string, there are some extra letters or symbols after that word. Can someone please tell me what could be possibly wrong with my code?
You're not null terminating the output string. printf("%s",out); will keep outputting characters until it finds 0 ('\0'). There are many options to fix this:
terminate the output to the current iterator position after the for-loop:
out[j] = '\0';
make the output the same length as the input:
out[strlen(in)] = '\0';
declare a 0-initialized array:
char out[100] = { 0 };
fill the output array with zero's yourself:
memset(out, 0; sizeof(out));
...
As the sorting is concerned, if it's just for learning then it's fine, otherwise you should pick a more efficient sorting algorithm
C strings are null terminated
Use
out[j] ='\0';
before printf
The %s specifier searches for a null termination.
In your case it keeps on printing until it finds one, so you get some random symbols.
Also avoid use of fflush.
You might want to update your logic to sort uppercase characters too.
You might want to use a sort say bubble sort
l=strlen(in);
for(i = 0; i < l; i++)
{
for(j = i + 1; j < l - 1; j++)
if(in[j-1] > in[j]){
ch = in[j];
in[j] = in[j-1];
in[j-1] = ch;
}
}
printf("Sorted String :%s",in);

How do i cycle through each letter in a string?

#include <stdio.h>
int main()
#include <stdio.h>
int main()
{
char msg[31] = {'\0'};
char encrypted[31] = {'\0'};
int key;
printf("Please enter a message under 30 characters: ");
fgets(msg, 31, stdin);
printf("Please enter an encryption key: ");
scanf("%d", &key);
int i = 0;
while (msg[i] && ('a' <= msg[i] <= 'z' || 'A' < msg[i] < 'Z'))
{
encrypted[i] = (msg[i] + key);
i++;
}
printf("%s\n", msg);
printf("%d\n", key);
printf("%s\n", encrypted);
}
Okay i've got my code to increment the characters but i don't know how to make it ignore special characters and spaces. Also how do i use % to loop back to 'a' and 'A'?
Thank you.
You just need a simple for loop:
for (int i = 0; i < 31; i++)
{
// operate on msg[i]
}
If you didn't know the length of the string to begin with, you might prefer a while loop that detects the null terminator:
int i = 0;
while (msg[i])
{
// operate on msg[i]
i++;
}
Your fgets and scanf are probably fine, but personally, I would be consistent when reading input, and fgets for it all. Then you can sscanf to get key out later.
scanf and fgets seem fine in this situation the way you've used them.
In C, a string is just an array of characters. So, you access each element using a for loop and array indexing:
for (int i = 0; i < strlen(str); i++) {
char thisChar = str[i];
//Do the processing for each character
}
You can perform arithmetic on thisChar as necessary, but be careful not to exceed 255. You might want to put a check on key to ensure it doesn't get too big.
Getting a string from scanf:
char msg[31];
scanf("%30s", msg);
OR (less efficient, because you have to fill the array with 0s first)
char msg[31] = { 0 };
scanf("%30c", msg);
Iterating a string is as easy a for loop (be sure to use c99 or c11)
int len = strlen(msg);
for(int i = 0; i < len; i++) {
char current = msg[i];
//do something
msg[i] = current;
}
"Encrypting" (i.e. ciphering) a character require a few steps
Determine if we have an uppercase character, lowercase character, or non-alphabetic character
Determine the position in the alphabet, if alphabetic.
Update the position, using the modulus operator (%)
Correct the position, if alphabetic
I could give you the code here, but then you wouldn't learn anything from doing it yourself. Instead, I encourage you to implement the cipher based on the steps I provided above.
Note that you can do things like:
char c = 'C';
char e = 'E' + 2;
char lower_c = 'C' - 'A' + 'a';

Resources