I'm new to programming and I'm stuck at this basic problem: I have a string as input and it can contain things like 1,2c, 11,120p, 5u so basically 1 or 2 integers (if two, they are separated by ,) and a character at the end. I have to save the integers and the ending character in different variables, but I don't know how to do it and how to separate the case with 1 integer with the case with 2. Thanks for the answers.
You can use sscanf() to try and parse the string and check how many conversions succeeded:
#include <stdio.h>
void parse_string(const char *s) {
int n1, n2;
char c1, c2;
if (sscanf(s, "%d,%d%c%c", &n1, &n2, &c1, &c2) == 3) {
printf("2 numbers: %d and %d, character is %c\n", n1, n2, c1);
} else
if (sscanf(s, "%d%c%c", &n1, &c1, &c2) == 2) {
printf("1 number: %d, character is %c\n", n1, c1);
} else {
printf("invalid string format: %s\n", s);
}
}
In the above code, the string will be rejected if it does not match one of the formats, but also if there is a trailing character after the match, including a space. Note however that the match might not be strict enough as embedded spaces and a + or - sign in front of the numbers will also be accepted. The Standard C library does not include a more general pattern matching mechanism. An initial test such as if (sscanf(s, "%*[0-9],%*[0-9]%c%c", &c1, &c2) == 1) could be used to exclude spaces and signs but numbers exceeding the range of int would still pass this preliminary test and cause undefined behavior for the subsequent %d conversion.
You can use substring for this problem .
https://www.programmingsimplified.com/c/source-code/c-substring
int main()
{
char string[1000], sub[1000];
int position, length, c = 0;
printf("Input a string\n");
gets(string);
printf("Enter the position and length of substring\n");
scanf("%d%d", &position, &length);
while (c < length) {
sub[c] = string[position+c-1];
c++;
}
sub[c] = '\0';
printf("Required substring is \"%s\"\n", sub); // '\"' to print "
return 0;
}
Related
Only the 'strlen' function is being executed by the program.
The if statements inside this while loop do not even work...
#include<stdio.h>
#include<string.h>
#include <ctype.h>
main()
{
char cMessage[100];
int cLow = 0, cUp = 0, cSpec = 0, cSpace = 0, cNum = 0;
printf("Enter your message: ");
scanf("%s", cMessage);
int x = 0;
while(cMessage[x] != 0)
{
x = strlen(cMessage);
printf("Total characters: %d", x);
if(islower(cMessage[x]))
{
printf("\nTotal Lowercase Letters: %d", cLow);
cLow++;
}
else if(isupper(cMessage[x]))
{
printf("\nTotal Uppercase Letters: %d", cUp);
cUp++;
}
else if(isalnum(cMessage[x]))
{
printf("\nTotal Special Characters: %d", cSpec);
cSpec++;
}
else if(isspace(cMessage[x]))
{
printf("\nTotal Lowercase Letters: %d", cSpace);
cSpace++;
}
else if(isdigit(cMessage[x]))
{
printf("\nTotal Lowercase Letters: %d", cNum);
cNum++;
}
}
x++;
}
I cannot figure out the cause of this issue...
What may be the cause of this?
EDIT: So here's the revised code of the program, the only problem that I have now is that the spaces are not being counted. And btw, is there a specific function used to 'count' special characters? I've used 'isalnum' and I realized it was wrong
#include<stdio.h>
#include<string.h>
#include <ctype.h>
#include<conio.h>
main(){
char cMessage[100];
int cLow=0, cUp=0, cSpec=0, cSpace=0, cNum=0;
printf("Enter your message: ");
scanf("%s", cMessage);
int x=0;
while(cMessage[x]){
printf("Total characters: %d", strlen(cMessage));
while(cMessage[x]!=0){
if(islower(cMessage[x])){ cLow++;}
if(isupper(cMessage[x])){ cUp++;}
if(isalnum(cMessage[x])){ cSpec++; }
if(isspace(cMessage[x])){ cSpace++; }
if(isdigit(cMessage[x])){ cNum++; }
x++;
}
printf("\nTotal Lowercase Letters: %d", cLow);
printf("\nTotal Uppercase Letters: %d", cUp);
printf("\nTotal Special Characters: %d", cSpec);
printf("\nTotal Spaces: %d", cSpace);
printf("\nTotal Numbers: %d", cNum);
getch();
}
}
The x = strlen(cMessage); will give you the length of cMessage which is always the index of the last item + 1.
for example if: cMessage = "The" and x = strlen(cMessage) , then:
x = 3
cMessage[0] = 'T'
cMessage[1] = 'h'
cMessage[2] = 'e'
cMessage[3] = NULL terminator // equivalence to 0
Note that there is usually a NULL terminator after the last character.
So as you can see, the while condition is always false after the first pass.
Try to use a separate variable to iterate through cMessage.
Also you need to consider putting variables like cUp++' before the 'printf statements.
A more elegant alternative will be using for statement instead of while.
Also note that isalnum(cMessage[x]) is interfering with if(isdigit(cMessage[x])) so, it is better to use separate if statements and git rid of else if, moreover, if you want to count special characters you have to negates isalnum to be: if(!isalnum(cMessage[x])).
At last your input will not accept sentences (word with spaces between them), so you have to consider replacing:
scanf("%s", cMessage);
with
scanf("%[^\n]s",&cMessage);
You take x as the lenght of your string. So that's one longer then your Array. After the full array is always a 0 to show the program the array is not longer. This way you can never go in the if's
cMessage[x] after x=strlen(cMessage) is always 0. String contains chars from 0 till x - 1, char at post x is 0. Thus any if-condition is false.
I suppose x=strlen(cMessage); is not needed and must be removed, x++ must be three last operator in the loop body, since you want to count chars of different kinds.
printf("Total characters: %zu", strlen(cMessage));
while(cMessage[x] != 0) {
if(islower(cMessage[x])) {
...
}
x++;
}
%d is not proper format for size_t type on 64-bit platform. Read this: How can one print a size_t variable portably using the printf family?
I have an input file with the following form
i 176064 Patterson Denise 8.58 11 DEN 15788
q 188464
ra 148702 167443
a 73131
d 163464
f 6.00
ct 73131 PHY
b 3
p 15703
pe
m 144626 6.51 8
e
The first character in each line[i,q,ra,a...] represents an code to a function , while the rest are values that I must store into variables,depending on that code. What's the best way to achieve this ? I have been thinking about using fscanf but each line does not have a specific format, the format itself depends on the code [i,q,ra,a,b..]
To read a line, use fgets()
char buffer[100];
while (fgets, buffer, sizeof buffer, istream) != NULL) {
Then scan the line against the various formats, each ending with " %n". "%n" records the scan position, if it got that far. Additional tests could check for extraneous extras character starting at n.
int num1, num2, num3;
char last[sizeof buf];
char first[sizeof buf];
char code[sizeof buf];
double rate;
int n = 0;
// v..v..v..v...v..v..v spaces optional here
sscanf(buffer, "i %d %s %s %lf %d %s %d %n",
&num1, last, first, &rate, &num2, code, &num3, &n);
if (n) {
Handle_i();
continue;
}
sscanf(buffer, "q %d %n", &num1, &n);
if (n) {
Handle_q();
continue;
}
sscanf(buffer, "ra %d %n", &num1, &num2, &n);
if (n) {
Handle_ra();
continue;
}
sscanf(buffer, "e %n", &n);
if (n) {
Handle_e();
continue;
}
...
fail();
}
As each format begins with a unique letter pattern, the sscanf() will quickly exit on mis-match.
Alternative, code could parse out the initial letters for a slightly more efficient decision tree. Suspect profiling will show little performance difference.
As with any complex format, consider how one would maintain the code and it is bound to evolve.
I'm trying to learn C on my own, I have some previous experience in Matlab and Python. I'm trying to create a simple guessing game where you give a number, the computer guesses a number and you have to tell it if it's higher or lower. I've written some code, but it just doesn't work (try inputting 30, for example). The code is ugly, but I'm just trying to understand what's going on.
I've tried writing it using the case statement, but same results there.
Also, what is going on when you answer the y/n question with yy? The numbers go way up all of a sudden?
#include "stdio.h"
#include "stdlib.h"
int main(void) {
int a;
int i = 1;
int b = 50;
int temp;
int last = 0;
char ans = ' ';
printf("Enter value for computer to guess (0-100): ");
scanf("%d", &a);
while (a - b) {
printf("Is the number larger than %i (y/n): ", b);
scanf("%s", &ans);
if (ans == 'y') {
temp = b;
b = b + ((b + last) / 2);
last = temp;
} else {
temp = b;
b = b - ((b + last) / 2);
last = temp;
}
i++;
}
printf("Your number was: %i. Number of guesses was: %i \n", b, i);
return 0;
}
In your code
scanf("%s",&ans);
invokes undefined behavior as you're overrunning the allocated memory.
To use %s format specifier, you'll need an array as the argument (pointer to the first element of the array, to be specific).
However, in your case, changing
scanf("%s",&ans);
to
scanf(" %c",&ans); // note the space
is likely to solve the issue. Optionally, to handle the extra input, (like yyy), you can consider clearing the input buffer after reading each input, like
while (getchar() != '\n');
or likewise.
You probably want the computer to binary search for the answer and get there efficiently. You'll need to keep track of the upper and lower boundaries where you're searching. Try something like this;
int main(void){
int a;
int i = 1;
int b = 50;
int lower = 0;
int upper = 100;
char ans[256] = {0};
printf("Enter value for computer to guess (0-100): ");
scanf("%d", &a);
while (a-b) {
printf("Is the number larger than %i (y/n): ",b);
scanf("%s",ans);
if (ans[0] == 'y') {
lower = b;
b = b + ((upper-lower)/2);
printf("Last: %d - %d\n",lower, upper);
}
else {
upper = b;
b = b - ((upper-lower)/2);
printf("Last: %d - %d\n",lower, upper);
}
i++;
}
printf("Your number was: %i. Number of guesses was: %i \n",b,i);
return 0;
}
This is the problem.
char ans = ' ';
...
scanf("%s",&ans);
ans has only a single byte of memory, but you've asked scanf for a whole string. So it dutifully stuffs the whole string into the single byte of ans. Since this includes a null byte, even the input y or n will write an extra byte. yy writes three bytes.
This causes ans to silently overflow its memory wrecking havoc on adjacent variables. This is why yy messes with things, you're putting 3 bytes (2 characters plus a null byte) into 1 allocated byte overflowing by 2 bytes. It overwrites last with the character y which is the number 121. You can see this with a few debugging printfs.
printf("b = %d, last = %d\n", b, last);
printf("Is the number larger than %i (y/n): ",b);
scanf("%s",&ans);
printf("b = %d, last = %d\n", b, last);
Enter value for computer to guess (0-100): 30
b = 50, last = 0
Is the number larger than 50 (y/n): yy
b = 50, last = 121
Instead you want to use %c to read a single character. But that has its own problems, scanf("%d", &a) is leaving a newline on STDIN and scanf("%c", &ans) will read that newline first.
This is why scanf is a problem and should be avoided, it can leave unexpected input in the stream. There's lots of answers here on SO recommending against scanf. Instead use fgets or getline to read the whole line and then use sscanf to read the string. I prefer getline because it handles allocating line memory for you.
Here's a sketch of what to do.
char *line = NULL;
size_t linelen = 0;
printf("Enter value for computer to guess (0-100): ");
getline(&line, &linelen, stdin);
sscanf(line, "%d", &a);
printf("You entered %d\n", a);
printf("Is the number larger than %i (y/n): ",b);
getline(&line, &linelen, stdin);
sscanf(line, "%c", &ans);
switch(ans) {
case 'y':
...
break;
case 'n':
...
break;
default:
printf("I don't understand '%c', try again.\n", ans);
}
free(line);
i have a c program in which i am accepting 2 numbers as input.
How do i validate if input entered is numbers only and not characters.
void main()
{
int a,b;
printf("Enter two numbers :");
scanf("%d%d",&a,&b);
printf("Number 1 is : %d \n Number 2 is : %d",a,b);
}
[Edit] Added Sample Code
Besides the other interesting suggestions (especially the one with scanf), you might also want to use the isdigit function:
The isdigit() function shall test
whether c is a character of class
digit in the program's current locale
note that this function examines only ONE char, not an entire bunch of them.
It is always good practice to resort to already-built functions; there are intricacies you might not be aware of even in the simplest task, and this will make you a good programmer overall.
Of course, in due time you might want to look at how that function works to get a good grasp of the underlying logic.
scanf returns the number of items that it has successfully scanned. If you asked for two integers with %d%d, and scanf returns 2, then it successfully scanned both numbers. Any number less than two indicates that scanf was unable to scan two numbers.
int main()
{
int a,b;
int result;
printf("Enter two numbers :");
result = scanf("%d%d",&a,&b);
if (result == 2)
{
printf("Number 1 is : %d \n Number 2 is : %d",a,b);
}
else if (result == 1)
{
// scanf only managed to scan something into "a", but not "b"
printf("Number 1 is : %d \n Number 2 is invalid.\n", a);
}
else if (result == 0)
{
// scanf could not scan any number at all, both "a" and "b" are invalid.
printf("scanf was not able to scan the input for numbers.");
}
}
One other value that scanf may return is EOF. It may return this if there is an error reading from the stream.
Also note that main returns int, but you have it declared with void return.
Read user line of text input as a string. This greatly simplifies error handling.
int a = 0, b = 0;
char buf[100];
for (;;) {
printf("Enter two integers :");
if (fgets(buf, sizeof buf, stdin) == NULL) {
printf("Input closed\n");
break;
}
Then test the string for 2 ints with no following junk. Use sscanf() (simple) , strtol() (more robust), etc.
int n; // %n records where scanning stopped
if (sscanf(buf, "%d%d %n", &a, &b, &n) == 2 && buf[n] == '\0') {
printf("Number 1 is : %d \n Number 2 is : %d", a, b);
break;
}
printf("<%s> is not 2 integers. Try again\n", buf);
}
More advanced code uses strtol() to validate and also detect excessively long lines of input.
I have a string (char) and I want to extract numbers out of it.
So I have string: 1 2 3 4 /0
And now I want some variables, so I can use them as integer: a=1, a=2, a=3, a=4
How can I do that?
The answers given so far are correct, as long as your string is formatted the way you expect. You should always check the return value of sscanf to make sure things worked okay. sscanf returns the number of conversions successfully performed, in the above case 4.
if (4 != sscanf(buf, "%d %d %d %d", &a, &b, &c, &d))
{
/* deal with error */
}
If buf was "1 2 3" or "1 2 a b" or something, sscanf would return a short item count.
As others have noted, if you know how many numbers to expect, sscanf is the easiest solution. Otherwise, the following sketches a more general solution:
First tokenize the string by spaces. The standard C method for this is strtok():
char* copy;
char* token;
copy = strdup(string); /* strtok modifies the string, so we need a copy */
token = strtok(copy, " ");
while(token!=NULL){
/* token now points to one number.
token = strtok(copy, " ");
}
Then convert the string to integers. atoi() will do that.
If the string always contains 4 numbers delimited with spaces, then it could be done with sscanf:
sscanf(string, "%d %d %d %d", &a, &b, &c, &d);
If the count of numbers varies, then you would need to parse the string.
Please clarify your question accordingly.
sscanf() can do that.
#include <stdio.h>
int main(void)
{
int a, b, c, d;
sscanf("1 2 3 4", "%d %d %d %d", &a, &b, &c, &d);
printf("%d,%d,%d,%d\n", a, b, c, d);
}