-
Strings
Hey, I can't seem to figure this out and have been sitting here for a long time scratching my head. I'm new to programming and I'm trying some stuff out. What I'm trying to do is read in information from a file and the problem I'm having is with the strings. I want to read in names in the format of "<Last Name> <First Name>" but the space between the two totally throws it off. I've searched around looking for a way to read it and couldn't find anything of much help. I did try fgets() but that doesn't seem to work. I've been trying all day to get this to work but can't seem to. Maybe one of you could help.
Here a sample of an input file, let's call it input.txt
Code:
11 5
Gupta Anil
96 90 85 90 80
Jeffers Jose
60 0 70 50 30
Evans Rudy
80 60 70 50 75
Williams Jason
50 40 0 0 70
Ball Adam
90 80 60 55 60
Arnold Joshua
0 0 0 0 0
Scot Michael
80 70 0 0 60
Cook Bret
95 80 80 70 60
Davis Ronald
0 0 0 0 0
Fox Brian
70 60 60 40 50
Hale Frank
60 50 60 30 40
Now for the function, I know it's wrong but it's all I can get.
Code:
void get_info(struct students student[], int *num_students, int *exams)
{
int i, j, grades = 0;
char names[30], file[40];
FILE *infile;
// Get file name
printf("Enter the name of the file containing the grades: ");
scanf("%s", file);
// Open file and read in info
infile = fopen(file, "r");
fscanf(infile, "%d %d", &num_students, &exams);
for(i = 0; i < *num_students; i++)
{
fscanf(infile, "%s", names);
strcpy(student[i].name, names);
for(j = 0; j < *exams; j++)
{
fscanf(infile, "%d", &grades);
student[i].grade[j] = grades;
}
}
// Close file
fclose(infile);
}
I've tried a lot of different methods but always get the same error.
Code:
0 [main] a 3832 handle_exceptions: Exception: STATUS_ACCESS_VIOLATION
10592 [main] a 3832 stackdump: Dumping stack trace to a.exe.stackdump
I did however get it working one time but all it did was read in the last name but not the first. Any ideas on how to fix this would be appreciated.
-
> fscanf(infile, "%d %d", &num_students, &exams);
Remove those &
With %d, you're supposed to pass a pointer to an int.
fscanf(infile, "%d", &grades);
So this is a good example - grades is an int declared locally.
But exams is already a pointer (you said int *exams), so there is nothing more to do
So you say
fscanf(infile, "%d %d", num_students, exams);
-
Ah, so that's where that error was coming from. I thought it had something to do with the way I was trying to read in the strings. After that I was able to figure out what I wanted to do. At first those two were local variables but I changed them to global after I needed them in other functions. In order to keep the values gotten there I made them pointers but I forgot to remove the address of operators. I probably would have never caught that thanks :).
As for the strings, I figured that out once I got all that cleared up. Here's how I did it, if there's a more effective way, which I'm postive there is, let me know because I'm here to learn :). And now the code:
Code:
void get_info(struct students student[], int *num_students, int *exams)
{
int i, j, grades = 0;
char l_name[30], f_name[30], file[40];
FILE *infile;
// Get file name
printf("Enter the name of the file containing the grades: ");
scanf("%s", file);
// Open file and read in info
infile = fopen(file, "r");
fscanf(infile, "%d %d", num_students, exams);
for(i = 0; i < *num_students; i++)
{
fscanf(infile, "%s %s", l_name, f_name);
strcat(l_name, " ");
strcat(l_name, f_name);
strcpy(student[i].name, l_name);
for(j = 0; j < *exams; j++)
{
fscanf(infile, "%d", &grades);
student[i].grade[j] = grades;
}
}
// Close file
fclose(infile);
}
-
Use fgets() to read a whole line in one go, which would be useful for reading in the student name.
But watch out for the newline which fgets() will append if there is room for it after reading the line.
-
Ok, I've run into another problem that's really weird. I'm now trying to sort the names alphabetically. Here's the code I used:
Code:
void sort_names(struct students student[], int num_students, int exams)
{
int i, count = 0;
char temp_name[30];
do
{
for(i = 0; i < num_students; i++)
{
if(strcmp(student[i].name, student[i+1].name) > 0)
{
strcpy(temp_name, student[i].name);
strcpy(student[i].name, student[i+1].name);
strcpy(student[i+1].name, temp_name);
}
}
count++;
}while(count < num_students);
}
But here's the output I get later on in the program:
Code:
Here is the sorted list:
1.
2. Arnold Joshua
3. Ball Adam
4. Cook Bret
5. Davis Ronald
6. Evans Rudy
7. Fox Brian
8. Gupta Anil
9. Hale Frank
10. Jeffers Jose
11. Scot Michael
As you can see it's skipping the first number. but the weird thing is if I change this line to:
Code:
if(strcmp(student[i].name, student[i+1].name) < 0)
I get this output:
Code:
Here is the sorted list:
1. Williams Jason
2. Scot Michael
3. Jeffers Jose
4. Hale Frank
5. Gupta Anil
6. Fox Brian
7. Evans Rudy
8. Davis Ronald
9. Cook Bret
10. Ball Adam
11. Arnold Joshua
I knew it would do it backwards but why didn't it skip the first one as it did with the > operator? I want it to do what it did here but the way it was in the first output. I don't know why it would work for one but not the other.
NOTE: Don't mind my function parameters, I'm not done writing the function yet. I'm just trying to get this part to work before I keep writing it.
-
This block of code works fine for me:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void sortList(struct student [], int);
struct student {
char name[30];
};
int main(void) {
struct student myList[3];
strcpy(myList[0].name,"zabba");
strcpy(myList[1].name,"dog");
strcpy(myList[2].name,"cat");
for(int i = 0; i < 3; i++) {
printf("%d. %s\n", i+1, myList[i].name);
}
sortList(myList, 3);
printf("\n Sorted list\n");
for(int i = 0; i < 3; i++) {
printf("%d. %s\n", i+1, myList[i].name);
}
return 0;
}
void sortList(struct student myList[], int numList) {
int count=0, i=0;
char temp[30];
while(count < numList){
for(int i = 0; i < numList-1; i++) {
if(strcmp(myList[i].name, myList[i+1].name) > 0) {
strcpy(temp, myList[i].name);
strcpy(myList[i].name , myList[i+1].name);
strcpy(myList[i+1].name, temp);
}
}
count++;
}
}
Where is your display part of the code?
-
Here's the whole thing so far:
Code:
#include <stdio.h>
#include <string.h>
struct students
{
char name[30];
int grade[5];
} student[300];
void get_info(struct students student[], int *num_students, int *exams);
void print_names(struct students student[], int num_students);
void sort_names(struct students student[], int num_students, int exams);
int main()
{
int num_students, exams, option;
get_info(student, &num_students, &exams);
sort_names(student, num_students, exams);
do
{
printf("Enter 1 to continue the program. Enter 0 to terminate the program.\n");
scanf("%d", &option);
if(option == 0){
printf("\nGoodbye!");
return 0;
}
print_names(student, num_students);
}while(option != 0);
printf("\nGoodbye!");
return 0;
}
void get_info(struct students student[], int *num_students, int *exams)
{
int i, j, grades = 0;
char l_name[30], f_name[30], file[40];
FILE *infile;
/* Get file name */
printf("Enter the name of the file containing the grades: ");
scanf("%s", file);
/* Open file and read in info */
infile = fopen(file, "r");
fscanf(infile, "%d %d", num_students, exams);
for(i = 0; i < *num_students; i++)
{
fscanf(infile, "%s %s", l_name, f_name);
strcat(l_name, " ");
strcat(l_name, f_name);
strcpy(student[i].name, l_name);
for(j = 0; j < *exams; j++)
{
fscanf(infile, "%d", &grades);
student[i].grade[j] = grades;
}
}
/* Close file */
fclose(infile);
}
void sort_names(struct students student[], int num_students, int exams)
{
int i, count = 0;
char temp_name[30];
do
{
for(i = 0; i < num_students; i++)
{
if(strcmp(student[i].name, student[i+1].name) > 0)
{
strcpy(temp_name, student[i].name);
strcpy(student[i].name, student[i+1].name);
strcpy(student[i+1].name, temp_name);
}
}
count++;
}while(count < num_students);
}
void print_names(struct students student[], int num_students)
{
int i;
printf("\nHere is the sorted list: \n");
for(i = 0; i < num_students; i++)
{
if(i + 1 < 10)
printf("%d. %s\n", i + 1, student[i].name);
else if(i + 1 >= 10 && i + 1 < 100)
printf("%d. %s\n", i + 1, student[i].name);
else if(i + 1 >= 100)
printf("%d. %s\n", i + 1, student[i].name);
}
}
-
Ok, I compiled and ran this:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void sort_names(struct student student[], int num_students, int exams);
void print_names(struct student student[], int num_students);
struct student {
char name[30];
};
int main(void) {
struct student myList[3];
strcpy(myList[0].name,"zabba");
strcpy(myList[1].name,"dog");
strcpy(myList[2].name,"cat");
for(int i = 0; i < 3; i++) {
printf("%d. %s\n", i+1, myList[i].name);
}
sort_names(myList, 3, 5);
printf("\n Sorted list\n");
print_names(myList, 3);
return 0;
}
void sort_names(struct student student[], int num_students, int exams)
{
int i, count = 0;
char temp_name[30];
do
{
for(i = 0; i < num_students-1; i++)
{
if(strcmp(student[i].name, student[i+1].name) > 0)
{
strcpy(temp_name, student[i].name);
strcpy(student[i].name, student[i+1].name);
strcpy(student[i+1].name, temp_name);
}
}
count++;
}while(count < num_students);
}
void print_names(struct student student[], int num_students)
{
int i;
printf("\nHere is the sorted list: \n");
for(i = 0; i < num_students; i++)
{
if(i + 1 < 10)
printf("%d. %s\n", i + 1, student[i].name);
else if(i + 1 >= 10 && i + 1 < 100)
printf("%d. %s\n", i + 1, student[i].name);
else if(i + 1 >= 100)
printf("%d. %s\n", i + 1, student[i].name);
}
}
And still got the correct output. So I believe you have a NULL student in your array somewhere. That would explain why when you sorted alphabetically the first line is blank.
-
Aha! I think I know where it is being introduced. Instead of :
Code:
for(i = 0; i < num_students; i++)
Use this:
Code:
for(i = 0; i < num_students-1; i++)
{
if(strcmp(student[i].name, student[i+1].name) > 0)
{
strcpy(temp_name, student[i].name);
strcpy(student[i].name, student[i+1].name);
strcpy(student[i+1].name, temp_name);
}
}
When doing this kind of sort you only compare up to N-1 values. Give that a try and let me know.
-
EDIT: I just saw the post above let me try that.
EDIT: It worked, you were right. Why do you only go up to the N-1?
-
Because as you are comparing the values when i = n-1 you are comparing it with value n aka
Code:
if(strcmp(student[i].name, student[i+1].name) > 0)
since i = n-1 therefore
Code:
if(strcmp(student[n-1].name, student[n-1+1].name) > 0)
or more simply
Code:
if(strcmp(student[n-1].name, student[n].name) > 0)
-
Ah, now I understand. If I have anymore problems with the program in the future I'll post it here. Thanks for the help so far :).