Scanning 2 chars in one line - c

I am new to C and I am trying to scan two char variables in one line.
I used #define _CRT_SECURE_NO_WARNINGS because I have to.
This is the piece of code that annoys me: scanf_s("%c-%c", &x,1, &y,1);
When inputting 2 chars, it looks something like this ---> e-f or a-b
Also, I need to lose scanf_s and make it into scanf only.
Another thing that is kinda weird to me is that after I input two chars and do actions later, I reset values of x and y to 0 and need to input them again. However, when I type them in, I get completely different values.
Here is the whole code that I wrote so far. Task: input 2 letters and print them in order specified in input e.g. a-c --> ABC or c-a --> cba
#include<stdio.h>
#define MAX 100
int main(){
char niz[MAX];
char kraj[MAX] = {0};
int razlika;//difference
char x, y;
int i;
char trenutniznak; //current character
int stoppolje=0;//stop field
int temp = 0;
while (1)
{
scanf_s("%c-%c", &x,1, &y,1);
if (x == '.' || y == '.')
{
return 0;
}
else if (y > x)//od pocetka do kraja
{ //(from start to end )
razlika = y - x + 1;
for (i = stoppolje+1, trenutniznak=x; i <= razlika; i++, trenutniznak++)
{
niz[i] = trenutniznak;
temp = i;
}
stoppolje = temp; // polje na kojem je zadnji znak
//(the field where the last character is )
x = 0;
y = 0;
razlika = 0;
}
else
{
printf("\n");
return 0;
}
}
}

Try to understand and then implement in your code
char c;
scanf(" %c",&c); // a whitespace character in scanf() would ignore any number of whitespace characters left in the input stream
printf("%c",c);
you can go through %c conversion specifier

Scanning 2 chars in one line
Simplify. Use fgets() to read a line of user input and convert that into a string.
Avoid scanf(). It does not well read a line and is difficult to use when input is unexpected.
char buf[80];
if (fgets(buf, sizeof buf, stdin)) {
Now scan/parse the string into the two characters. Look for bad input.
char extra;
if (sscanf(buf, "%c-%c %c", &x, &y, &extra) != 2) {
fprintf(stderr, "invalid input <%s>\n", buf);
} else {
// Use x, y in some fashion
printf("Good input <%c> <%c>\n", x, y);
}
}
Sneak: If you must use scanf(), add a scanf(""); before the fgets() to use scanf(). It will not read anything.

"Task: input 2 letters and print them in order specified in input e.g. a-c --> ABC or c-a --> cba"
If scanf() is not necessary, consider using fgets(), then the resulting string array, say char buf[4] = {0}; the the array elements buf[0], buf[1] and buf[2] will contain for example 'a', '-' and 'c'. (buf[3] will contain \0 character.) These are just numeric values that happen to be within the ASCII character range, but can also be logically manipulated as numbers, so just output the sequence of numbers using a format specifier that will guarantee they appear as ASCII:
int main(void)
{
char buf[4] = {0};
int c = 0;
printf("Enter maximum of three characters: eg 'a-d'\n(or ctrl-c to exit.)\n");
while(fgets(buf, sizeof buf, stdin))
{
//test input
if((buf[0] < 'a') || (buf[0] > 'Z') ||
(buf[2] < 'a') || (buf[2] > 'Z') ||
(buf[1] != '-')
)
{
printf("Invalid input. Try again\n(or hit ctrl-c to exit.");
}
else
{
buf[strcspn(buf, "\n")] = 0;//remove newline
if(buf[0] > buf[2])
{
for(char i = buf[0];i >= buf[2];i--)
{
printf("%c", i);
}
printf("\n");
}
else if ((buf[0] < buf[2]))
{
for(char i = buf[0];i<= buf[2];i++)
{
printf("%c", toupper(i));//note UPPER CASE as specified
}
printf("\n");
}
memset(buf, 0, sizeof buf);//reset buffer for next iteration.
while((c = getchar()) != '\n' && c != EOF);//clear \n from stdin
printf("\nEnter maximum of three characters: eg 'a-d'\n(or ctrl-c to exit.)\n");
}
}
}

Well I managed somehow to do it, thank you everyone for answering my question :)
#include<stdio.h>
#define MAX 1000
int main()
{
char niz[MAX];
char kraj[MAX] = {0};
int razlika;
char x, y;
int i;
char trenutniznak;
int stoppolje=-1;
int temp = 0;
while (1)
{
scanf_s(" %c-%c", &x,1, &y,1);
if (x == '.' || y == '.')
{
for (i = 0; i <= stoppolje; i++)
{
printf("%c", niz[i]);
}
return 0;
}
else if(x == '_' || y == '_')
{
niz[stoppolje + 1] = ' ';
stoppolje += 1;
}
else if (y > x)//od pocetka do kraja
{
razlika = y - x + 1;
trenutniznak = x;
for (i = stoppolje+1, trenutniznak; i < razlika+stoppolje+1; i++, trenutniznak++)
{
niz[i] = trenutniznak;
temp = i;
}
stoppolje = temp; // polje na kojem je zadnji znak
x = 0;
y = 0;
razlika = 0;
}//ako idemo po redosljedu abecednom
else if(x>y)
{
razlika = x-y + 1;
trenutniznak = x;
for (i = stoppolje+1, trenutniznak; i < razlika + stoppolje + 1; i++, trenutniznak--)
{
niz[i] = trenutniznak;
temp = i;
}
stoppolje = temp;
x = 0;
y = 0;
razlika = 0;
}
else if (x == y)
{
razlika = 0;
trenutniznak = x;
for (i = stoppolje + 1, trenutniznak; i < razlika + stoppolje + 2; i++, trenutniznak++)
{
niz[i] = trenutniznak;
temp = i;
}
stoppolje = temp;
x = 0;
y = 0;
razlika = 0;
}
}
}

Related

why can't my program recognize similar words in a string?

I want to write a program that will take an input T. In the next T lines, each line will take a string as an input. The output would be how many ways the string can be reordered.
#include <stdio.h>
#include <stdlib.h>
int main() {
int T, i, l, count = 1, test = 0, word = 0, ans;
char line[200];
scanf("%d", &T);
for (i = 0; i < T; i++) {
scanf(" %[^\n]", line);
l = strlen(line);
for (int q = 0; q < l; q++) {
if (line[q] == ' ') {
word++;
}
}
ans = fact(word + 1);
word = 0;
for (int j = 0; j < l; j++) {
for (int k = j + 1; k < l; k++) {
if (line[k] == ' ' && line[k + 1] == line[j]) {
int m = j;
int n = k + 1;
for (;;) {
if (line[m] != line[n]) {
break;
} else
if (line[m] == ' ' && line[n] == ' ') {
test = 1;
break;
} else {
m++;
n++;
}
}
if (test == 1) {
count++;
ans = ans / fact(count);
count = 0;
test = 0;
}
}
}
}
printf("%d\n", ans);
}
}
int fact(int n) {
if (n == 1) {
return 1;
} else {
return n * fact(n - 1);
}
}
Now, in my program,
my output is like this:
2
no way no good
12
yes no yes yes no
120
if T = 2 and the 1st string is no way no good, it gives the right output that is 12 (4!/2!). That means, it has identified that there are two similar words.
But in the 2nd input, the string is yes no yes yes no. that means 3 yes and 2 nos. So the and should be 5!/(3!2!) = 10. But why is the answer 120? and why can't it recognize the similar words?
The main problem in your duplicate detector is you test the end of word with if (line[m] == ' ' && line[n] == ' ') but this test fails to identify a duplicate that occurs with the last word because line[n] is '\0', not ' '.
Note these further problems:
you do not handle words that occur more than twice correctly: you should perform ans = ans / fact(count); only after the outer loop finishes. For example, if a word is present 3 times, it will be detected as 3 pairs of duplicates, effectively causing ans to be divided by 23 = 8, instead of 3! = 6.
you should protect against buffer overflow and detect invalid input with:
if (scanf(" %199[^\n]", line) != 1)
break;
the range of type int for ans is too small for a moderately large number of words: 13! is 6227020800, larger than INT_MAX on most systems.
The code is difficult to follow. You should consider parsing the line into an array of words and using a more conventional way of counting duplicates.
Here is a modified version using this approach:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int cmpstr(const void *p1, const void *p2) {
char * const *pp1 = p1;
char * const *pp2 = p2;
return strcmp(*pp1, *pp2);
}
unsigned long long factorial(int n) {
unsigned long long res = 1;
while (n > 1)
res *= n--;
return res;
}
int main() {
int T, i, n, begin, count;
unsigned long long ans;
char line[200];
char *words[100];
if (!fgets(line, sizeof line, stdin) || sscanf(line, "%d", &T) != 1)
return 1;
while (T --> 0) {
if (!fgets(line, sizeof line, stdin))
break;
n = 0;
begin = 1;
for (char *p = line; *p; p++) {
if (isspace((unsigned char)*p)) {
*p = '\0';
begin = 1;
} else {
if (begin) {
words[n++] = p;
begin = 0;
}
}
}
qsort(words, n, sizeof(*words), cmpstr);
ans = factorial(n);
for (i = 0; i < n; i += count) {
for (count = 1; i + count < n && !strcmp(words[i], words[i + count]); count++)
continue;
ans /= factorial(count);
}
printf("%llu\n", ans);
}
return 0;
}

Odd output of string in C

I received an assignment to write a code that would erase the instances of a string in another string, and although my code does that successfully, the symbol ╠ appears many times at the end of the result string.
Example:
For input string 1 - A string is a string, and an input string 2 - str
The result should be A ing is a ing.
But I receive A ing is a ing╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠
Hoped I could get some assistance regarding this issue, cause no matter what I've tried I wasn't able to
fix this.
#include <stdio.h>
#define STRING_SIZE 100
int StrippingFunc(char input_str1[STRING_SIZE], char input_str2[STRING_SIZE], char
result_string[STRING_SIZE])
{
if (input_str2[0] == '\n' || input_str2[0] == '\0')
{
return 0;
}
for (int k1 = 0; k1 < STRING_SIZE; k1++)
{
if (input_str1[k1] == '\n')
{
input_str1[k1] = '\0';
}
}
for (int k2 = 0; k2 < STRING_SIZE; k2++)
{
if (input_str2[k2] == '\n')
{
input_str2[k2] = '\0';
}
}
int Length;
int length2 = 0;
int index2 = 0;
while (input_str2[index2] != '\0') // Loop used to determine input_string2's length.
{
length2++;
index2++;
}
int InString = 0;
int i = 0;
int j;
int resultindex = 0;
while (input_str1[i] != '\0')
{
Length = length2;
int l = i;
j = 0;
int proceed = 1;
if (input_str1[l] == input_str2[j])
{
while ((input_str2[j] != '\0') && (proceed != 0))
{
while (Length >= 0)
{
if (Length == 0)
{
InString = 1;
i += (l-i-1);
proceed = 0;
Length = -1;
}
if (input_str1[l] == input_str2[j])
{
Length--;
j++;
l++;
}
else if ((input_str1[l-1] == input_str2[j-1]) && (input_str2[j] == '\0'))
{
proceed = 0;
Length = -1;
}
else
{
proceed = 0;
Length = -1;
result_string[resultindex] = input_str1[l - 1];
resultindex++;
}
}
}
}
else
{
result_string[resultindex] = input_str1[i];
resultindex++;
}
i++;
}
return InString;
}
int main()
{
char result_string[STRING_SIZE];
char input_string1[STRING_SIZE];
char input_string2[STRING_SIZE];
printf("Please enter the main string..\n");
// Your function call here..
fgets(input_string1, STRING_SIZE + 1, stdin);
printf("Please enter the pattern string to find..\n");
// Your function call here..
fgets(input_string2, STRING_SIZE + 1, stdin);
int is_stripped = StrippingFunc(input_string1, input_string2, result_string);; // Your function call here..
// Store the result in the result_string if it exists
printf("> ");
printf(is_stripped ? result_string : "Cannot find the pattern in the string!");
return 0;
}
But I receive A ing is a ing╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠
In the code after you fill result_string but you missed to add the final null character, because of that the printf after reach non initialized characters with an undefined behavior producing your unexpected writting. After
while (input_str1[i] != '\0')
{
Length = length2;
...
}
add
result_string[resultindex] = 0;
note you have the place for because result_string and input_str1 have the same size
Having
char input_string1[STRING_SIZE];
char input_string2[STRING_SIZE];
these two lines can have an undefined behavior :
fgets(input_string1, STRING_SIZE + 1, stdin);
fgets(input_string2, STRING_SIZE + 1, stdin);
because fgets may write after the end of the arrays, you need to remove +1 or to size the arrays one more
In
for (int k1 = 0; k1 < STRING_SIZE; k1++)
{
if (input_str1[k1] == '\n')
{
input_str1[k1] = '\0';
}
}
for (int k2 = 0; k2 < STRING_SIZE; k2++)
{
if (input_str2[k2] == '\n')
{
input_str2[k2] = '\0';
}
}
except if fgets fill all the arrays you have an undefined behavior working on non initialized characters because you do not stop when you reach newline or the null character.
In
int length2 = 0;
int index2 = 0;
while (input_str2[index2] != '\0') // Loop used to determine input_string2's length.
{
length2++;
index2++;
}
length2 and length2 have exactly the same value, is it useless to have two variables, and in fact this lop is useless because the previous loop with the right termination already give you the expected length.
In
printf(is_stripped ? result_string : "Cannot find the pattern in the string!");
I encourage you to replace printf by a puts not only to add a final newline to flush the output and make it more clear in case you start your program in a shell, but also because in case the input string contains for instance %d and it is not removed and is_stripped is true then printf will try to get an argument whose do not exist, with an undefined behavior
If you do all the corrections with your inputs your code will print > A ing is a ing without undefined behavior

Program to count length of each word in string in C

I'm writting a program to count the length of each word in array of characters. I was wondering if You guys could help me, because I'm struggling with it for at least two hours for now and i don't know how to do it properly.
It should go like that:
(number of letters) - (number of words with this many letters)
2 - 1
3 - 4
5 - 1
etc.
char tab[1000];
int k = 0, x = 0;
printf("Enter text: ");
fgets(tab, 1000, stdin);
for (int i = 2; i < (int)strlen(tab); i++)
{
for (int j = 0; j < (int)strlen(tab); j++)
{
if (tab[j] == '\0' || tab[j]=='\n')
break;
if (tab[j] == ' ')
k = 0;
else k++;
if (k == i)
{
x++;
k = 0;
}
}
if (x != 0)
{
printf("%d - %d\n", i, x);
x = 0;
k = 0;
}
}
return 0;
By using two for loops, you're doing len**2 character scans. (e.g.) For a buffer of length 1000, instead of 1000 character comparisons, you're doing 1,000,000 comparisons.
This can be done in a single for loop if we use a word length histogram array.
The basic algorithm is the same as your inner loop.
When we have a non-space character, we increment a current length value. When we see a space, we increment the histogram cell (indexed by the length value) by 1. We then set the length value to 0.
Here's some code that works:
#include <stdio.h>
int
main(void)
{
int hist[100] = { 0 };
char buf[1000];
char *bp;
int chr;
int curlen = 0;
printf("Enter text: ");
fflush(stdout);
fgets(buf,sizeof(buf),stdin);
bp = buf;
for (chr = *bp++; chr != 0; chr = *bp++) {
if (chr == '\n')
break;
// end of word -- increment the histogram cell
if (chr == ' ') {
hist[curlen] += 1;
curlen = 0;
}
// got an alpha char -- increment the length of the word
else
curlen += 1;
}
// catch the final word on the line
hist[curlen] += 1;
for (curlen = 1; curlen < sizeof(hist) / sizeof(hist[0]); ++curlen) {
int count = hist[curlen];
if (count > 0)
printf("%d - %d\n",curlen,count);
}
return 0;
}
UPDATE:
and i don't really understand pointers. Is there any simpler method to do this?
Pointers are a very important [essential] tool in the C arsenal, so I hope you get to them soon.
However, it is easy enough to convert the for loop (Removing the char *bp; and bp = buf;):
Change:
for (chr = *bp++; chr != 0; chr = *bp++) {
Into:
for (int bufidx = 0; ; ++bufidx) {
chr = buf[bufidx];
if (chr == 0)
break;
The rest of the for loop remains the same.
Here's another loop [but, without optimization by the compiler] double fetches the char:
for (int bufidx = 0; buf[bufidx] != 0; ++bufidx) {
chr = buf[bufidx];
Here is a single line version. Note this is not recommended practice because of the embedded assignment of chr inside the loop condition clause, but is for illustration purposes:
for (int bufidx = 0; (chr = buf[bufidx]) != 0; ++bufidx) {

Why is nothing being printed? C Programming

I'm making a program that takes the characters from congress.txt makes them all uppercase, then "shifts them two characters", (A goes to C) (Z goes to B). But nothing is being printed, my main concern is if my arrays are being stored and passed to the different functions properly.
This is what is in congress.txt:
Congress shall make no law respecting an establishment of religion, or prohibiting the free exercise thereof; or abridging the freedom of speech, or of the press; or the right of the people peaceably to assemble, and to petition the government for a redress of grievances.
#include<stdio.h>
int processFile(int *store);
int cipher(int *store, int *code);
int outputCode(int *code);
int main(void){
int store[300], code[300], i;
processFile(store);
cipher(store, code);
outputCode(code);
getchar();
return 0;
}
void processFile(int *store){
int i, a = 0;
FILE *f = fopen("congress.txt", "r");
for (i = 0; a != EOF;){
fscanf(f, "%c", &a); //store character in a
if (a <= 'Z' && a >= 'A'){ //store uppercase letters
store[i] = a;
i++;
}
if (a <= 'z' && a >= 'a'){ //store lowercase letters as uppercase
store[i] = a - 32;
i++;
}
}
i++;
store[i] = '\0';
}
void cipher(int *store, int *code){
int i;
for (i = 0; store[i] != 0; ++i){
if (store[i] <= 'X' && store[i] >= 'A'){ //tests to see if the letter is between A and X
code[i] = (char)(store[i] + 2); //shifts letter by two characters
}
if (store[i] >= 'Y' && store[i] <= 'Z'){
code[i] = (char)(store[i] - 24); //shifts Y and Z to A or B respectively
}
}
}
void outputCode(int *code){
int i, a, b;
for (a = 0; code[a] != 0; ++a){
if (!(a % 50)){ //makes a newline every 50 characters
printf("\n");
}
for (b = 0; code[a] != 0 && b <= 5; ++b){ //prints chunks of 5 characters then makes a space
printf("%c", code[a]);
}
printf(" ");
}
}
There are several things wrong with your code - many of which your compiler will complain about.
To start - you don't have return values for functions that are declared int. Just make them void, or return something.
Second - you declare int a; but proceed to use it like a char. Declare it how you use it.
Third - testing for end of file is done with feof(f) not a != EOF.
Fourth - when you output your code you need to increment a, otherwise you get the same value five times:
VVVVVV JJJJJJ KKKKKK UUUUUU KKKKKK UUUUUU UUUUUU
etc.
Fifth - your printing routine doesn't guarantee it will stop - if you have a single '\0' followed by other garbage, you will print more garbage (unless it happens on a multiple of 5). You need to pad your cipher with zeros.
So - working code:
#include<stdio.h>
int processFile(int *store);
int cipher(int *store, int *code);
int outputCode(int *code);
int main(void){
int store[300], code[300], i;
processFile(store);
cipher(store, code);
outputCode(code);
printf("\n=====\n\n");
return 0;
}
int processFile(int *store){
int i;
char a = 0;
FILE *f = fopen("congress.txt", "r");
for (i = 0; !feof(f) && i<299;){
fscanf(f, "%c", &a); //store character in a
if (a <= 'Z' && a >= 'A'){ //store uppercase letters
store[i] = a;
i++;
}
if (a <= 'z' && a >= 'a'){ //store lowercase letters as uppercase
store[i] = a - 32;
i++;
}
}
store[i]='\0';
return 0;
}
int cipher(int *store, int *code){
int i;
for (i = 0; store[i] != 0; ++i){
if (store[i] <= 'X' && store[i] >= 'A'){ //tests to see if the letter is between A and X
code[i] = (char)(store[i] + 2); //shifts letter by two characters
}
if (store[i] >= 'Y' && store[i] <= 'Z'){
code[i] = (char)(store[i] - 24); //shifts Y and Z to A or B respectively
}
}
for(; i<300; i++) code[i]=0; // pad with zeros
return 0;
}
int outputCode(int *code){
int i, a, b;
for (a = 0; code[a] != 0; ++a){
if (!(a % 50)){ //makes a newline every 50 characters
printf("\n");
}
for (b = 0; code[a] != 0 && b <= 5; ++b){ //prints chunks of 5 characters then makes a space
printf("%c", code[a++]);
}
printf(" ");
}
return 0;
}

Can't get user input using getchar() and pointer notation in C

I'm changing a program from normal array notation to pure pointer notation and I can't receive user input using getchar() in a while loop. I printed out was the program was receiving and it output upside down question marks. I wasn't sure why this was happening because I never changed the variable type. The problem is in the second function to receive user input. Thank you for the help.
#include <stdio.h>
#include <stdlib.h>
/* Function prototypes */
void fillS1(char * x);
void fillS2(char * x, char * y, char z);
void strFilter(char * a, char * b, char c);
int main(int argc, const char * argv[])
{
char s1[42];
char s2[22];
char x = 0;
fillS2(s2, s1, x);
return 0;
}
/* Function to generate a random string of 40 uppercase letters */
void fillS1(char randomlyGeneratedString[])
{
char * pointerToRandom = randomlyGeneratedString;
int i;
for (i = 0; i < 40; i++) {
*(pointerToRandom + i) = 'A' + rand() % 26;
}
pointerToRandom[40] = (char)0;
//printf("This is the generated string %s\n", pointerToRandom);
}
/* Function to get user input of characters */
void fillS2(char userString[], char randomString[], char replacementCharacter)
{
char * pointerToUserString = userString;
char * pointerToRandom = randomString;
int i = 0;
int n = 0;
int capitalLetterCheck = 0;
char loopContinue = 0;
char copyString[42];
char * pointerToCopyString = copyString;
fillS1(pointerToRandom);
do {
/* For loop to copy the first randomly generated string */
for(i = 0; i < 42; i++)
*(pointerToCopyString + i) = *(pointerToRandom + i);
i = 0;
capitalLetterCheck = 0;
/* While loop to to get user input */
printf("Please enter at least 2 capital letters and a maximum of 20.\n");
while (((*(pointerToUserString + i)) = getchar() != '\n')) {
/* Counter to determine how many characters were entered */
i++;
}
i++;
*(pointerToUserString + i) = '\0';
//printf("This is the value if i %i", i);
//printf("This is the user's string %s", pointerToUserString);
/* Capital letter check */
for (n = 0; n < 20; n++) {
if (((*(pointerToUserString + i)) >= 'A') && (*(pointerToUserString + i) <= 'Z'))
{
capitalLetterCheck++;
}
}
if (i < 3) {
printf("You need at least two letters\n");
}
else if (i > 21){
printf("You cannot have more than twenty letters\n");
}
else if (capitalLetterCheck >= 2) {
puts(pointerToUserString);
printf("Enter a character to replace occuring letters.\n");
scanf("%c", &replacementCharacter);
getchar();
strFilter(pointerToCopyString, pointerToUserString, replacementCharacter);
}
else
printf("You must have 2 capital letters.\n");
printf("Would you like to enter another string (y/n)?\n");
loopContinue = getchar();
getchar();
} while (loopContinue != 'n' && loopContinue != 'N');
}
/* Function to replace letters with the character chosen by the user */
void strFilter(char a[], char b[], char c)
{
char * pointerToA = a;
char * pointerToB = b;
int i = 0;
int n = 0;
while (n < 20) {
for (i = 0; i < 40; i++) {
if ((*(pointerToA + i)) == *(pointerToB + n)){
*(pointerToA + i) = c;
}
}
i = 0;
n++;
}
puts(a);
}
The problem is this in the if statement:
(*(pointerToUserString + i)) = getchar() != '\n'
Assignment is an expression, with lower precedence than comparison. This means the above is the same as:
(*(pointerToUserString + i)) = (getchar() != '\n')
So (*(pointerToUserString + i)) gets assigned the value of the expression getchar() != '\n' which is not what you want.

Resources