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++;
}
Related
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
I can't seem to figure out what is going on with my output. I am reading in multiple lines of user input and outputting corresponding input that exceeds a lower boundary. For some reason when I output, the string that's outputted is omitting the first character of the string. Can anyone tell me why this is occuring?
#include <stdio.h>
typedef struct{
char name[4];
int population;
} state;
enum { MAX_STATES = 10 };
int main()
{
state myStates[MAX_STATES];
int c;
int i = 0;
while ((c = getchar())!= EOF)
{
scanf("%s %d\n", myStates[i].name, &myStates[i].population);
i++;
}
// printf("Last character is [%d]\n", c);
printf("");
if (c <= 0)
{
for(int j = 0; j <= MAX_STATES; j++)
{
if(myStates[j].population >= 10)
printf("%s %d\n", myStates[j].name, myStates[j].population);
else
break;
}
}
return 0;
}
Input:
TX 23
CA 45
Output:
X 23
A 45
Updated Code:
#include <stdio.h>
typedef struct{
char name[4];
int population;
} State;
enum { MAX_STATES = 10 };
int main()
{
State myStates[MAX_STATES];
int i, j;
// Function to read in multiple lines (up to 10) of user input; loop
// controls in place, detects format problems, prevents string buffer
// overflows.
for (i = 0; i < MAX_STATES; i++)
{
if (scanf("%2s %d\n", myStates[i].name, &myStates[i].population) != 2)
break;
}
// Function to output (stdout) array of State structs that exceed 10
// population.
for(j = 0; j < i; j++)
{
if(myStates[j].population >= 10)
printf("%s %d\n", myStates[j].name, myStates[j].population);
else
break;
}
return 0;
}
The output as posted, only goes until there is an input that is less than 10 and it breaks out of the loop. When I didn't have that break statement, I was getting garbage output at the last line. Any suggestions to improve the output?
Replace:
int i = 0;
while ((c = getchar()) != EOF)
{
scanf("%s %d\n", myStates[i].name, &myStates[i].population);
i++;
}
with:
int i;
for (i = 0; i < MAX_STATES; i++)
{
if (scanf("%3s %d", myStates[i].name, &myStates[i].population) != 2)
break;
}
This protects you against entering too many states, uses the for loop to put the loop controls in place, detects format problems, prevents string buffer overflows, and reads the first character into the name. Also, a trailing white space (such as a blank or newline) in a format string is a very bad idea in a scanf() format string if the input is being entered interactively. If the input comes from a file, it is less serious but still unnecessary most of the time. (See Trailing blank in scanf() format for more information.)
Keeping a while loop
If you're really adamant that you need a while loop, then you can use:
int i = 0;
while (i < MAX_STATES && (c = getchar()) != EOF)
{
ungetc(c, stdin);
if (scanf("%3s %d", myStates[i].name, &myStates[i].population) != 2)
break;
i++;
}
or:
int i = 0;
while (i < MAX_STATES && (c = getchar()) != EOF)
{
myStates[i].name[0] = c;
if (scanf("%2s %d", &myStates[i].name[1], &myStates[i].population) != 2)
break;
i++;
}
Note that these while loops still maintain both lots of overflow protection — overflowing the main array, and overflowing the name field. Note that one of the two scanf() statements uses %3s and the other %2s; you should be able to explain why. (And yes, the null byte is not counted by scanf(), so you have to use an 'off-by-one' length in the conversion specification.)
There are, no doubt, other techniques that could also be used. However, I think you'll find that the for loop is more nearly idiomatic C.
One alternative that is often sensible is to use fgets() (or POSIX getline() if it is available) to read whole lines, and then sscanf() to parse the lines. This often leads to more resilient programs, and better error reporting. It also stops people who try to put the information for all 50 states on a single line, or who put each datum on a separate line with a blank line in between them all, from getting away with the malformed data. You can quietly insist on two fields (and, if you're careful, only two fields) on the line.
And the output code?
May I inquire about a suggestion for displaying the output properly?
You have:
printf("");
if (c <= 0)
{
for(int j = 0; j <= MAX_STATES; j++)
{
if(myStates[j].population >= 10)
printf("%s %d\n", myStates[j].name, myStates[j].population);
else
break;
}
}
The first printf() does nothing; it should go. The if (c <= 0) condition is a bit dubious. It is possible to type a null byte (often Control-# or Control-Shift-2), though it would be a bit hard to get that to break the original loop. The for loop should be more like for (int j = 0; j < MAX_STATES; j++) — this is the template for safe for loops in C. You most frequently use for (int i = 0; i < MAX; i++). However, you only want to print the states that were read, so instead of using MAX_STATES, you need to use i as the limit. If you really only want to print the top 9 states (CA, TX, FL, NY, IL, PA, OH, GA, NC — see Wikipedia; Michigan is just shy of 10M, it says), then the if condition is fine.
So, you could use (noting that the input loop sets i to the number of states read successfully):
for (int j = 0; j < i; j++)
printf("State: %.2s, Pop'n: %dM\n", myStates[j].name, myStates[j].population);
You can tweak the format to suit your requirements, of course. This will print nothing if no states were read, or the number of states that were read. If you really want to apply the condition on the population, then you'd use:
for (int j = 0; j < i; j++)
{
if (myStates[i].population >= 10)
printf("State: %.2s, Pop'n: %dM\n", myStates[j].name, myStates[j].population);
}
An alternative is:
int i = 0;
char temp[100];
for(i=0; i<MAX_STATES; i++){
fgets(temp, 100, stdin);
if(strcmp(temp, "\n") == 0)
break;
sscanf(temp, "%s %d\n", myStates[i].name, &myStates[i].population);
}
You could try adding a space before %s in scanf, or specify a strict number of chars.
scanf(" %3s",
Or even use as in Beej's guide:
// read all whitespace, then store all characters up to a newline
scanf(" %[^\n]", s);
You could try adding a space before %s in scanf, or specify a strict number of chars.
Or even use this:
// read all whitespace, then store all characters up to a newline
scanf(" %[^\n]", s);
I'm fairly new to coding and am currently taking a programming course at school with C. We were given an assignment and I'm having a bit of difficulty with the first part. We're learning how to use the string-handling library (stdlib.h) and the objective of the assignment is to input multiple lines of text from the keyboard. The instructor advised us to use two-dimensional arrays in order to do this, but I'm a bit stuck. Here's the code I've written:
int main(void) {
char string[3][SIZE];
int i, j;
int c;
printf("Enter three lines of text:\n");
for (i = 0; i < 3; i++) {
j = 0;
while ((j < SIZE) && (c = getchar() != '\n')) {
string[i][j] = c;
j++;
}
}
for (i = 0; i < 3; i++) {
for (j = 0; j < SIZE; j++) {
printf("%c", string[i][j]);
}
printf("\n");
}
return 0;
}
Some points that I'd like to make are that I used the getchar() function to receive input one character at a time, and also the second for loop I intended to print each line of text that is stored in each row of the string array.
The input is any string of text for three lines, for example:
Hi my name is John.\n
I am from the US\n
and I'm a student.
Here's what the current output looks like:
Enter three lines of text:
rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr...
The output that I'm expecting is:
Enter three lines of text:\n
Hi my name is John.\n
I'm from the US\n
and am a student.
Any tips or advice would be greatly appreciated. Thank you!
First of all let me commend the fact the you starting your way with C. That's the most solid language to learn(better is only assembly itself) - you will have a full understanding of how things work, which you wouldn't get if started from some language written on top of C(like Java and Python).
But it's a hard and long road, which worth that.
On the code: there is a lot going and you have made a lot of amusing bugs that would reproduce different interesting things every other time and machine you run it.
First of all: to make your code work somehow all you need is add parenthesis:
while ((j < SIZE) && ((c = getchar()) != '\n')) {
In C everything is binary(or integer, depending how you look at it) and default binding is to the right a op1 b op2 c op3 d..
First op3 is evaluated c op3 d = r1, then you have a op1 b op2 r1 and so on.
Thus you was comparing the value of getchar() with value of character '\n' - which are not equal, so you get TRUE (value 1) and store it in local variable c.
Next you still have some problems because of the way you initialized your array:
char string[3][SIZE];
What it does is simply "intrusts" 3*SIZE*sizeof(char) bytes of you process address space to a thing labeled "string". But that does not clear up all the remnants of previous live (of your program, or even before) on those bytes, so if it happens that SIZE in your program == 100 and you used to store your credit card on a real address memory (RAM) mapped to that region of your program memory you would see your credit card when you print it by printf - if you didn't overwrite those 300 bytes.
This may help you looking at it:
#include <stdlib.h>
#include <stdio.h>
#define SIZE 10
int main(void) {
char string[3][SIZE];
int i, j;
int c;
for(i = 0; i < 3; i++)
for(j = 0; j < SIZE; j++){
string[i][j] = 0;
}
printf("Enter three lines of text:\n");
for (i = 0; i < 3; i++) {
j = 0;
while ((j < SIZE) && ((c = getchar()) != '\n')) {
string[i][j] = c;
j++;
}
}
for (i = 0; i < 3; i++) {
for (j = 0; j < SIZE; j++) {
printf("%c", string[i][j]);
}
printf("\n");
}
return 0;
}
Also be aware that getchar() may behave lousy with input and newlines - it depends on whether you console buffers input before sending it to your program on enter(newline) or not. More here How to avoid press enter with any getchar()
Note: I wrote this answer before the OP clarified they had to use getchar.
To read a whole line at a time, use fgets. To print a whole string at a time, use printf with the %s format.
#include <stdio.h>
int main(void) {
// No need to define a SIZE constant.
// Because it's stack allocated we can its size.
char strings[3][100];
printf("Enter three lines of text:\n");
for ( int i = 0; i < 3; i++) {
// Reads one line, up to the size of `strings[i]`, from stdin.
fgets( strings[i], sizeof(strings[i]), stdin );
}
for ( int i = 0; i < 3; i++) {
// Print each string and its line number.
printf("Line %d: %s\n", i, strings[i]);
}
return 0;
}
This is not the best pattern to read input. You'll learn very quickly that fixed memory sizes and reading input don't work well. For future reference, it would be more like this.
#include <stdio.h>
#include <string.h>
int main(void) {
// A list to store 3 strings, but no memory for the strings themselves.
char *strings[3];
printf("Enter three lines of text:\n");
// A line buffer that's sufficiently large.
// This will be reused.
char line[4096];
for ( int i = 0; i < 3; i++) {
// Read into the large line buffer.
fgets( line, sizeof(line), stdin );
// Copy the string into a buffer that's just big enough.
strings[i] = strdup( line );
}
for ( int i = 0; i < 3; i++) {
printf("Line %d: %s\n", i, strings[i]);
}
return 0;
}
This allocates a single large line buffer to do the reading, then copies what its read with strdup to memory of just the right size. This lets you read even very long lines of input without wasting a bunch of memory if they're very short.
Note that strdup() is not part of the C standard library, but it's part of the POSIX spec. Any major compiler will have it, and it's easy to write your own.
#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';
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.