C - How to sort false elements in array - arrays

A text file with names and results is put to a c program to be sorted by results. How do ignore false inserts like number 8 in the file below?
.txt code looks like this
Paul 35.6
Peter 53.4
Jack 23.0
8
Steph 0.0
Amanda 43.5
First array is arrayName[], second is arrayResult[], arrayFail[] is for 0.0 points.
#define ARRAYSIZE 15 // THIS IS THE MACRO FOR DEFINING THE ARRAY SIZE
#define STRSIZ 40 // THIS IS THE MACRO FOR DEFINING THE STRING SIZE
int main(){
/* Declaration of variables */
int i, j, n, f = 0;
float a, m =0;
char c;
/* Defining the arrays for names and results */
char arrayName[ARRAYSIZE][STRSIZ];
char arrayTemp[ARRAYSIZE][STRSIZ];
char arrayFail[ARRAYSIZE][STRSIZ];
float arrayResults[ARRAYSIZE];
n = ARRAYSIZE;
/* Code to open file and check list for validation */
FILE *fp;
fp = fopen("List.txt", "r"); //Opens the file
while ((c = fgetc(fp)) != EOF){
if (c == '\n')
m = m +1;
}
n = m;
// Close the file
fclose(fp);
/* Validates the name list */
while( n <= 0 || n > 15){
printf("\nThe list is invalid. It must be atleast one name and a maximum of 15 names. Please edit List.txt and re-run the program\n");
return 0;
}
/* Here the program scans the list from the text file */
for(i = 0; i < n; i++){
scanf("%s %f", arrayName[i], &arrayResults[i]);
}
/* Printing out the competitors list */
printf("The competitors: ");
for(i = 0; i < n - 1; i++){
printf("%s, ", arrayName[i]);
}
for(i = n - 1; i < n; i++){
printf("%s.", arrayName[i]);
}
/* The array is ordered */
for(i = 0; i < n; i++){
for(j = i + 1; j < n; j++){
if( arrayResults[i] < arrayResults[j]){
a = arrayResults[i];
strcpy(arrayTemp[i], arrayName[i]);
arrayResults[i] = arrayResults[j];
strcpy(arrayName[i], arrayName[j]);
arrayResults[j] = a;
strcpy(arrayName[j], arrayTemp[i]);
}
}
}
/* Printing out the Top 3 */
printf("\n\nThe Top 3:\n");
for(i = 0; i < 3; i++)
printf("No%d: %s with %.1f\n", i+1, arrayName[i], arrayResults[i]);
/* Failed competitors and their names are detected and stored */
for(i = 0; i < n; i++){
if( arrayResults[i] == 0 ){
strcpy(arrayFail[f], arrayName[i]);
f++;
}
}
/* Printing out the failed competitors */
printf("\nThe failed competitors were: ");
for(i = 0; i < f - 1; i++){
printf("%s, ", arrayFail[i]);
}
printf("%s.", arrayFail[f - 1]);
printf("\n");
return 0;
}

You could test the validity of each entry during the collection and bypass it when the test fails (you could adjust the test to your own goal, here we just test that the string is not empty) :
int countEntry = 0;
for(i = 0; i < n; i++){
scanf("%s %f", arrayName[i], &arrayResults[i]);
// If name or score is null, decrease i to ignore that entry
if (arrayName[i][0] == 0 || arrayResults[i][0] == 0) i--;
// Else counts the entry
else countEntry++;
}
Then you should control that there is at least one valid entry :
if(countEntry == 0) {
printf("\nThe list is invalid. It must be atleast one name. Please edit List.txt and re-run the program\n");
return 0;
}

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;
}

How to make a program that scrambles the order of the words in a sentence from a file

I have a file with say 4 sentences, I know that there are 4 because each sentence has '.' at the end.
What I did was read from the file given and paste each sentence in a 2 dimensional array like so:
char sentence[0][200] = "Hello how are you."
char sentence [1][200] = "I'm good thanks. etc.
Here is the code for this:
int main()
{
char sentence[RSIZ][LSIZ];
char fname[20] = "t.txt";
FILE *fptr = NULL;
int i = 0;
int tot = 0;
char c;
int nrsentences = 0;
printf("\n\n Read the file and store the lines into an array :\n");
printf("------------------------------------------------------\n");
fptr = fopen(fname, "r");
// Check if file exists
if (fptr == NULL)
{
printf("Cant open the file %s", fname);
return 0;
}
// Sentences counter from file
for (c = getc(fptr); c != EOF; c = getc(fptr))
if (c == '.') // Increases if found '.'
nrsentences = nrsentences + 1;
fptr = fopen(fname, "r");
for (i=0; i<nrsentences; i++)
fgets(sentence[i], 200, fptr);
Then I would separate the this array in to words with this code:
(still in main(){})
char newString[10][30];
int j,ctr;
j=0; ctr=0;
for (int k = 0; k < nrsentences; k++) {
for(i=0;i<=(strlen(frases[k]));i++)
{
// if space or NULL found, assign NULL into newString[ctr]
if(sentence[k][i]==' '|| sentence[k][i]=='\0')
{
newString[ctr][j]='\0';
ctr++; //for next word
j=0; //for next word, init index to 0
}
else
{
newString[ctr][j]=sentence[k][i];
j++;
}
}
}
printf("\n Strings or words after split by space are :\n");
for(i=0;i < ctr;i++)
printf(" %s ",newString[i]);
Then here is the problem (I think), the part of the scrambling code.
This works like this:
I give the code: the sentences and the inedex.
by default it is like this
index-> 0 1 2 3
sentence-> Hello how are you
but with this code it converts to this:
index-> 3 2 0 1
sentence-> you are Hello how
int index[] = {2,3,5,1,0,4,7,6}; //here I have a function that generates the random list(which I dont know yet how to make it work here
int n = nrsentences;
randomize(newString, index, n, nrsentences);
printf("Reordered array is: \n");
for (int i=0; i<n; i++)
printf ("%s ", newString[i]);
return 0;
}
Here is the randomize() function
void randomize(char* arr[], int index[], int n, int nrsentences)
{
printf("%d", n);
char* temp[n];
// arr[i] should be present at index[i] index
//for (int k = 0; k < nrsentences; k++){
for (int i=0; i<n; i++)
temp[index[i]] = arr[i];
// Copy temp[] to arr[]
for (int i=0; i<n; i++)
{
arr[i] = temp[i];
index[i] = i;
}
//}
}
And here is the index randomizer, which I dont know yet (didnt try) how to add it to the main, or randomize function.
int *random_number(int words)
{
int array[25];
int x, p, count;
int i=0;
srand(time(NULL));
while(i< words){
int r=rand()% words +1;
for (x = 0; x < i; x++)
{
if(array[x]==r){
break;
}
}
if(x==i){
array[i++]=r;
}
}
for(p=0;p<words;p++){
printf("%d ", array[p]);
}
return array;
}
or
int array[25];
int words = 5;
int x, p, count;
int i=0;
srand(time(NULL));
while(i< words){
int r=rand()% words +1;
for (x = 0; x < i; x++)
{
if(array[x]==r){
break;
}
}
if(x==i){
array[i++]=r;
}
}
for(p=0;p<words;p++){
printf("%d ", array[p]);

How to save a modified array to a file

So I created an array which is saved in a file. I have the number 4 printed out 100 times in the file. Now everytime the an element in the array is accessed it the value will decrease by 1. So if A[1] = 4 is accessed then it will become A[1] = 3 and be saved on the file. The thing is I can't save the modified array to the file.
I already tried moving the placement of FILE pointer.
void buildingB4()
{
system("CLS");
FILE *input, *output;
int i, B4[100], room;
input = fopen("B4.txt", "r");
if (input == NULL)
{
output = fopen("B4.txt", "w");
for (i = 1; i <= 100; i++)
{
B4[i] = 4;
fprintf(output, "%d\n", B4[i]);
}
fclose(output);
for (i = 1; i <= 100; i++)
{
if (i % 10 == 0)
{
printf("\n\n");
}
printf("B-4-%d(%d)\t", i, B4[i]);
}
}
else
{
for (i = 1; i <= 100; i++)
{
fscanf(input, "%d\n", &B4[i]);
if (i % 10 == 0)
{
printf("\n\n");
}
printf("B-4-%d(%d)\t", i, B4[i]);
}
fclose(input);
printf("\nPlease choose a room:B-4-");
scanf("%d", &room);
B4[room] = B4[room] - 1;
output = fopen("B4.txt", "a");
fprintf(output, "%d\n", B4[i]);
studentDetails();
}
}
say if A[1] = 4
and when user input is 1, 1 is saved in a variable called room.
so A[room] = A[room] -1
so the result would be A[1] = 3 and it modify the A[1] saved in the file.
Use fclose after the line
fprintf(output, "%d\n", B4[i]);
I've found little mistakes in your code and here is your fixed code:
#define HOME_SIZE 100
void show_rooms(int B[]){
for (int i = 0; i < HOME_SIZE; i++){
if (i % 10 == 0){
printf("\n\n");
}
printf("B-4-%3d(%d) ", i + 1, B[i]);
}
}
void buildingB4()
{
FILE *input, *output;
input = fopen("B4.txt", "r");
unsigned int B[HOME_SIZE], room;
if (input == NULL){
fclose(input);
// Setting all homes to 4.
for (int i = 0; i < HOME_SIZE; ++i){
B[i] = 4;
}
output = fopen("B4.txt", "w");
for(int i = 0; i < HOME_SIZE; ++i)
fprintf(output, "%d\n", B[i]);
fclose(output);
show_rooms(B);
}
else{
for (int i = 0; i < HOME_SIZE; ++i){
fscanf(input, "%d", &B[i]);
}
fclose(input);
show_rooms(B);
printf("\nPlease choose a room:B-4-");
scanf("%d", &room);
if (room > 0 && room <= HOME_SIZE)
B[room - 1] -= 1;
output = fopen("B4.txt", "w");
for(int i = 0; i < HOME_SIZE; ++i)
fprintf(output, "%d\n", B[i]);
}
}
Notice that :
In C index starts from 0 not 1.
close using file after your work in order to save it properly.
Don't use '%d\n' format for scanf, it will ignore ' ' and '\n' automatically.
Tips for future development :
Try using feof function to know if your file is ended or not instead of using constant size for your inputs.

C program - find largest sequence in array

Given this example :
int arr[3][7] = { {1,0,0,1,1,1,1}, //should output 4
{0,1,1,1,1,0,1}, //should output 4
{0,0,1,1,1,1,1}}; //should output 5
Find the largest sequence containing number 1, and print line index and number of 1.
Do not count total numbers of 1 in each line. Only if they are one after another.
here is my approach :
int main(){
int i,j,c=0,count=0;
int arr[3][7] = { {1,0,0,1,1,1,1}, //output 4
{0,1,1,1,1,0,1}, //output 4
{0,0,1,1,1,1,1}}; // output 5
for(i=0; i<3; i++){
for(j=0; j<7; j++){
if(arr[i][j] == 1){
c++;
} else if( arr[i][j] == 0 && c > count ) {
count = c;
c = 0;
}
}
printf("%d\n", count);
}
return 0;
}
What i want to get as output now is 4,4,5 but i am getting 1,4,5.
SOLUTION thanks to https://stackoverflow.com/users/1228887/twain249
int main(){
int i,j,c=0,count=0;
int arr[3][7] = { {1,1,0,1,1,1,1}, //output 4
{0,1,1,1,1,0,1}, //output 4
{0,0,1,1,1,1,1}}; // output 5
for(i=0; i<3; i++){
for(j=0; j<7; j++){
if(arr[i][j] == 1){
c++;
} else {
count = c;
c = 0;
}
}
if(c > count){
count = c;
}
printf("%d\n", count);
c=0;
}
return 0;
}
You forgot to handle the case where the longest sequence is the end of the list
after the inner j loop add the following
if (c > count) {
count = c;
}
Also you forgot to add a clear after each check.
After the printout add
c = clear = 0;
EDIT: 1 more error. You need to reset c even if the new sequence isn't the longest.
Change the else if into
else if (arr[i][j] == 0) { // If isn't necessary if 0/1 are your only options
{
if (c > count) {
count = c;
}
c = 0;
}

issues using file with Xcode c

When I run this program with a file imported into Xcode, I receive an error of Thread 1: EXC_BAD_ACCESS (code=1 address=0x68) at the line c = fgetc(ptr);. I am not sure why fptr is null when it gets to this line. Any help would be great thanks.
#include <stdio.h>
#define M 100
#define N 100
char array[M][N] = {0};
void readFile();
void findStartandEnd();
void mazeTraversal();
int m = 0;
int n = 0;
int start[2] = {0};
int end[2] = {0};
int main() {
readFile();
//findStartandEnd();
//mazeTraversal();
}
void readFile() {
FILE *fptr;
char c;
char file_name[20];
int i, j;
printf("Please enter the size of the MxN maze.\n");
printf("Start with the M size then the N size follow each number by the return key.\n");
scanf("%d", &m);
scanf("%d", &n);
printf("Type in the name of the file containing the Field\n");
scanf("%s", file_name);
fptr = fopen(file_name, "r");
for (i = 0; i < M && i < m; i++)
for (j = 0; j < N && j < n; j++) {
c = fgetc(fptr);
while (!((c == '1') || (c =='0')))
c = fgetc(fptr);
array[i][j] = c;
}
fclose(fptr);
for (i = 0; i < M && i < m; i++)
for (j = 0; j < N && j < n; j++) {
if (j == 0) printf("\n");
printf("%c ", array[i][j]);
}
printf("\n");
}
You do not test if scanf correctly parsed a string into file_name. You do not even protect file_name from a potential buffer overflow with scanf("%19s", file_name);
Furthermore, you do not test whether fopen succeeded at opening the file. fptr could be NULL for many possible reasons, you must test that and fail gracefully.
Note that scanf will stop at the first white space character after the first word. Filenames with embedded spaces cannot be entered with this method.
Note also that c should be defined as int instead of char to properly test for end of file as EOF returned by fgetc() does not fit in a char.
You should also use braces around non trivial statements commended by the for loops. They are not strictly necessary, but it will avoid silly bugs when later amending your code.

Resources