Program to bubble sort a txt file in C - c

I'm writing a C program to be given a txt file containing names of player and how many wins they have (its for a bigger game project), and sort them from highest to lowest amount of wins. While the code compiles and successfully orders the wins im experiencing a problem with the names where they seem to be stacking on top each other.
#include<stdio.h>
#include<stdlib.h>
char name[20];
int wins[20];
void main()
{
FILE *fp;
int i=0,size,j,swap;
char ch;
fp=fopen("record.txt","r");
if(fp==NULL)
{
printf("\n Cannot open the file \n");
exit(0);
}
while(ch!=EOF)
{
fscanf(fp,"%s %d",&name[i],&wins[i]);
ch=fgetc(fp);
i++;
}
size=i-1;
for(i=1;i<size;++i)
for(j=0;j<size-i;j++)
if(wins[j+1]>wins[j])
{
swap = wins[j];
wins[j] = wins[j+1];
wins[j+1] = swap;
swap = name[j];
name[j] = name[j+1];
name[j+1] = swap;
}
fp=fopen("sortedRecord.txt","w");
for(i=0;i<size;i++){
fprintf(fp,"%s %d \n",&name[i],wins[i]);
printf ("%s %d \n", &name[i],wins[i]);
}
fclose(fp);
}
Here is the input file "record.txt"
Andrew 5
Billboy 10
Hill 7
Mill 1
And here is what i get when i run it.
BHAMill 10
HAMill 7
AMill 5
Mill 1
I'm new to code so i know mine sucks but for the life of me i cant see exactly where its going wrong. Any help or advice is appreciated.

As jwdonahue said the issue is with your definition of name. char name[20] creates an array of 20 chars, not 20 strings.
When you run the while(ch!=EOF) loop what's happening? First time through you find the address of the 0th element in name and write Andrew there so name has ['A', 'n', 'd', 'r', 'e', 'w', '\0', '\0', '\0', '\0'] (the \0 is the end of string character). Second time through you find the address of the 1st element in name and write Billboy, but the 0th element is still there and hasn't changed so you end up with the contents being ['A', 'B', 'i', 'l', 'l', 'b', 'o', 'y', '\0', '\0']. Adding Hill to the 2nd position results in ['A', 'B', 'H', 'i', 'l', 'l', '\0', 'y', '\0', '\0']. Then finally adding Mill gives the array ['A', 'B', 'H', 'M', 'i', 'l', 'l', '\0', '\0', '\0'].
When you then go to sort scores you are sorting the characters in this array which end up as ['B', 'H', 'A', 'M', 'i', 'l', 'l', '\0', '\0', '\0'] (only the first four characters will be affected by your sort). In your print statement you then print the character array starting at the 0th, 1st, 2nd and 3rd positions respectively so you get BHAMill, HAMill, AMill, and Mill.
Hopefully that should help you enough to get you unstuck. :)

Related

If function and scanf function not working together

so I have been trying to write a code that displays different messages if different keys are pressed
It should display "Your hair looks nice" if one of the characters of the string is pressed and display "You look like your mom" if any number of symbol is pessedd (anything other than the array's elements)
what is the issue here?
(Mind the messages in the code I'm trying to stay chill so I picked random messages)
the code:
#include<stdio.h>
int
main ()
{
char i,o;
char a[54] =
{ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'g', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C',
'D',
'E', 'F', 'G', 'H', 'I', 'G', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
'T',
'U', 'V', 'W', 'X', 'Y', 'Z'
};
if (scanf ("%c", &o) == a[i])
printf ("Your hair looks nice");
else
printf ("You look like your mom");
return 0;
}
C have a set of standard character classification functions, like for example isalpha to check if a character is a letter or not.
With this you can make your program much simpler, and don't need the array:
#include <stdio.h>
#include <ctype.h>
int main(void)
{
int ch = getc(); // Read one character
if (isalpha(c))
{
puts("Your hair looks nice.");
}
else
{
puts("You look like your mom!");
}
}
Note that I use the getc function to read a character instead. In most cases scanf shouldn't really be used for input, it's use is unfortunately more non-trivial than the beginners guides and tutorials make it seem.
You need to check all relevant values of i. Currently, you don't even assign a single value to i, but you need to assign 54 different values in turn.
And of course, you need to call scanf only once, not 54 times.
If you want to see whether the inputted character is in the array, then you must compare that character with all 54 characters in the array. However, in your posted code, you are only making one comparison. I suggest that you use a for loop for doing the 54 comparisons. You can do one comparison per loop iteration.
Here is an example:
#include <stdio.h>
#include <stdlib.h>
int main( void )
{
char a[54] = {
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'g', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'G', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
};
char input;
//get input character
if ( scanf( "%c", &input ) != 1 )
{
fprintf( stderr, "Input error!\n" );
exit( EXIT_FAILURE );
}
//determine whether input character is in array
for ( int i = 0; i < 54; i++ )
{
if ( a[i] == input )
{
printf( "Found character in array.\n" );
return 0;
}
}
printf( "Did not find character in array.\n" );
return 0;
}
However, in order to determine whether a character is an alphabetical letter, there is a much simpler solution: You can simply call the function isalpha as demonstrated in one of the other answers.
From scanf's man page:
RETURN VALUE:
On success, these functions return the number of input items successfully matched and assigned; this can be fewer than provided for, or even zero, in the event of an early matching failure.
According to this, the statement
if (scanf ("%c", &o) == a[i])
compares the return value of scanf, which in this case would be one 1(if scanf succeeded) to a[i], where i is uninitialised and leads to undefined behaviour. As I remember #Fe203 once saying:
"Leaving variables uninitialised is asking Demon of Hard-To-Find Bugs to co-author your code."
So you ought to first initialise i, then iterate through the array, comparing o to all the 54 values of i.
Aside:
You shouldn't be using scanf for user-interactive stuff. It is not supposed to be used as such, and it's quite hard to get right. In this case, consider using getc or getchar which reads one character at a time.
Or at least, check the return value of scanf.

why the size of string is same as number of char but length is one more than number of char?

I used the following code:
#include <stdio.h>
#include <string.h>
void main()
{
char c[] = {'J', 'O', 'H', 'N'};
printf("size (bytes)=%d\n", sizeof(c));
int len = strlen(c);
printf("Length = %d\n", strlen(c));
printf("%s", c);
The output size of the string is 4, but the length is 5. is the string not supposed to have /0 at the end? So the output size of the string should be 5, but the length is 4.
If I write code as char c[] = {'J', 'O', 'H', 'N', \0}; or c[] = "JOHN" then I got output size of the string is 5, the length is 4
In C, a string is a sequence of character values including a 0-valued terminator - the string "JOHN" would be represented as the sequence {'J', 'O', 'H', 'N', 0 }.
Strings are stored in arrays of character type - because the you need to store the terminator in addition to the characters of the string, the size of the array has to be at least one more than the length of the string. IOW, to store the 4-character string "JOHN" you need an array that's at least 5 elements wide.
Had you initialized the array as
char c[] = "JOHN";
then the terminator would have properly been accounted for.
If the terminator isn't present, then what you have isn't a string and the various str* library functions won't handle it properly. In your case above, strlen looked through the elements {'J', 'O', 'H', 'N'} and didn't find the 0 terminator, so it kept looking past the end of the array until it saw a zero-valued byte.
The definition of a string in C is that it is an array of characters, terminated by a null character, or '\0'.
You wrote:
char c[] = {'J', 'O', 'H', 'N'};
So let's see.
array of char: ✅
terminated by a null character: ❌
So c is not a string. So it's not valid to call strlen on it, and it's not valid to print it out using printf's %s format.
You could make it a proper string by changing the initialization to:
char c[] = {'J', 'O', 'H', 'N', 0};
or equivalently
char c[] = {'J', 'O', 'H', 'N', '\0'};
Or it would be easier and clearer to just write
char c[] = "JOHN";
When you use a string literal (that is, a string in double quotes) as an initializer for a character array like that, the compiler automatically does exactly the same thing for you as if you had written {'J', 'O', 'H', 'N', '\0'};, but it's obviously a lot less typing.

Char array null termination & length in c

I am writing a function to check length of a char array in c. It takes another parameter, which sets the limit for \0 check.
int string_length(char* string, int maximum_length) {
int i = 0;
while(string[i] != '\0' && i < maximum_length) {
i++;
}
return i;
}
In this answer, it is mentioned that a char array must be null terminated, if it is created using {} syntax. I call the above function with not terminated char array & the result is 10(9 letters + 1).
char not_terminated_string[] = {'m', 'y', ' ', 's', 't', 'r', 'i', 'n', 'g' };
int length = string_length(not_terminated_string, 100);
// length is 10
I am not able to understand why is it this way.
For the following line, C compiler creates an array of 10 char size elements and lays down the first 9 characters, adding a string \0 delimiter at the very end.
char *a = "my string";
Considering the following line; C compiler creates an array of 9 char size elements and lays down the characters. A string delimiter is not added at the very end. If there happens to be a zero value at the 10th byte (byte number 9), that would be only by chance.
char b[] = { 'm', 'y', ' ', 's', 't', 'r', 'i', 'n', 'g' };
The statement "a char array must be null terminated, if it is created using {}" means, if you want to be able to use that char array as a string (like, to be able to use it in a printf), then you should add a string terminating character by yourself, like;
char b[] = { 'm', 'y', ' ', 's', 't', 'r', 'i', 'n', 'g', '\0' };
Your program produced ten because you defined an array of only nine non-null characters, but it happened to be followed by one more non-null character and then a null character. (Technically, the behavior of your program is not defined by the C standard due to overrunning the array, and there are other ways your program could then have misbehaved to produce ten, but this is the most likely occurrence.)
The declaration char not_terminated_string[] = {'m', 'y', ' ', 's', 't', 'r', 'i', 'n', 'g' }; defines not_terminated_string to be an array of nine char, which are initialized with the given characters. No null character is automatically appended to this array.
When your program passed this array to string_length, that routine counted the nine characters in the array, and then it attempted to look at the tenth. It appears, most likely, that the next byte in memory was not null, so the routine counted it and looked at the eleventh. It appears that one was null, so the routine stopped and returned ten.

Why is the printf specifiers, "%s", printing multiple variables at once?

I declared four string variables and initialized in four different ways. I then used the printf function four times, as the name implies, to print to the console the four string variables.
I already tried printing one at a time, but that didn't worked out. After the first attempt, I tried using the escape sequence but that didn't work. I then tried searching online of finding the proper ways to print out string, but all I've found came back to same using the printf function.
#include <stdio.h>
int main() {
char name1[] = "Ignacio";
char name2[8] = "Ignacio";
char name3[] = {'D', 'i', 'e', 'g', 'o'};
char name4[5] = {'D', 'i', 'e', 'g', 'o'};
printf("Name: %s\n", name1);
printf("Name: %s\n", name2);
printf("Name: %s\n", name3);
printf("Name: %s\n", name4);
return 0;
}
EXPECTED OUTPUT:
Name: Ignacio
Name: Ignacio
Name: Diego
Name: Diego
ACTUAL OUTPUT:
Name: Ignacio
Name: Ignacio
Name: DiegoIgnacio
Name: DiegoDiegoIgnacio
char name3[] = {'D', 'i', 'e', 'g', 'o'};
char name4[5] = {'D', 'i', 'e', 'g', 'o'};
These two are not strings, because they are not null-terminated.
Try:
char name3[] = {'D', 'i', 'e', 'g', 'o', '\0'};
char name4[6] = {'D', 'i', 'e', 'g', 'o', '\0'};
Whats happening is the a null terminating character is implicitly being added when you initialize a char[] like below:
char myStr[] ="Ignacio";
If you want to initialize a char[] with individual characters you must initialize it like the following because the null terminating character must be explicitly added:
char myStr[] ={'I', 'g', 'n', 'c', 'i','0','\0'}).
Explanation for the Behaviour in Your Case:
Memory Layout:
[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [A] [B] [C] [D] [E] [F] [10] [11]
'D' 'i' 'e' 'g' 'o' 'D' 'i' 'e' 'g' 'o' 'I' 'g' 'n' 'a' 'c' 'i' 'o' '\0'
After you initialize your strings, the characters are arranged in memory like above. In the C language, all valid strings must have a null terminating character at there end to specificity the end of the string. The reason why is printf will just start at the address of the char* passed to it and will keep reading characters until a '\0' character is encountered. Because of this, if you pass printf an address to an array of characters that does not contain a '\0', then printf will keep marching past those characters into memory until a null terminating character is encountered. (This could result in a segmentation fault)
Explanation for Your Output: (Reference the memory layout above)
Name: DiegoIgnacio
printf will start at index [5] and will print all characters until the '\0' character, thus "DiegoIgnacio" ([5] - [11]) is the output.
Name: DiegoDiegoIgnacio
printf will start at index [0] and will print all characters until the '\0' character, thus "DiegoDiegoIgnacio" ([0] - [11]) is the output.

A poker card game in C. Please explain suits[4][9], and faces[13][6]?

So I have a sample code to create a deck of card for a mini poker game in c. But I do not understand how the suits and faces are determined. Why do these arrays have 2 dimensions? I know that [9] and [6] are the columns of the array, but I do not understand the purpose of them.
char suits[4][9]= {"Hearts","Diamonds","Clubs","Spades"};
char faces[13][6]= {"Ace","2","3","4","5","6","7","8","9", "10","Jack",
"Queen","King"};
The first set of square brackets is the number of elements in the first array, the second square bracket is the maximum length of the char array (string).
The second bracket in char suits[4][9] has nine spaces to allow space for the null character \0 which is used to terminate the string.
So the array actually looks like this:
char suits[4][9] = {
{'H', 'e', 'a', 'r', 't', 's', '\0'},
{'D', 'i', 'a', 'm', 'o', 'n', 'd', 's', '\0'},
{'C', 'l', 'u', 'b', 's', '\0'},
{'S', 'p', 'a', 'd', 'e', 's', '\0'}
};
When you have :
char suits[4][9]
it means that your array has 4 rows and the string that will be placed in each row can have a maximum length 9 and subtracting the ending '\0' character, maximum length 8.
Similarly,
char faces[13][6]
means that your array has 13 rows and the string that will be placed in each row can have a maximum length 6 and subtracting the ending '\0' character, maximum length 5.

Resources