Strings, gets and do while - c

I'm doing an exercise in C but I have a problem when at the and I want to repeat the cicle (do while), infact if I type 1 the programme starts again by the top, but it doesn't stop at the gets(testo); . I tried plenty of ways to solve the bug without a solution, can anyone help me?
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
main(){
int cch, cw, i, j, w, ord, f; //counter and index
char testo[80];
char alfa[50][25];
char swap[25];
do{
cch=0;
cw=0;
j=0;
w=0;
f=0;
for(i=0;i<80;i++){
testo[i]='\0';
}
printf("Write the text:\n");
gets(testo);
//initialization 2d array
for(i=0;i<50;i++){
for(j=0;j<25;j++){
alfa[i][j]='\0';
}
}
j=0;
//Count word and characters
if(testo[0]!='\0'){
cw=1;
for(i=0;testo[i]!='\0';i++){
cch++;
if(testo[i]==' '){
cw++;
j++;
}
}
}
if(cch==j){
printf("You haven't written any word\n\n");
}
else{
//Don't count double space
for(i=0;i<cch;i++){
if(testo[i]==' ' && testo[i+1]==' '){
cw--;
}
}
//Don't count as word if the text start with a space
if(testo[0]==' '){
cw--;
w--;
}
printf("\nThe text is composed by %d characters\n", cch);
printf("The text is composed by %d words\n", cw);
if(cw>0){
printf("\nUsed words:\n");
for(j=0;j<cch;j++){
if(testo[j]==' ' && testo[j+1]==' '){
//nothing to do
}
else{
if(testo[j]!=' '){
alfa[w][f]=testo[j];
f++;
}
else if(testo[j]=='\0'){
alfa[w][f]='\0';
f=0;
w=0;
}
else{
alfa[w][f]='\0';
w++;
f=0;
}
}
}
for(i=0;i<cw;i++){
printf("%d> %s\n", i+1, &alfa[i]);
}
//order
f=1;
printf("\nWords used in alphabetical order:\n");
while(f==1){
f=0;
for(i=0;i<cw-1;i++){
ord=strcmp(alfa[i],alfa[i+1]);
if(ord>0){
strcpy(swap,alfa[i]);
strcpy(alfa[i],alfa[i+1]);
strcpy(alfa[i+1],swap);
f=1;
}
}
}
for(i=0;i<cw;i++){
printf("%d> %s\n", i+1, alfa[i]);
}
}
}
printf("\nDo you want write another text? (1=yes) -> ");
scanf("%d", &j);
}while(j==1);
}
I know that isn't very optimized as code at the moment and has other errors, but I'm having problem on this.
Thank you.
PS: The code is tested on OpenVMS

It's because the scanf call at the end of the loop doesn't read the newline. Instead this newline is read by your gets call.
A simple solution is to add a space to the end of the scanf format string, like so:
scanf("%d ", &j);
This will make scanf skip trailing whitespace in the input.
Another solution is to put an extra fgets after the scanf, but then don't add the extra space in the format string:
scanf("%d", &j);
fgets(testo, sizeof(testo), stdin);
Or use fgets to get the line, and then use sscanf to extract the answer:
fgets(testo, sizeof(testo), stdin);
sscanf(testo, "%d", &j);

Your first and most obvious problem is with the left over newline. When you use scanf() here:
printf("\nDo you want write another text? (1=yes) -> ");
scanf("%d", &j);
}
and you use the %d format specificer, the function is looking for a number, when you enter a number really you're entering a number and a newline character
> 1<enter key> // which means on stdin you're getting '1''\n'
scanf() only picks up the 1 and leaves the newline which your gets() function then picks up, so it looks like it's skipping the input. All you need to do is consume that newline character, one quick fix would be to consume it with getchar():
printf("\nDo you want write another text? (1=yes) -> ");
scanf("%d", &j);
getchar();
}
Now your program works as you'd expect.
Other issues of note:
Your main should really be returning an int type, even if it's just a return 0
You shouldn't be using gets(), even then man page for gets() says Never use gets(). That's usually a good indication not to. ;) So replace that line with fgets(testo, sizeof(testo), stdin);
You missed a performance specificer here: printf("\nThe text is composed by % characters\n", cch); so you're getting garbage output, that should have been %d

Or you can try using the function flushall() just before gets()

Related

How to de-allocate an array of characters in c?

I'm writing a program that asks the number of strings which i'll then count how many spaces it has.
My problem is when I start a new cycle I can't allocate the array of characters I use to count the spaces.
Thanks in advance.
#include <stdio.h>
#include <string.h>
int main(){
char a[20];
int x, z, esp=0, num;
scanf("%d\n", &num);
int array[num];
for (int i=0;i<num;i++){
scanf("%[^\n]", &a);
z =strlen(a);
for (x=0; x<=z; x++){
if (a[x] == ' '){
esp++;
}
}
array[i] = esp;
esp =0;
}
for (int i=0;i<num;i++){
printf ("%d\n", array[i]);
}
return 0;
}
Problems:
Not having all warnings enabled. Save time, enable them all.
'\n' blocks for more input in scanf("%d\n", &num);
Not checking scanf() return value.
Not limiting input with a width in scanf("%[^\n]", &a);
Wrong type passed in scanf("%[^\n]", &a);
Big one: not consuming the end-of-line with repeated scanf("%[^\n]", &a); calls.
Perhaps more.
Repaired code:
// scanf("%d\n", &num);
if (scanf("%d", &num) != 1) { // '\n' removed
puts("Error1");
return -1;
}
// scanf("%[^\n]", &a);
if (scanf(" %19[^\n]", a) != 1) { // ' ' consumes white-space like \n
puts("Error2");
return -1;
}
On the first scanf, remove \n character, after the first scanf, add getchar() to consume new line character.
Replace second scanf with gets;
Then it will work correctly.
By the way, since gets is unsafe, you can use fgets with stdin parameter and max character count parameter instead of gets.
Thanks to everyone who commented and answered my question, I think I wasn't able to explain myself properly. It's a code which reads a number, the number of the lines of characters which then it'll count the spaces of; my problem started when the code executes a new cycle in which this scanf didn't let me enter the string of characters again: scanf("%[^\n]", &a), but did everything else in the cycle while using the same string.
I'm really new to this, coding and the page itself so thanks for the advices. I was able to find a solution: scanf("%[^\n]%*c, &a)
%*[^\n] scans everything until a \n, but doesn't scan in the \n. The asterisk(*) tells it to discard whatever was scanned.
%*c scans a single character, which will be the \n left over by %*[^\n] in this case. The asterisk instructs scanf to discard the scanned character.
And here is the updated code:
#include <stdio.h>
#include <string.h>
int main(){
char a[20];
int x, z, esp=0, num;
scanf("%d\n", &num);
int array[num];
for (int i=0;i<num;i++){
scanf("%[^\n]%*c", &a);
z =strlen(a);
for (x=0; x<=z; x++){
if (a[x] == ' '){
esp++;
}
}
array[i] = esp;
esp =0;
}
for (int i=0;i<num;i++){
printf ("%d\n", array[i]);
}
return 0;
}

Parsing an integer in a string

I am trying to get an integer separated by space in a string, the sample input and outputs I expected are :
i : word 1
o : 1
i : word 20
o : 20
I tried doing it like this:
scanf("word %d", &num);
but it doesn't work.
I also tried this:
scanf("%[^/]*c%d", &num);
or
scanf("%[^/] %d", &num);
But still, none of them works. Can anyone give me a tip on how to do this? Thanks
Note : the output integer doesn't have a space in front of it.
Full code :
int t, num;
char word[1000];
int arr[100], arr2[100];
fgets(word, 1000, stdin);
scanf("%d", &t);
while(t--){
scanf("word %d", &num);
printf("%d\n", num);
}
As you can see in the above sample code, I am also taking more inputs before taking the input for num.
The first code just needs a space before the scanf text sequence to discard any blank characters that are left in stdin from previous reads, you can, however, improve it further to recongize bad inputs and discard them if that is the case:
while(t){
if(scanf(" word %d", &num) == 1){ //space before word
printf("%d\n", num);
t--;
}
}
But if you want to use that regex specifier you cand do something like:
while(t){
if(scanf("%*[^ ]%d", &num)){
printf("%d\n", num);
t--;
}
}
This would work not only for word but for any other string, provided that it only has one word, i.e. no spaces, apart from the one in the end.

Scanning multidimensional string with space in c

I'm trying to make a simple voucher. So, I used a multidimensional string. But facing trouble including space in those strings. Instead, I took words as input. But is there any way to include space? My code is given below-
#include<stdio.h>
#include<string.h>
int main(){
int sum =0, n, i;
puts("Please input how many transactions you want to enlist: ");
scanf("%d", &n);
char list[301][51];
int amount[301];
puts("Please enter the name of your transaction and the amount: (Press space or enter to toggle between name and amount . And avoid using spaces in the name; use underscore instead.)");
for(i=0; i<n; i++){
scanf("%s %d", &list[i], &amount[i]);
sum += amount[i];
}
list[0][n+1] = '\0';
amount[n+1] = '\0';
puts("");
printf("\t\t\t\t Voucher\n\n");
puts(" Ser.|\t Name \t\t\t\t\t\t\t|Amount");
puts("------------------------------------------------------------------------------------------------------------");
for(i=0; i<n; i++ ){
printf(" %03d |\t %-50s\t|%6d\n", i+1, list[i], amount[i]);
}
puts("------------------------------------------------------------------------------------------------------------");
printf(" | Total\t\t\t\t\t\t\t|%6d", sum);
puts("");
return 0;
}
For this you could use the %[ scanf specifier, to read all characters until you hit a digit, and write it into list[i].
This will leave you with a trailing space in list[i], but that can be trimmed if you don't want it.
The scanf call could then look something like
scanf(" %50[^0-9]%d", list[i], &amount[i]);
Note the leading space in the format string, to tell scanf to skip white-space (like the newline from the previous line), and the width-specifier to not read more than can fit in line[i].
Of course, that prevents you from having numbers inside the string you read. To solve this problem you need to go a more complicated route.
For example by reading the whole line into a buffer, and then find the last space in the string. You can then copy the contents before the last space to list[i], and convert the contents after to an int value for amount[i].

2D char array (Storing text with the spacebar in an one char array element?)

Acc. to this post, the most used method to store text in a 2D array is by using %s approach. But, this approach has a downfall, i.e. whenever you press spacebar, the text which is typed after goes into the second element of array. for e.g. you typed
Input:-
1st element of char array = Hi everyone
Output:-
1st element of char array = Hi
2nd element of char array = everyone
Expected output:-
1st element of char array = Hi everyone
So, i want to ask why the below written approach cannot be used to enter text into a 2D array?
#include <stdio.h>
int main()
{
char ch[20];
printf("Enter name:");
scanf("%19[^\n]", ch);
printf("Your name is: %s", ch);
return 0;
}
If the above approach can be used, then please let me know how?
Please do not introduce pointer concepts/code in answer to this post. This is a question to understand why the above written approach fails.
Consider this as the code which fails:-
#include <stdio.h>
int main()
{
char name[4][20];
int i;
printf("Enter names:-\n");
for(i=0; i<4; i++)
{
printf("Enter name %d: ", i);
scanf("%19[^\n]", name[i]);
printf("\n");
}
for(i=0; i<4; i++)
{
printf("Entered name %d: %s", i, name[i]);
printf("\n");
}
return 0;
}
The above program compiles without any error or warning, but fails during runtime.
The problem in the example you provided is that the newline is left in the buffer. You can discard this leading whitespace by changing this:
scanf("%19[^\n]", &name[i]);
To this
scanf(" %19[^\n]", &name[i]);
Note the space before %19. With this, your program prints:
Enter names:-
Enter name 0: foo
Enter name 1: bar
Enter name 2: baz
Enter name 3: qux
Entered name 0: foo
Entered name 1: bar
Entered name 2: baz
Entered name 3: qux
This is because the %[^\n] specifier tells it to take everything but the newline. So the newline will be left in the buffer, and when scanf is called again, it is the first thing in the buffer, so those additional calls can't take any input.
That leading space in the scanf fixes the problem, because it tells scanf to discard any trailing whitespace, which includes that newline left in the buffer.
This is what a reference says about it:
Whitespace character: the function will read and ignore any whitespace characters encountered before the next non-whitespace
character (whitespace characters include spaces, newline and tab
characters -- see isspace). A single whitespace in the format string
validates any quantity of whitespace characters extracted from the
stream (including none).
Figured out another approach to get it done.
#include <stdio.h>
int main()
{
char name[4][20];
int i;
printf("Enter names:-\n");
for(i=0; i<4; i++)
{
printf("Enter name %d: ", i);
scanf("%19[^\n]", name[i]);
fflush(stdin);
printf("\n");
}
for(i=0; i<4; i++)
{
printf("Entered name %d: %s", i, name[i]);
printf("\n");
}
return 0;
}

Why does scanf skip getting string input? [duplicate]

This question already has an answer here:
How to read / parse input in C? The FAQ
(1 answer)
Closed 5 years ago.
I am trying to get multiple words input and multiple lines into one array. But somewhere the code skips getting the input and skips to end the program. I have tried adding space before and after the ' %s' (or '%s ') but it won't work (maybe because it's inside a loop?). Would really appreciate anyone's help! It also starts to act weird if I enter more than two-three words :(
My goal is to find how many times a specific letter has occurred throughout all those words and lines.
#include <stdio.h> //include standard library
int main(){
int lineCount, occuranceCount;
printf("How many lines are you going to enter?");
scanf("%d", &lineCount);
char input[lineCount][100], searchChar;
for(int i=0; i<lineCount; i++){
printf("Please enter line #%d (100 characters of less):",i+1);
scanf("%s", &input[i]);
}
printf("What letter do you want to check the frequence in those lines? ");
scanf("%c", &searchChar);
for(int j=0; j<lineCount; j++){
for(int k=0; k<100; k++){
if(input[j][k] != '\0'){
if(input[j][k]==searchChar)
occuranceCount++;
}
}
}
printf("The letter occurs for %d time", occuranceCount);
return 0;
}
scanf(" %c", &searchChar);
^
You need the space over here to consume any \n from stdin.
Also scanf() will read one word not a line(space separated words) as you are thinking.
And also it is better to use strlen(input[j]) to know how much you should read.
Another thing, use size_t instead of int in the looping.
Intialize occuranceCount to 0.
Also to avoid buffer overrun exploits use scanf("%99s", input[i]); in your code.
In order to read a line you can use fgets().
1) Change
scanf("%c", &searchChar); --> scanf(" %c", &searchChar);
to get rid of any \n left in the input buffer from previous scanf
2) Change
for(int k=0; k<100; k++){ --> for(int k=0; k<strlen(input[j]); k++){
to avoid reading beyond the actual user input.
Besides that:
Never do scanf("%s", &input[i]); as the user can overflow your input buffer. At least change it to: scanf("%99s", &input[i]); but consider using fgets instead
Using fgets your program could be:
#include <stdio.h>
int main(){
size_t lineCount = 0, occuranceCount = 0;
printf("How many lines are you going to enter?");
scanf("%zu ", &lineCount);
if (lineCount == 0) return 0; // Input error
char input[lineCount][100], searchChar;
for(size_t i=0; i<lineCount; i++){
printf("Please enter line #%zu (100 characters of less):",i+1);
fgets(input[i], 100, stdin);
}
printf("What letter do you want to check the frequence in those lines? ");
scanf("%c", &searchChar);
for(size_t j=0; j<lineCount; j++){
for(size_t k=0; k<strlen(input[j]); k++){
if(input[j][k]==searchChar) occuranceCount++;
}
}
printf("The letter occurs for %zu time", occuranceCount);
return 0;
}
scanf using the %s always read until a ' '(whitespace) or '\n'(new line) is encountered, so you always can read only one word with scanf("%s", s1)...
if you want to read the spaces or new line characters you must use gets, or fgets(more secure than gets)

Resources