How to avoid entering strings already present in a list - c

In this piece of code I'm trying to check if a string (in my case the name of a club) is already entered from standard input. My goal is to avoid entering a name already present in the list, but it doesn't work.
Can someone help me please?
Thanks all.
gets(club[i].name);
if(i != 0){
for(left = 0; left < i; left++){
for(right = i; right > 0; right--){
outcome = strcmp(club[left].name, club[right].name);
if(outcome == 0){
printf("You already entered this team. Pick another one: \n");
gets(club[i].name);
}
}
}
}
i++;
break;

I'm not sure about the algo. (Besides, use fgets instead of gets)
You should compare against [i], not the other values.
This is simpler than the algo left/right:
int ok = 1;
for(int j = 0; j < i && ok ; j++){
ok = strcmp(club[j].name, club[i].name);
}
if ( ! ok) {
// ask again on the same 'i'
}
AFAIU, i is the last item, so j goes from 0 to i-1.
You don't need nested loops, because each input has already been checked against the previous ones. So when a new one comes, you only need to compare it with the previous values.
edit: If n is the number of items (item i is currently being input, but is not always the latest one), use that algo instead
int ok = 1;
for(int j = 0; j < n && ok ; j++){
ok = j == i || strcmp(club[j].name, club[i].name);
}
if ( ! ok) {
// ask again on the same 'i'
}

Just talk about your logic. Except for redundant comparisons, I think you need to reset the value of left and break inner loop.
Following your logic, the code should be:
gets(club[i].name);
if(i != 0){
for(left = 0; left < i; left++){
for(right = i; right > 0; right--){
outcome = strcmp(club[left].name, club[right].name);
if(outcome == 0){
printf("You already entered this team. Pick another one: \n");
gets(club[i].name);
left = 0;
break;
}
}
}
}
i++;
break;

Related

Array pointer while loop input

I am trying to write a program to check for duplicate input from a programmable handheld barcode scanner, I am programming it to be able to scan 2000 barcodes.
I am new to c Programming, I am trying to take an input and put it into the array and increase the pointer to the next with every loop.
Example: int Array [10];
I want to scanf() into Array location 0 on the first loop then increment by 1 location to location 2 etc every time the while loops runs. Please help, your help is much appreciated.
#include <stdio.h>
int main ()
{
int i,j,k=1,arr[2000],ArrSize=2000;
//Welcome message
printf("Welcome to Yamato Transport (S) Pte. Ltd.\n");
printf("Barcode checker Ver 1.0\n");
while (k>=2000,k++)
{
//Scanner Input
for(i=0;i<ArrSize;i++)
{
scanf("%d",&arr[i]);
}
//Duplicate Logic
printf("Duplicate Barcodes: ");
for(i=0; i<ArrSize; i++)
{
for(j=i+1;j<ArrSize;j++)
{
if(arr[i]==arr[j])
{
printf("%d\n",arr[i]);
}
}
}
//Remove single duplicate
//Clear Screen
}
return 0;
}
The first problem with your code is this:
int i,j,k=1,...
...
while (k>=2000,k++)
^^^^^^
ups...
This will give the warning "left-hand operand of comma expression has no effect" which actually means that the line is the same as:
while (k++)
That will keep looping until you have integer overflow (which is undefined behavior). So you don't want to do that.
Since you initialize k to 1, I assume that you wanted to do:
while (k++ < 2000)
Now let's assume that you want:
while (k++ < 2000) // Will loop approx 2000 times
{
//Scanner Input
for(i=0; i< ArrSize; i++) // Will loop 2000 times
{
scanf("%d",&arr[i]);
}
So in the end your program calls scanf 2000 x 2000 = 4.000.000 times. Is that what you want? The purpose of the outer while is unclear.
Your program first reads 2000 integers and afterwards it seems you want to remove duplicates. That's a bad approach as you may end you doing a lot of memory move whenever you need to remove a duplicate element from the array.
A better approach is to check whether a newly scanned value is a duplicate before inserting it in the array. That could look something like:
for(i=0; i < ArrSize; )
{
int tmp;
if (scanf("%d", &tmp) != 1)
{
// Input error
exit(1);
}
// Check if tmp is already in the array
int duplicate = 0;
for (int j = 0; j < i; ++j)
{
if (tmp == arr[j])
{
duplicate = 1;
break;
}
}
if (duplicate)
{
printf("dup found\n");
}
else
{
arr[i] = tmp;
++i;
}
}
This should give you ArrSize unique elements.
Notice: In order to check if something is a duplicate, you'll need to scan through the array from start to the current number of elements. To improve performance you could consider another approach, e.g. a sorted tree, hash tables, etc so that check for duplicates can be done much faster. This gets more important as the number of array elements increase.
So half the problem is solved, I am still not sure how do I increase the pointer to the next position so on the next loop it will store another barcode number which will then be passed to the duplicate checker for checking then repeat the loop for the next scan.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int i,j,k=1,arr[2000],counter=1;
//Welcome message
printf("Welcome to Yamato Transport (S) Pte. Ltd.\n");
printf("Barcode checker Ver 1.0\n");
while (k++ < 2000) // Will loop approx 2000 times
{
//Scanner Input
printf("Scan barcode\n");
for(i=0; i< counter; i++) // Will loop 1 time
{
scanf("%d",&arr[i]);
}
//check for duplicates
for(i=0; i < counter; )
{
int tmp;
if (scanf("%d", &tmp) != 1)
{
// Input error
exit(1);
}
// Check if tmp is already in the array
int duplicate = 0;
for (int j = 0; j < i; ++j)
{
if (tmp == arr[j])
{
duplicate = 1;
break;
}
}
if (duplicate)
{
printf("Duplicate Barcode\n");
}
else
{
arr[i] = tmp;
++i;
}
}
}
return 0;
}

Terminate an array input taking when input is -1 without using break?

I am taking input in an array of length 100 using scanf in a loop. After 20 numbers, if I enter -1, I want the loop to exit, i.e finish taking input and continue with the rest of the program. I am doing something like this
for(i=0;i<100;i++)
{
scanf("%d", &input[i]);
if(input[i] == -1)
{
break;
}
}
I heard, it is bad practice to use break statements even though this code works perfectly fine. So I was wondering what is a more efficient way to end the loop when -1 is entered. I tried
for(i=0;scanf("%d",&input[i])!=-1;i++)
also
fori(i=0;i<100;i++){
do
{scanf("%d", &input[i]);
}while(input[i]!=-1
}
Neither of these don't work
The second expression of the for loop is a free-form boolean expression. In this case you could add your condition there. However in this case it wouldn't look exactly nice. For example
for(i=0; i < 100 && (i < 1 || input[i - 1] != -1); i++)
{
scanf("%d", &input[i]);
}
I.e. if we have already input one value, check the value and that must be inequal to -1 for the loop to continue
Another would be to use a synthetic flag variable:
int loop_again = 1;
for (i = 0; loop_again && i < 100; i++) {
scanf("%d", &input[i]);
if(input[i] == -1)
{
loop_again = 0;
}
}
All in all, these both look way uglier than just using the break statement for the very thing that it was invented for.
Note that you also should check the return value of scanf itself!
it is bad practice to use break statements
As Ancient Greeks said, "Pan Metron Ariston", which means that everything that is used with balance is great. This applies here too, and your code as is, is good to go. The only thing to be worried about is not checking the return value of scanf().
Now if you really insist on changing your approach, then please refer to Haapala's answer, we got there first.
You can use a while loop and check for -1 in the input in the loop conditional. Note that you should always check the value returned by scanf(). In the posted code, non-numeric input results in no value being stored in input[]; this may lead to undefined behavior later if the code attempts to use an indeterminate value.
Here is an example. Note that the loop conditional first checks whether the array index has grown too large, then checks the return value from scanf() to be sure that a number was entered, then checks to see if -1 was entered. In the case of non-numeric input, the loop is terminated.
#include <stdio.h>
#define INPUT_SZ 100
int main(void)
{
int input[INPUT_SZ];
size_t i = 0;
while (i < INPUT_SZ && scanf("%d", &input[i]) == 1 && input[i] != -1) {
++i;
}
puts("You entered:");
for (size_t j = 0; j < i; j++) {
printf("%d\n", input[j]);
}
return 0;
}
Sample interaction:
2 4 6 8 -1
You entered:
2
4
6
8
You can simply change the value of counter variable to max, then it'll automatically come out of loop.
#include<stdio.h>
#define MAX 10
int main()
{
int ar[MAX], i, count;
for(i=0; i<MAX; i++)
{
scanf("%d", &ar[i]);
if(ar[i]==-1)
{
count=i--; //this is your new MAX. Not mandatory but will be useful if you need to access array elements
i=MAX;
}
}
//printing array
for(i=0; i<count; i++)
{
printf("Element %d: %d\t", i+1, ar[i]);
}
return 0;
}
Hope this helps.
Use a do-while loop
int i=0;
do{
if(scanf("%d", &input[i++]) != 1)
{
if(i>0)
--i; // Decrementing i if an integer is not provided
int ch;
while ((ch = getchar()) != '\n' && ch != EOF) // Wasting the buffer
;
}
}while(input[i-1] != -1 && i<=99);

Storing a number so that it wont be redefined the next iteration of the loop

I am trying to write a loop that will count the total number of words inputted as well as the number of words on the given line. Total words is cumulative, however, words on a given line is not. How would I store this number outside of the loop so that it will not be redefined in the next iteration?
My idea was to store them into an int array and just display the array afterwards, however this proved more difficult than anticipated.
Here's an Example:
Hello World
cats and dogs
OUTPUT:
5 words total
2 3 //2 on line one and 3 on line two
This is what I have thus far:
char lines[50];
int numOfLines = 0;
int numOfWords = 0
int i;
int wordsPerLine[50]; //Unused at this point
for(i = 1; i <= 1000; i++){
fgets(lines,50,stdin);
if (strcmp(lines, ".\n") == 0){
break;
}
numOfLines++;
for (i = 0; i < strlen(lines); i++){
if(lines[i] == ' '){
numOfWords++;
wordsPerLine[i] = numOfWords; //everything works up until here
}
}
}
for (i = 0; i < numOfLines; i++){
printf("%d ", wordsPerLine[i]); //trying to print out the array where I'd hope to store them, however I get a bunch of random numbers
}
Here are your issues:
You reuse i for the control variable in the inner loop, so it interferes with the outer loop. Use a separate variable for this (j).
In the outer loop, you start counting at 1, so wordsPerLine[0] never gets set. Start this loop at 0.
You set wordsPerLine[i] to the current value of numOfWords which is the total number of words. Instead, set this value to 0 before the loop and increment on each iteration.
You need to check for a newline when counting words, otherwise you won't count the last one.
After these changes, your code should look like this:
for(i = 0; i <= 1000; i++){
fgets(lines,50,stdin);
if (strcmp(lines, ".\n") == 0){
break;
}
numOfLines++;
wordsPerLine[i] = 0;
for (j = 0; j < strlen(lines); j++){
if(lines[j] == ' ' || lines[j] == '\n'){
numOfWords++;
wordsPerLine[i]++;
}
}
}
EDIT:
Changed how wordsPerLine and numOfWords are managed so numOfWords contains the total words when the outer loop finishes.
The problem, as I see it is you're trying to use the same variable i twice as counters for two separate loops which leads to wrong logic.
Use a separate counter for the outer loop, say, j and use that variable to index wordsPerLine outside the inner loop, at the end of body for outer loop.
Use different counter in the nested for loop and reset the numofWords
char lines[50];
int numOfLines = 0;
int numOfWords = 0;
int i, j;
int wordsPerLine[50]; //Unused at this point
for(i = 1; i <= 1000; i++){
fgets(lines,50,stdin);
if (strcmp(lines, ".\n") == 0){
break;
}
for (j = 0; j < strlen(lines); j++){
if(lines[j] == ' ' || lines[j] == '\n'){
numOfWords++;
wordsPerLine[numOfLines]++; //everything works up until here
}
}
numOfLines++;
}
for (i = 0; i < numOfLines; i++){
printf("words in %d is %d\n", i, wordsPerLine[i]); //trying to print out the array where I'd hope to store them, however I get a bunch of random numbers
}
printf("total words is %d\n", numOfWords);

replace rows of n(n>=2) '*' symbols with n/2 '+' symbols

Only using getchar() and putchar(). For example having entered "asf****f*d" you get "asf++f*d". The signal of the input's end is the symbol '.'. My best attempt is:
char c = 0, flag = 0; int k = 0;
while ((c = getchar()) !='.')
{
if (c == '*') { k++; flag = 1; } else putchar(c);
if (flag)
{
if (c != '*')
{
flag = 0;
if (k == 1) { putchar('*'); k = 0; continue; }
for (int i = 0; i< k/2; i++)
putchar('+');
k = 0;
}
}
}
This code does not work. I tried to swap those two if's:
char c = 0, flag = 0; int k = 0;
while ((c = getchar()) !='.')
{
if (flag)
{
if (c != '*')
{
flag = 0;
if (k == 1) { putchar('*'); k = 0; continue; }
for (int i = 0; i< k/2; i++)
putchar('+');
k = 0;
}
}
if (c == '*') { k++; flag = 1; } else putchar(c);
}
but after doing that symbols after single '*' are not printed, that is inputting "asf****f*d" I get "asf++f*"
Your second attempt had the best chance of success, but the flow of control got messed up due to your use of continue. Many people find comfort in this statement, but in this case it is just a bad goto. Please use else to escape your nested ifs; draw an NSD if you find this difficult. Currently, continue skips the putchar(c) in your second code sample, which explains the loss of the character following the single star.
There is another issue though; if the closing period is immediately preceded by a list of stars, then the replacement plusses will not be printed. This is caused by the fact that you save up all stars and print the replacing plusses all in one go. This 'buffering' demands a 'flush'. Though this is not difficult (print the pending plusses after the outer loop has finished), it does make your code messier. I strongly recommend to slightly change your algorithm. Instead of saving up stars, just print a single plus for every second star. This will make your code simpler and cleaner, and a 'flush' is no longer necessary.
I could of course give you a complete solution, but where's the fun in that?

rewrite c expression without continue and break

In a school exercise (on paper) i've this question:
5) rewrite the code without using continue and break:
for (i = 0; i < N; i++) {
scanf("give me an int %d", & a);
if (a < 0) {
continue;
}
if (a == 0) {
break;
}
/* elaborate positive int */
}
I'm thinking about this:
for(i=0;i<N;i++){
scanf("give me an int %d",&a");
if(a==0){return -1; //??i dont know how to exit}
if(a<0){
do{
scanf("give me an int %d",&a");
if(a==0){return -1; //??i dont know how to exit}
}while(!(a<0))
}
/* elaborate positive int */
}
but, I'm actually not able to do this.. can you help me? thanks :)
Might not be what your teacher wants but that's actually the easiest way:
a = INT_MAX;
for(i = 0; i < N && a != 0; i++) {
scanf("give me an int %d", &a);
if(a > 0) {
/* elaborate positive int */
}
}
The reason for not using return is that you just want to exit/restart the loop. The function could contain more stuff that should not be skipped.
And that scanf call looks wrong.. do you really want to enter "give me an int .." everytime?
for(i = 0; i < N && a != 0; i++)
{
scanf("give me an int %d",&a");
if(a>0)
{ /*do stuff*/ }
}
if(a==0) i--; //As noted by Daniel Fischer
Not going to give you full code, but:
remember you can add conditions inside the clause of the for statement. (hint: move the breaking condition there to terminate the loop)
does the continue actually do anything in your example?
In this specific case, not much needs to be done. Since a < 0 and a == 0 are mutually exclusive conditions, an if-else-if statement could be used as follows:
for (i = 0; i < N; i++)
{
scanf("give me and int %d", &a);
if (a < 0)
// Do something or nothing here, but this skips the rest of the loop
// body just like continue would.
else if (a == 0)
i = N; // This satisfies the loop condition, so it won't loop again
// just like break would.
}
This is not a general solution, but it should give you the proper behavior in this case.

Resources