Incorrect output using strcmp - c

I'm doing the day 8 of the 30 days of code in HackerRank and I am having a problem with strcmp.
The code asks the user for names of people and their numbers, then asks for other names, if a name wasn't entered before, then it outputs Not found, but if it was then it outputs the name and his number. But for some reason, the output only works in the last loop of the for statement.
Code:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
typedef struct {
char name[100];
int number;
} phonebook;
int main() {
int n = 0;
do {
scanf("%i", &n);
} while (n < 1 || n > 100000);
int i = 0;
phonebook people[n];
for (i = 0; i < n; i++) {
scanf("%s %i", people[i].name, &people[i].number);
}
char othernames[n][100];
for (i = 0; i < n; i++) {
scanf("%s", othernames[i]);
}
for (i = 0; i < n; i++) {
if (strcmp(othernames[i], people[i].name) == 0) {
printf("%s=%i\n", people[i].name, people[i].number);
} else {
printf("Not found\n");
}
}
return 0;
}

You didn't find the othernames from the beginning to end to compare peopleevery time, so you need to replace
for (i = 0; i < n; i++) {
if (strcmp(othernames[i], people[i].name) == 0) {
printf("%s=%i\n", people[i].name, people[i].number);
}
else {
printf("Not found\n");
}
}
to
bool found = false;
for (i = 0; i < n; i++) {
for ( j = 0 ; j < n ; j++ ) {
if (strcmp(othernames[j], people[i].name) == 0) {
printf("%s=%i\n", people[i].name, people[i].number);
found = true;
}
}
}
if ( found == false ) printf("Not found\n");

The problem is othernames should just be an array of char, not a matrix. And for each othername entered, you must scan whole phonebook to find it or display Not found. As coded, you only test if the i-th othername typed happens to correspond to the i-th entry in the phone book.
Here is a modified version:
#include <stdio.h>
#include <string.h>
typedef struct {
char name[100];
int number;
} phonebook;
int main() {
int n = 0;
do {
if (scanf("%i", &n) != 1)
return 1;
} while (n < 1 || n > 100000);
phonebook people[n];
for (int i = 0; i < n; i++) {
if (scanf("%99s %i", people[i].name, &people[i].number) != 2)
return 1;
}
for (int i = 0; i < n; i++) {
char othername[100];
if (scanf("%99s", othername) != 1)
break;
int j;
for (j = 0; j < n; j++) {
if (strcmp(othername, people[j].name) == 0) {
printf("%s=%i\n", people[i].name, people[i].number);
break;
}
}
if (j == n) {
printf("Not found\n");
}
}
return 0;
}
Note that it is probably not a good idea to store phone numbers as int values. Better use a char array so an initial 0 is significant and to store longer numbers.

Related

How to detect duplicate string using strcmp()

#include<stdio.h>
#include<stdio.h>
#include<string.h>
struct stud
{
char nam[20];
int num;
char letter[5];
};
int main()
{
struct stud s[5];
int i, j;
for(i = 0; i < 5; i++){
printf("Enter the name of student #%d: ", i+1);
scanf("%s", s[i].nam);
printf("Enter the number grade of student #%d: ", i+1);
scanf("%d", &s[i].num);
}
for (j = 0; j < i; j++) {
if (strcmp(s[i].nam, s[j].nam) == 0)
printf("Error. Duplicate name detected.");
}
for(i = 0; i < 5; i++){
if(s[i].num >= 90 )
strcpy(s[i].letter, "A");
else if(s[i].num >= 80)
strcpy(s[i].letter, "B");
else if(s[i].num >= 70)
strcpy(s[i].letter, "C");
else if(s[i].num >= 60)
strcpy(s[i].letter, "D");
else
strcpy(s[i].letter, "F");
}
for(i = 0; i < 5; i++)
printf("\n%s has a %s ", s[i].nam, s[i].letter);
return 0;
}
This program has the user enter 5 names and 5 numeric grades, which will then result in the output of their respective letter grades for that student. I'm trying to make it so if the user enters a duplicate name, and message will print saying they can't do that. My attempt in trying to do this is as follows:
for (j = 0; j < i; j++) {
if (strcmp(s[i].nam, s[j].nam) == 0)
printf("Error. Duplicate name detected.");
}
Where I believe that s[j] is the previous string, and compare to see if it equals 0(duplicate) and prints a message. This obviously doesn't work however so I would like to know how to fix this so it can correctly detect duplicate names. Thank you.
Also I have posted this question before but the person that provided an explanation deleted their response before I could provide further questions and ask for clarification. So I am posting this again with an attempt in seeking further aid in what I did wrong in my code.
At the start of the detection loop, i is already 5, so using s[i] is undefined behavior
In your detection loop, i is invariant. you are just comparing a name against the last one [except for the UB, of course].
You need two loops to compare all names against one another.
Also, using 5 everywhere is a "magic number". Better to use a #define (e.g. SMAX)
In the code below, I use cpp conditionals to denote old vs. new code:
#if 0
// old code
#else
// new code
#endif
#if 1
// new code
#endif
Here is the corrected code. It is annotated with the bugs and fixes:
#include <stdio.h>
#include <stdio.h>
#include <string.h>
struct stud {
char nam[20];
int num;
char letter[5];
};
#define SMAX 5 // maximum number of students
int
main()
{
struct stud s[SMAX];
int i, j;
for (i = 0; i < SMAX; i++) {
printf("Enter the name of student #%d: ", i + 1);
scanf("%s", s[i].nam);
printf("Enter the number grade of student #%d: ", i + 1);
scanf("%d", &s[i].num);
}
// NOTE/BUG: i is already SMAX, so using s[i] is UB (undefined behavior)
// NOTE/BUG: i never changes
#if 0
for (j = 0; j < i; j++) {
if (strcmp(s[i].nam, s[j].nam) == 0)
printf("Error. Duplicate name detected.");
}
#else
for (i = 0; i < (SMAX - 1); i++) {
for (j = i + 1; j < SMAX; j++) {
if (strcmp(s[i].nam, s[j].nam) == 0)
printf("Error. Duplicate name detected -- %s\n",s[j].nam);
}
}
#endif
for (i = 0; i < SMAX; i++) {
if (s[i].num >= 90)
strcpy(s[i].letter, "A");
else if (s[i].num >= 80)
strcpy(s[i].letter, "B");
else if (s[i].num >= 70)
strcpy(s[i].letter, "C");
else if (s[i].num >= 60)
strcpy(s[i].letter, "D");
else
strcpy(s[i].letter, "F");
}
// NOTE/BUG: newline should go at the end of the printf to prevent a hanging
// last line
#if 0
for (i = 0; i < SMAX; i++)
printf("\n%s has a %s ", s[i].nam, s[i].letter);
#else
for (i = 0; i < SMAX; i++)
printf("%s has a %s\n", s[i].nam, s[i].letter);
#endif
return 0;
}
UPDATE:
Thanks for the tip! On a side note, how would I make it so while the user is entering the duplicate names, the error message appears and the program ends right there.For example: Enter the name of student 1: dan Enter grade: 87 Enter the name of student 2: dan Enter the grade: 78 Error. No duplicate names allowed. And then the program ends there. –
User234567
Easy enough. I put the duplication detection code into functions.
But, I've added a few more enhancements so this may help you with your learning ;-)
I added reprompting the user if they enter a duplicate.
I hate scanf ;-) I reworked the prompting code by putting it into two functions. It will work better if input is a file. This is useful during testing
I changed the conversion from grade number to grade letter to use a table.
Anyway, here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
struct stud {
char nam[20];
int num;
char letter[5];
};
struct letter {
int num;
const char *letter;
};
#define LET(_num,_let) \
{ .num = _num, .letter = _let }
struct letter letters[] = {
LET(90,"A"),
LET(80,"B"),
LET(70,"C"),
LET(60,"D"),
LET(0,"F"),
LET(0,NULL)
};
#define SMAX 5 // maximum number of students
// chkall -- check entire array for duplicates
int
chkall(const struct stud *s,int smax)
{
int i;
int j;
int dup = 0;
for (i = 0; i < (smax - 1); i++) {
for (j = i + 1; j < smax; j++) {
if (strcmp(s[i].nam, s[j].nam) == 0) {
printf("Error. Duplicate name detected -- %s\n",s[j].nam);
dup += 1;
}
}
}
return dup;
}
// chkone -- check a given entry for duplicate (as they are added)
int
chkone(const struct stud *s,int i)
{
int j;
int dup = 0;
for (j = 0; j < i; j++) {
if (strcmp(s[i].nam, s[j].nam) == 0) {
printf("Error. Duplicate name detected -- %s\n",s[j].nam);
dup += 1;
}
}
return dup;
}
// prompt_string -- prompt user for a string
char *
prompt_string(const char *what,int i,char *buf,size_t siz)
{
static int tty = -1;
// decide if our input is tty or file
if (tty < 0) {
struct winsize ws;
tty = ioctl(0,TIOCGWINSZ,&ws);
tty = (tty >= 0);
}
printf("Enter the %s of student #%d: ", what, i + 1);
fflush(stdout);
char *cp = fgets(buf,siz,stdin);
do {
// handle EOF
if (cp == NULL)
break;
buf[strcspn(buf,"\n")] = 0;
// echo the data if input is _not_ a tty
if (! tty)
printf("%s\n",buf);
} while (0);
return cp;
}
// prompt_number -- prompt user for a number
long long
prompt_number(const char *what,int i)
{
char *cp;
char buf[100];
long long val;
while (1) {
cp = prompt_string(what,i,buf,sizeof(buf));
// handle EOF
if (cp == NULL) {
val = -1;
break;
}
// decode the number
val = strtoll(buf,&cp,10);
if (*cp == 0)
break;
printf("invalid number syntax -- '%s'\n",cp);
}
return val;
}
int
main(void)
{
struct stud s[SMAX];
int i;
for (i = 0; i < SMAX; i++) {
while (1) {
prompt_string("name",i,s[i].nam,sizeof(s[i].nam));
if (! chkone(s,i))
break;
}
s[i].num = prompt_number("number grade",i);
}
// recheck all entries
// this will _never_ report a duplicate because of the chkone above
chkall(s,SMAX);
for (i = 0; i < SMAX; i++) {
for (struct letter *let = letters; let->letter != NULL; ++let) {
if (s[i].num >= let->num) {
strcpy(s[i].letter,let->letter);
break;
}
}
}
for (i = 0; i < SMAX; i++)
printf("%s has a %s\n", s[i].nam, s[i].letter);
return 0;
}

Why do i have a segmentation fault (core dump) with big multidimensional array?

I have this simple program which has to receive in input a matrix[d][d] with every element separated by a , whenever is given the input AddM, then it is supposed to print the matrix.
It works well when the d is small, let's say around 20, but if I enter a larger d then it gives me a segmentation fault (core dump) error.
Can somebody explain why it has this behaviour?
Thank you for your time and sorry if my question is stupid.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LENGHT 5
int menu(char c[]);
int **buildAdjMat(int **m);
int d;
int main() {
char *command;
int m_result = 1;
int i = 0, j = 0;
int **m;
if (scanf("%d", &d) == 0)
return 0;
printf("d: %d\n", d);
m = (int **)malloc(d * sizeof(int *));
for (i = 0; i < d; i++) {
m[i] = (int *)malloc(d * sizeof(int));
}
do {
command = (char*)malloc(sizeof(char) * MAX_LENGHT);
if (scanf("%s", command) == 0)
return 0;
m_result = menu(command);
if (m_result == 1) {
m = buildAdjMat(m);
for (i = 0; i < d; i++) {
for (j = 0; j < d; j++) {
printf("%d ", m[i][j]);
}
printf("\n");
}
free(command);
} else {
printf("End! with value %d", m_result);
free(command);
}
} while(m_result == 1);
free(m);
return 0;
}
int menu(char c[]) {
if (strcmp(c, "AddM") == 0) {
printf("AddM!\n");
return 1;
} else {
return -1;
}
}
int **buildAdjMat(int **m) {
int i = 0, j = 0;
char c = '\0';
for (i = 0; i < d; i++) {
for (j = 0; j < d; j++) {
if (scanf("%d", &m[i][j]) == 0)
return NULL;
if (scanf("%c", &c) == 0)
return NULL;
}
}
return m;
}

C program to insert elements into an array until user inputs a 0 or less number

I'm trying to make a C program to insert elements into an array until user inputs a 0 or less number, as the title says. But when I print the array out, it doesn't show the numbers I inputted. I have tried using a while as well as do-while loops but without success.
#include <stdio.h>
int main() {
int data[100];
int i;
for (i = 0; i < 100; i++) {
printf("Input your number:\n");
scanf("%d", &data[i]);
if (data[i] <= 0) {
break;
}
}
printf("Your array:");
int n = sizeof(data[i]);
for (int i = 0; i < n; i++) {
printf("%d ", &data[i]);
}
}
Try this:
#include <stdio.h>
int main() {
int data[100];
int i;
int counter = 0;
for (i = 0; i < 100; i++) {
printf("Input your number:\n");
scanf("%d", &data[i]);
counter++;
if (data[i] <= 0) {
break;
}
}
printf("Your array:");
for (int j = 0; j < counter - 1; j++) {
printf("%d ", data[j]);
}
}
The problem was that you had printf("%d ", &data[i]); instead of printf("%d ", data[i]);.
And also you've trying to get the sizeof() of an element data[i], not the size of the whole array. That's why there's counter in my code.
int n = sizeof(data[i]);
this is wrong, you want
int n = i;
sizeof(data[i]) gives you the size of an int (4 on my machine)
On the other hand, you need to check the result of scanf, if a bad input is entered do not increment the counter, something like:
int i = 0;
while (i < 100)
{
int res = scanf("%d", &data[i]);
if (res == EOF)
{
break;
}
if (res == 1)
{
if (data[i] <= 0)
{
break;
}
i++;
}
else
{
// Sanitize stdin
int c;
while ((c = getchar()) != '\n');
}
}
Finally, scanf wants a pointer to the object, but this is not the case of printf:
printf("%d ", &data[i])
should be
printf("%d ", data[i])

Detect if the number in the array has been already input (C program)

I am kind of confused. I'd like to make a program where if the number in the array has been already input, then it will detect it and say it was repeated, so the program would tell the user to put another non-repeated integer.
#include <stdio.h>
#define SIZE 5
int main()
{
int array[SIZE];
int i;
int j;
for (i = 0; i < SIZE; i++)
{
printf("[%d] Insert a number: ", i + 1);
scanf("%d", &array[i]);
j = i - 1; // This is the closest that I've gotten guys. But I need to create a loop to make j be -1 until it finds a repeated number in the array.
if (array[i] == array[j])
{
printf("The number is repeated");
i--;
}
if (array[i] > 1000)
{
printf("Sorry, the number you entered cannot be bigger than 1000\n");
i--;
}
if (array[i] < 0)
{
printf("Sorry, the number you entered cannot be less than 0\n");
i--;
}
}
for (i = 0; i < SIZE; i++)
{
printf("The array inside is %d\n", array[i]);
}
return 0;
}
As you can see, I did something similar. I just put j = i - 1 so basically it will tell the program that it was repeated. However, I suppose that I should create a loop that will subtract -1 to j until it finds the repeated value (if there is one). I just not have any idea how to create that loop and make it work.
Thank you very much!
The checks can be done the following way (without testing)
int array[SIZE];
int i;
for (i = 0; i < SIZE; i++)
{
int valid = 1;
int num;
do
{
printf("[%d] Insert a number: ", i + 1);
scanf("%d", &num );
if ( !( valid = !( num > 1000 ) ) )
{
printf("Sorry, the number you entered cannot be bigger than 1000\n");
}
else if ( !( valid = !( num < 0 ) ) )
{
printf("Sorry, the number you entered cannot be less than 0\n");
}
else
{
int j = 0;
while ( j < i && num != array[j] ) j++;
if ( !( valid = j == i ) )
{
printf("The number is repeated");
}
}
} while ( !valid );
array[i] = num;
}
This should work for you:
#include <stdio.h>
#define SIZE 5
int main() {
int array[SIZE];
int numberCount, repeatCount;
for(numberCount = 0; numberCount < SIZE; numberCount++) {
printf("[%d] Insert a number:\n>", numberCount + 1);
scanf("%d", &array[numberCount]);
for(repeatCount = 0; repeatCount < numberCount; repeatCount++) {
if (array[numberCount] == array[repeatCount]) {
printf("\nThe numbe is repeated\n");
numberCount--;
break;
}
}
if (array[numberCount] < 0) {
printf("\nSorry, the number you entered cannot be less than 0\n");
numberCount--;
}
if (array[numberCount] > 1000) {
printf("\nSorry, the number you entered cannot be bigger than 1000\n");
numberCount--;
}
}
printf("\n\n");
for(numberCount = 0; numberCount < SIZE; numberCount++)
printf("The array inside is %d\n", array[numberCount]);
return 0;
}

Replacing elements in an array

I have a problem thats giving me a huge ache.
This piece of code purpose is to fill up an array with integer values and at the same time defend against strings and etc....but it doesn't defend against duplicates, but tried I got to far as replacing the number with a new number for example
Enter 6 integers
1, 2, 2, 3, 4, 5
my code will let me replace that 2 at position 1 with another number. What I want it to do is not to repeat the same number again, for example please replace 2 at position 1. I dont want the user to enter 2 again... and I want to make it to double check the work the array if any repeating numbers exists thank you.
system("clear");
printf("\nEntering Winning Tickets....\n");
nanosleep((struct timespec[]){{1, 0}}, NULL);
system("clear");
char userInput[256];
char c;
int duplicationArray[6] = {-1, -1, -1, -1, -1, -1};
for (i = 0; i < 6; i++)
{
printf("\nPlease enter the %d winning ticket number!(#'s must be between 1-49): ", i+1);
fgets(userInput, 256, stdin);
if ((sscanf(userInput, "%d %c", &winningNumbers[i], &c) != 1 || (winningNumbers[i] <= 0) || winningNumbers[i] >= 50))
{
printf("\nInvalid Input.\n") ;
nanosleep((struct timespec[]){{0, 350000000}}, NULL);
system("clear");
i = i - 1;
}
}
for (i = 0; i < 6 - 1; ++i)
{
min = i;
for (j = i+1; j < 6; ++j)
{
if (winningNumbers[j] < winningNumbers[min])
min = j;
}
temp = winningNumbers[i];
winningNumbers[i] = winningNumbers[min];
winningNumbers[min] = temp;
}
for (i = 0; i < 6; i++)
{
if (winningNumbers[i] == winningNumbers[i+1])
{
duplicationArray[i] = i;
duplicationCounter++;
}
else
{
duplicationCounter--;
}
}
if (duplicationCounter > -6)
{
for (i = 0; i < 6; i++)
{
int j, min, temp;
min = i;
for (j = i+1; j < 6; ++j)
{
if (duplicationArray[j] > duplicationArray[min])
min = j;
}
temp = duplicationArray[i];
duplicationArray[i] = duplicationArray[min];
duplicationArray[min] = temp;
}
for (i = 0; i < 6; i++)
{
if (duplicationArray[i] == -1)
{
zeroCounter++;
}
}
int resize = (6 - zeroCounter)+1;
for (i = 0; i <= resize; i++)
{
if (duplicationArray[i] == -1)
{
i++;
}
else if (duplicationArray[i] != -1)
{
system("clear");
printf("\nDuplicated numbers has been dected in your array. ");
printf("\nPlease replace the number %d at postion %d with another number: ", winningNumbers[duplicationArray[i]], duplicationArray[i]);
fgets(userInput, 256, stdin);
if ((sscanf(userInput, "%d %c", &winningNumbers[duplicationArray[i]], &c) != 1 || (winningNumbers[i] <= 0) || winningNumbers[i] >= 50))
{
printf("\nInvalid Input.\n") ;
nanosleep((struct timespec[]){{0, 350000000}}, NULL);
system("clear");
i = i - 1;
}
}
}
duplicationCounter = 0;
for (i = 0; i < 6; i++)
{
if (winningNumbers[i] == winningNumbers[i+1])
{
duplicationArray[i] = i;
duplicationCounter++;
}
else
{
duplicationCounter--;
}
}
printf("%d, ", duplicationCounter);
}
#include <stdio.h>
#include <stdint.h>
#define DATA_SIZE 6
int main(void){
char userInput[256];
int inputNum, winningNumbers[DATA_SIZE];
uint64_t table = 0;
int i=0;
while(i<DATA_SIZE){
printf("\nPlease enter the %d winning ticket number!(#'s must be between 1-49): ", i+1);
fgets(userInput, sizeof(userInput), stdin);
if(sscanf(userInput, "%d", &inputNum) != 1 || inputNum <= 0 || inputNum >= 50)
continue;
uint64_t bit = 1 << inputNum;
if(table & bit)
continue;
table |= bit;
winningNumbers[i++] = inputNum;
}
for(i=0;i<DATA_SIZE;++i)
printf("%d ", winningNumbers[i]);
printf("\n");
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#define DATA_SIZE 6
int inputNumberWithRangeCheck(const char *msg, const char *errMsg, int rangeStart, int rangeEnd){
char inputLine[256];
int n;
for(;;){
printf("%s", msg);
fgets(inputLine, sizeof(inputLine), stdin);
if(sscanf(inputLine, "%d", &n) != 1 || n < rangeStart || n > rangeEnd)
fprintf(stderr, "%s", errMsg);
else
return n;
}
}
int inputNumber(void){
return inputNumberWithRangeCheck(
"\nPlease enter the winning ticket number!(#'s must be between 1-49): ",
"Invalid Input.\n",
1,49);
}
int *inputArray(int *array, size_t size){
int i;
for(i=0;i<size;++i){
printf("\nInput for No.%d\n", i+1);
array[i] = inputNumber();
}
return array;
}
int **duplicateCheck(int *array, size_t size){
int **check, count;
int i, j;
check = malloc(size*sizeof(int*));
if(!check){
perror("memory allocate\n");
exit(-1);
}
//There is no need to sort the case of a small amount of data
//(Cost of this loop because about bubble sort)
for(count=i=0;i<size -1;++i){
for(j=i+1;j<size;++j){
if(array[i] == array[j]){
check[count++] = &array[i];
break;
}
}
}
check[count] = NULL;
if(count)
return check;
else {
free(check);
return NULL;
}
}
int main(void){
int winningNumbers[DATA_SIZE];
int **duplication;
int i, j;
inputArray(winningNumbers, DATA_SIZE);
while(NULL!=(duplication = duplicateCheck(winningNumbers, DATA_SIZE))){
for(i=0;i<DATA_SIZE;++i){
if(duplication[i]){
printf("\nyour input numbers : ");
for(j=0;j<DATA_SIZE;++j)
printf("%d ", winningNumbers[j]);
fprintf(stderr, "\nThere is duplicate. Please re-enter.\n");
*duplication[i] = inputNumber();
} else
break;
}
free(duplication);
}
for(i=0;i<DATA_SIZE;++i)
printf("%d ", winningNumbers[i]);
printf("\n");
return 0;
}

Resources