I’m trying to make a program that receives a text from a file where its lines are a first name, a last name and a note. I want to return the ordered lines: first the students with a grade lower than 5 and after the students passed in order of appearance in the file. The problem is that I can’t print the names and I don’t know what the fault is. The main code is as follows:
int main(int argc, char *argv[])
{
char line[MaxLinea+1];
char *name;
char *surname;
lista_notas *mi_lista = NULL;
int i, blank, grade;
FILE *archivo = fopen(argv[1], "r");
while(fgets(line, MaxLinea, archivo)) //recorrer linea fich
{
grade = get_grade(line);
if (grade < 5) //Insertar en la lista
{
name = get_name(line);
surname = get_surname(line);
insertar(&mi_lista, name, surname, grade);
}
}
fclose(archivo);
archivo = fopen(argv[1], "r");
while(fgets(line, MaxLinea, archivo)) //recorrer linea fich
{
grade = get_grade(line);
if (grade > 4) //Insertar en la lista
{
name = get_name(line);
surname = get_surname(line);
insertar(&mi_lista, name, surname, grade);
}
}
mostrar_lista(mi_lista);
free_lista(mi_lista);
//system("leaks a.out");
return 0;
}
The get_name function is:
char *get_name(char *line)
{
int i;
char *name = malloc(51);
if (name == NULL)
exit(71);
i = 0;
while(line[i] != ' ')
name[i] = line[i++];
name[i] = 0;
return name;
}
If the program receives a fich.txt which content is:
Nombre1 Apellido1 8
Nombre2 Apellido2 2
Nombre3 Apellido3 6
The output must be:
Nombre2 Apellido2 2
Nombre1 Apellido1 8
Nombre3 Apellido3 6
but instead, it is:
Apellido2 2
Apellido1 8
Apellido3 6
Thanks for your help!
The full code is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MaxLinea 154
//Tamaño máximo linea = 50 (nombre) + 100 (apellido) + 2 (nota máx 10)
// + 2 espacios + caracter nulo? = 155
typedef struct notas{
char *nombre;
char *apellido;
int nota;
struct notas *siguiente;
} lista_notas;
int get_grade(char *line);
char *get_name(char *line);
char *get_surname(char *line);
void insertar(lista_notas **ptr, char *name, char *surname, int grade);
void mostrar_lista(lista_notas *ptr);
void free_lista(lista_notas *ptr);
int main(int argc, char *argv[])
{
char line[MaxLinea+1];
char *name;
char *surname;
lista_notas *mi_lista = NULL;
int i, blank, grade;
FILE *archivo = fopen(argv[1], "r");
while(fgets(line, MaxLinea, archivo)) //recorrer linea fich
{
grade = get_grade(line);
if (grade < 5) //Insertar en la lista
{
name = get_name(line);
surname = get_surname(line);
insertar(&mi_lista, name, surname, grade);
}
}
fclose(archivo);
archivo = fopen(argv[1], "r");
while(fgets(line, MaxLinea, archivo)) //recorrer linea fich
{
grade = get_grade(line);
if (grade > 4) //Insertar en la lista
{
name = get_name(line);
surname = get_surname(line);
insertar(&mi_lista, name, surname, grade);
}
}
mostrar_lista(mi_lista);
free_lista(mi_lista);
//system("leaks a.out");
return 0;
}
void insertar(lista_notas **ptr, char *name, char *surname, int grade)
{
lista_notas *p1, *p2;
p1 = *ptr;
if(p1 == NULL)
{
p1 = malloc(sizeof(lista_notas));//y si usamos calloc ¿qué cambia?
if (p1 == NULL)
exit(71);
if (p1 != NULL)
{
p1->nombre = name;
p1->apellido = surname;
p1->nota = grade;
p1->siguiente = NULL;
*ptr = p1;
}
}
else
{
while(p1->siguiente != NULL)//recorrer la lista hasta el último
p1 = p1->siguiente;
p2 = malloc(sizeof(lista_notas));//y si usamos calloc ¿qué cambia?
if (p2 == NULL)
exit(71);
if(p2 != NULL)
{
p2->nombre = name;
p2->apellido = surname;
p2->nota = grade;
p2->siguiente = NULL;
p1->siguiente = p2;
}
}
}
void mostrar_lista(lista_notas *ptr)
{
while(ptr != NULL)
{
printf("%s ",ptr->nombre);
printf("%s ",ptr->apellido);
printf("%d\n",ptr->nota);
ptr = ptr->siguiente;
}
/* printf("\n");*/
}
void free_lista(lista_notas *ptr)
{
lista_notas *aux = ptr;
lista_notas *aux2;
while(aux != NULL)
{
aux2 = aux;
aux = aux->siguiente;
free(aux2->nombre);
free(aux2->apellido);
free(aux2);
}
}
int get_grade(char *line)
{
int i, blank, num;
i = 0;
blank = 0;
while(line[i] != '\0')
{
if (blank == 2) //sacar la nota
{
num = atoi(&line[i]);
blank++;
}
else if(line[i] == ' ')
blank++;
i++;
}
return num;
}
char *get_name(char *line)
{
int i;
char *name = malloc(51);
if (name == NULL)
exit(71);
i = 0;
while(line[i] != ' ')
name[i] = line[i++];
name[i] = 0;
return name;
}
char *get_surname(char *line)
{
int i, j;
char *surname = malloc(101);
if (surname == NULL)
exit(71);
i = 0;
j = 0;
while(line[i] != ' ')
i++;
while(line[++i] != ' ')
surname[j++] = line[i];
surname[j] = 0;
return surname;
}
At least these problems:
++ not sequenced
name[i] = line[i++]; is bad code. The i++may occur before, after, (or even during) name[i]. Result: undefined behavior (UB). #paddy
Limited size
char *name = malloc(51); does not need to use the magic number 51.
May run off end
while(line[i] != ' ') leads to trouble when line[] lacks a ' '.
Alternative (like OP's code)
char *get_name(char *line) {
size_t i = 0;
while(line[i] != ' ' && line[i] != '\0') {
i++;
}
char *name = malloc(i + 1);
if (name == NULL) {
exit(71);
}
for (size_t j = 0; j < i; j++) {
name[j] = line[j];
}
name[i] = 0;
return name;
}
Or perhaps using standard efficient library functions
char *get_name(const char *line) {
size_t token_length = strcspn(line, " ");
char *name = malloc(token_length + 1);
if (name == NULL) {
exit(71); // Consider a named macro/enum here rather than a magic 71
}
name[token_length] = '\0';
return memcpy(name, line, token_length);
}
Other issues
Off by 1
// fgets(line, MaxLinea, archivo)
fgets(line, sizeof line, archivo)
Advanced: Assuming first, last names do not include spaces
Consider first names like "Betty Jo" and last names like Lloyd Webber
Some names are longer than 51.
Related
in today task i had to implement the function "my_split" that is based on pointers and accessing addresses, I'm having a little bit of trouble with "catching" all of the content from the file into the output.
this is my function:
void my_split(const char *source, char *first, char *second, const char delim){
int ree = 1;
while(*source != '\n'){
if(*source == delim){
ree = 0;
*source++;
}
else{
if(ree == 1){
*first++ = *source++;
}
else {
*second++ = *source++;
}
}
}
*first = '\0';
*second = '\0';
}
Main function:
int main(void){
int max_n = 200;
char source[max_n];
char strA[max_n];
char strB[max_n];
int T;
scanf("%d%*c", &T);
for(int i = 0; i < T; i++){
fgets (source, max_n, stdin);
my_split(source, strA, strB, ';');
printf("First: %s\n", strA);
printf("Second: %s\n", strB);
}
}
^^^ teacher gave us this one.
TXT FILE:
2
2345.454;6737.98
this is the line;splitted by semicolon
My output is:
First:
Second:
First: 2345.454
Second: 6737.98
The desired output is:
First: 2345.454
Second: 6737.98
First: this is the line
Second: splitted by semicolon
I'm trying to make above function, but It didn't workout, well it works half-succesfull
Your function seem to work. Try it like this...
#include <stdio.h>
void my_split(const char *, char *, char *, const char);
int main() {
FILE* fp;
fp = fopen("data.txt", "r");
if (NULL == fp) {
printf("file can't be opened \n");
return 0;
}
char source[100];
while (fgets(source, 100, fp) != NULL) {
char first[100] = "", second[100] = "";
my_split(source, first, second, ';');
printf("First: %s\n", first);
printf("Second: %s\n", second);
}
// Closing the file
fclose(fp);
return 0;
}
void my_split(const char *source, char *first, char *second, const char delim){
int ree = 1;
while(*source != '\n'){
if(*source == delim){
ree = 0;
*source++;
}
else{
if(ree == 1){
*first++ = *source++;
}
else {
*second++ = *source++;
}
}
}
*first = '\0';
*second = '\0';
}
It outputs:
First: 2
Second:
First: 2345.454
Second: 6737.98
First: this is the line
Second: splitted by semicolon
I have csv file with below format :
name,birthmonth,country,hobby
jack,jan,england,soccer
roben,july,germany,soccer
emma,dec,china,tennis
yannick,sep,france,music
alex,nov,england,cricket
thomas,apr,germany,tennis
mike,oct,netherlands,cycling
michelle,feb,france,poetry
yui,mar,japan,coding
feng,jun,china,reading
I want to parse this file using C, and put all the lines with same country name in a consecutive manner i.e shown below:
name,birthmonth,country,hobby
jack,jan,england,soccer
alex,nov,england,cricket
roben,july,germany,soccer
thomas,apr,germany,tennis
emma,dec,china,tennis
feng,jun,china,reading
yannick,sep,france,music
michelle,feb,france,poetry
mike,oct,netherlands,cycling
yui,mar,japan,coding
So far, I have tried this code below, however not able to match things properly and proceed further:
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<fcntl.h>
#include<string.h>
int main (int argc, char **argv) {
//int line;
char line[200];
char *inputFile = argv[1];
FILE *input_csv_file;
char a,b,c,d,e;
input_csv_file = fopen(inputFile, "rt");
if(input_csv_file ==0) {
printf("Can not open input file \n");
}
else {
//while((line = fgetc(input_csv_file)) != EOF) {
while(fgets(line, sizeof line, input_csv_file) != NULL) {
printf ("line = %s\n", line);
if(sscanf(line, "%s,%s,%s,%s,%s", a,b,c,d,e)) {
//if(sscanf(line, "%[^,], %[^,], %[^,], %[^,], %[^,]", a,b,c,d,e)) {
printf("d=%s\n",d);
}
}
}
return 0;
}
I am a newbie in C/C++. Any help would be much appreciated
Thanks.
I could write the code to get the required output. Below is the code:
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<fcntl.h>
#include<string.h>
int main(int argc, char ** argv)
{
struct filedata {
char nation[8];
char content[50];
};
char line[100];
char *inputFile = argv[1];
FILE *input_csv_file;
int iter = 0, c;
char * tok;
int count = 0;
char ch;
char country[] = "country";
char header_line[50];
input_csv_file = fopen(inputFile, "rt");
//count line numbers of the input csv
for(ch = getc(input_csv_file); ch!= EOF; ch=getc(input_csv_file))
if(ch == '\n')
count = count + 1;
fclose(input_csv_file);
count = count -1;
struct filedata * record[count];
input_csv_file = fopen(inputFile, "rt");
if(input_csv_file == 0)
{
printf("Can not open input file\n");
} else
{
while(fgets(line, sizeof line, input_csv_file) != NULL)
{
//printf("-- line = %s\n", line);
int s_line = sizeof line;
char dup_line[s_line];
strcpy(dup_line, line);
int h = 0;
int s_token;
tok = strtok(line, ",");
while(tok != NULL)
{
h++;
if(h == 3)
{
s_token = sizeof tok;
break;
}
tok = strtok(NULL, ",");
}
// skipping the line having column headers
if(compare_col(tok, country) == 0) {
strcpy(header_line, dup_line);
continue;
}
iter++;
c = iter - 1;
record[c] = (struct filedata*)malloc(sizeof(struct filedata));
strcpy(record[c]->nation, tok);
strcpy(record[c]->content, dup_line);
} //while
struct filedata * temp;
FILE * fptr;
fptr = fopen("nation_csv.txt", "w");
if(fptr == NULL)
{
printf("Error in opening the file to write\n");
exit(1);
}
// sorting the arr of struct nation wise
for(iter=1; iter < count; iter++)
for(c =0 ; c < count -1; c++) {
if(strcmp(record[c]->nation, record[c+1]->nation) > 0) {
temp = record[c];
record[c] = record[c+1];
record[c+1] = temp;
}
}
for(iter=0; iter < count; ++iter)
{
if(iter == 0) {
fprintf(fptr, "%s", header_line);
continue;
}
fprintf(fptr, "%s", record[iter]->content);
}
fclose(fptr);
}
fclose(input_csv_file);
}
int compare_col(char a[], char b[] )
{
int c = 0;
while(a[c] == b[c]) {
if(a[c] == '\0' || b[c] == '\0')
break;
c++;
}
if(a[c] == '\0' && b[c] == '\0')
return 0;
else
return -1;
}
Thanks for all your inputs. Any further inputs to make it better are much appreciated.
Thanks
I'm writing a small application for college that parses some wikipedia pages and outputs information about the people in the pages.
I wrote it in Java and am trying to re-write it in C. I'm getting a weird bug, sometimes the program's output is correct and sometimes it is wrong, without changing the input.
Here is a sample input that triggers the error with the name "105.html"
This is the output I get sometimes:
105 Linus Pauling Estadunidense 28 de fevereiro de 1901 Portland, Oregon 19 de agosto de 1994 Big Sur, Califórnia 93
This is the output I get other times:
105 Linus Pauling Estadunidense 28 de f#evereir#o�y� dC�L��e ���y�19I�L��01 Portland, Oregon 19 de agosto de 1994 Big Sur, Califórnia 93
I notice that if I set a breakpoint in XCode, I usually get the RIGHT result...
I'm new to C so I actually have no clue how to start debugging this.
Here is the code if anyone is interested in actually reading it. The code is in a mixture of Portuguese and English but I added English comments so it should be easy to follow.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct pessoa{
int id;
char *nome; //name
char *nacionalidade; // nationality
char *nascimento; // date of birth
char *local_nascimento; // place of birth
char *morte; // date of death
char *local_morte; // place of death
int idade; // age
};
struct pessoa *inicializar(int n) {
struct pessoa *pessoas = malloc(sizeof(pessoas) * n);
return pessoas;
}
void imprimir_pessoa(struct pessoa *p) {
printf("%i %s %s %s %s %s %s %i\n", p->id, p->nome, p->nacionalidade,
p->nascimento, p->local_nascimento, p->morte,
p->local_morte, p->idade);
}
void imprimir_pessoa_asterisco(struct pessoa *p) {
printf("%i ## %s ## %s ## %s ## %s ## %s ## %s ## %i\n", p->id, p->nome, p->nacionalidade,
p->nascimento, p->local_nascimento, p->morte,
p->local_morte, p->idade);
}
size_t index_of(char *string, char *to_find) {
return strstr(string, to_find) - string;
}
char *remove_tags(char *string) {
// inicializa para o mesmo tamanho da string de entrada para garantir que ira caber
char * resp = malloc(sizeof(char) * strlen(string) + 1);
// jumps over the html tags and finds the aproppriate information
for (size_t i = 0; i < strlen(string); i++) {
while (i < strlen(string) && string[i] == '<') {
for (i++; string[i] != '>'; i++);
i++;
while(i < strlen(string) && string[i] == '&'){
for (i++; string[i] != ';'; i++);
i++;
}
}
while(i < strlen(string) && string[i] == '&'){
for (i++; string[i] != ';'; i++);
i++;
resp[strlen(resp)] = ' ';
}
if (i < strlen(string)) {
resp[strlen(resp)] = string[i];
}
}
while(strlen(string) > 0 && resp[0] == ' '){ // jumps over white spaces on the begining
resp += 1;
}
resp[strlen(resp)] = 0;
return resp;
}
char* extrair_nome(char *string) { // extract the person's name
size_t index = index_of(string, "<title>") + strlen("<title>");
size_t index_fim = index_of(string, " Wiki") - 4;
char *nome = malloc(sizeof(char) * (index_fim - index));
memcpy(nome, (string+index), index_fim - index);
return nome;
}
char* substring(char * string, char *c) {
return string + strcspn(string, c);
}
void remove_new_line(char *string) {
char *pos;
if ((pos=strchr(string, '\n')) != NULL)
*pos = '\0';
}
void ler_pessoa(char *nome_arquivo, struct pessoa *p) { // parse the file to fill the pessoa struct
size_t length = strlen(nome_arquivo);
p->id = (nome_arquivo[length - 8] - 48) * 100;
p->id = (p->id + (nome_arquivo[length - 7] - 48) * 10);
p->id = p->id + (nome_arquivo[length - 6] - 48);
int tamanho_linha = 2000;
char *linha = malloc(sizeof(char) * tamanho_linha);
FILE *fp = fopen(nome_arquivo, "r");
if (fp == NULL) {
printf("Falha ao abrir arquivo %s\n", nome_arquivo);
exit(1);
}
while (fgets(linha, tamanho_linha, fp) != NULL) {
if (strstr(linha, "<title>")) { // extracts name
p->nome = extrair_nome(linha);
remove_new_line(p->nome);
break;
}
}
while (fgets(linha, tamanho_linha, fp) != NULL) {
if (strstr(linha, "Nacionalidade")) { // extracts nationality
fgets(linha, tamanho_linha, fp);
p->nacionalidade = remove_tags(linha);
remove_new_line(p->nacionalidade);
break;
}
}
while (fgets(linha, tamanho_linha, fp) != NULL) {
if (strstr(linha, "Nascimento")) { // extracts date of births
fgets(linha, tamanho_linha, fp);
p->nascimento = remove_tags(linha); // <-- this one is not working all the time??
remove_new_line(p->nascimento);
break;
}
}
//se vivo
if (strstr(p->nascimento, ")") != NULL) { // if the person is alive the date of birth date is of the type: date(age)
char *tmp = malloc(sizeof(char) * strlen(p->nascimento)); // so we extract the age
strcpy(tmp, p->nascimento);
tmp = tmp + strcspn(tmp, "(") + 1;
tmp[index_of(tmp, " ")] = 0;
p->idade = atoi(tmp);
p->morte = "vivo"; // not dead
p->local_morte = "vivo"; // not dead
} else {
p->morte = ""; // we set this later
p->local_morte = "";
}
while (fgets(linha, tamanho_linha, fp) != NULL) {
if (strstr(linha, "Local")) { // extracts place of death
fgets(linha, tamanho_linha, fp);
p->local_nascimento = remove_tags(linha);
remove_new_line(p->local_nascimento);
break;
}
}
if (strlen(p->morte) == 0) { // we set this now if the person is not alive (hence size 0)
while (fgets(linha, tamanho_linha, fp) != NULL) {
if (strstr(linha, "Morte")) { // extract death day
fgets(linha, tamanho_linha, fp);
p->morte = remove_tags(linha);
remove_new_line(p->morte);
break;
}
}
if (strstr(p->morte, "(") != NULL) {
char *tmp = malloc(sizeof(char) * strlen(p->morte));
strcpy(tmp, p->morte); // extract age when the person died, like above
tmp = tmp + strcspn(tmp, "(") + 1;
tmp[index_of(tmp, " ")] = 0;
p->idade = atoi(tmp);
p->morte[index_of(p->morte, "(")] = 0;
}
while (fgets(linha, tamanho_linha, fp) != NULL) {
if (strstr(linha, "Local")) { // get the place of death
fgets(linha, tamanho_linha, fp);
p->local_morte = remove_tags(linha);
remove_new_line(p->local_morte);
break;
}
}
}
fclose(fp);
}
int main(int argc, const char * argv[]) {
struct pessoa p;
ler_pessoa("/tmp/105.html", &p);
imprimir_pessoa(&p);
return 0;
}
resp[strlen(resp)] = ' '; and resp[strlen(resp)] = string[i]; are bad as resp[] is not certainly null character terminated.
Code needs a new approach to determine which element of resp[] to assign.
resp[strlen(resp)] = 0; is questionable too.
strlen(resp) returns the length of the string, not counting the null terminator. For strlen() to work well, resp must be null terminated first, else it is not referencing a string. The null character is in the index that equals the length, so resp[strlen(resp)] = 0; is a no-op function, other than killing some CPU cycles.
Code has other problems.
Example: Insufficient space. #Weather Vane;
// bad code
char *tmp = malloc(sizeof(char) * strlen(p->nascimento)); // so we extract the age
strcpy(tmp, p->nascimento);
Sample string allocator/duplicator (Note: strdup() often exists on many platforms)
char *strdupe(const char *s) {
size_t size = strlen(s) + 1;
dupe = malloc(size);
if (dupe) {
memcpy(dupe, s, size);
}
return dupe;
}
This task is to get the first line as a title then calculate data from a file ,the minus number is by parentheses. It will print the title and he sum of these data. each line is terminated by newline character. I don't know what the problem is. I don't know how to deal with "Bus error 10". Maybe because of the allocation of memory, I have no idea... Can anyone help me?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Our definition of a structure to represent department data.
struct dept {
int id;
char *name;
int balance;
struct dept *next;
};
typedef struct dept dept_t;
// For (a)
dept_t *create_dept(int dept_id, char *dept_name, int dept_balance);
// For (b)
dept_t *load_dept(int id);
// For (c)
void free_dept(dept_t *dept);
// For (d)
void print_dept(dept_t *dept);
int main(int argc, char *argv[])
{
dept_t *d = load_dept(51423);
print_dept(d);
free_dept(d);
}
// (a)
dept_t *create_dept(int dept_id, char *dept_name, int dept_balance)
{
dept_t *d = malloc(sizeof(dept_t));
d->id = dept_id;
d->name = dept_name;
d->balance = dept_balance;
d->next = NULL;
return d;
}
// (b)
char *prompt(FILE *fp)
{
char ch;
// skip leading whitespace
do
{
fscanf(fp, "%c", &ch);
if(feof(fp))
{
return NULL;
}
} while(ch == '\n');
// read in until whitespace
int cur_size = 8;
char *str = malloc(sizeof(char) * cur_size);
int cur_pos = 0;
str[cur_pos] = ch;
cur_pos++;
do
{
fscanf(fp, "%c", &ch);
if(feof(fp))
{
str[cur_pos] = '\0';
return str;
}
str[cur_pos] = ch;
cur_pos++;
if(cur_pos >= cur_size - 1)
{
cur_size = cur_size * 2;
str = realloc(str, sizeof(char) * cur_size);
}
} while(ch != '\n');
str[cur_pos - 1] = '\0';
return str;
}
dept_t *load_dept(int id)
{
FILE *fp;
char *filename;
int balance = 0;
char *name;
char *string;
int i;
dept_t *d;
filename = malloc(sizeof(char)*10);
sprintf(filename,"%d.txt",id);
if((fp = fopen(filename,"r")) == NULL)
{
fprintf (stdout,"Can't open \"%s\"file.\n",filename);
exit(1);
}
name = prompt(fp);
int value;
for(i=0;i<6;i++)
{
string = prompt(fp);
if (string[0]=='(')
{
value = atoi(&string[1]);
balance = balance - value;
}
else
{
value = atoi(string);
balance = balance + value;
}
}
free(string);
free(filename);
if(fclose(fp)!=0)
{
fprintf(stderr,"Error closing file\n");
}
d = create_dept(id,name,balance);
return d;
}
// For (c)
void free_dept(dept_t *dept)
{
free(dept->name);
free(dept);
}
// For (d)
void print_dept(dept_t *dept)
{
printf("Department: %s",dept->name);
printf(" %d",dept->balance);
}
Since, as user3629249 noted, the function: prompt() can return a null pointer, you should change
for(i=0;i<6;i++)
{
string = prompt(fp);
to
while (string = prompt(fp))
{
(then less than 6 data lines won't cause a fault).
When I gdb the program, it says something is wrong with strcpy, but I do not know why.
Thanks.
The program requires me to read an input file, find the course abbreviation, the course description, the number of credit hours, and the professor name.
Also, I am trying to read the credit hours from the file, which are on the same line as the course. I am trying to only get the credit hours that are on the same line as the course, but it instead prints every number as a credit hour.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX 20
typedef struct courses{
char *abbr;
char *name;
int credits;
char *prof;
struct courses *next;
}courses;
int isAbbr(char *string);
int isName(char *string);
int isCredit(char *string);
int isProf(char *string);
courses *readfile(FILE *);
courses *create_course(char *abbr, char *name, int credits, char *prof);
courses *create_list(courses *, courses *);
int main(int argc, char **argv)
{
if (argc != 2)
{
printf("Inadequate amount of arguments.\n");
return 0;
}
FILE *fp = fopen(argv[1], "r");
if (fp == NULL)
{
printf("File cannot be opened.\n");
return 0;
}
courses* head = NULL;
head = readfile(fp);
int choice = 0;
while (choice != 3)
{
printf("\nSelect your option below:\n1-Register for a Course\n2-See my total\n3-Exit\nChoice: ");
scanf("%d",&choice);
}
return 0;
}
courses *readfile(FILE *fp)
{
courses *head, *entry;
head = entry = NULL;
char *abbr = malloc(MAX);
char *namep = malloc(MAX);
namep = "hello";
char *prof = malloc(MAX);
int credit;
int credflag = 0;
int nameFlag = 0;
int profFlag = 0;
int credits = 0;
char line[MAX];
while (fgets(line, MAX - 1, fp) != NULL)
{
if (line[strlen(line) - 1] == '\n')
{
line[strlen(line) - 1] = '\0';
}
char* token = strtok(line," ,\t");
while (token != NULL)
{
if (isAbbr(token) == 1)
{
abbr = token;
credflag = 1;
}
if (isName(token) == 1)
{
credflag = 1;
}
if (isCredit(token) == 1)
{
if(credflag == 1)
{
credits = atoi(token);
credflag = 0;
}
}
if (isProf(token)== 1)
{
if(nameFlag == 1) //print names, reset name flag = 0
{
entry = create_course(abbr, namep, credits, token);
head = create_list(entry,head);
nameFlag = 0;
}
else
{
namep = malloc(sizeof(char));
strcpy(namep, token);
nameFlag = 1;
}
}
else
{
nameFlag = 0;
}
token = strtok(NULL," ,\t");
}
}
}
courses *create_course(char *abbr, char *name, int credits, char *prof)
{
courses *entry = malloc(sizeof(courses));
entry->abbr=(char*)malloc(sizeof(char)*256);
strcpy(entry->abbr, abbr);
entry->name=(char*)malloc(sizeof(char)*256);
strcpy(entry->name, name);
entry->abbr=(char*)malloc(sizeof(char)*256);
strcpy(entry->prof, prof);
entry->credits = credits;
entry->next = NULL;
return entry;
}
courses *create_list(courses *head, courses *entry)
{
if (head == NULL)
{
return entry;
}
courses* curr = head;
while (curr->next != NULL)
{
curr = curr->next;
}
curr->next = entry;
return head;
}
int isProf(char *string)
{
int length = strlen(string);
int i;
if (isupper(string[0]))
{
for (i=1; i<length; i++)
{
if (islower(string[i]))
{
continue;
}
else
{
return 0;
}
}
return 1;
}
}
int isCredit(char *string)
{
int n;
int nfields = sscanf(string, "%d", &n);
if (nfields == 1 && n > 0)
{
return 1;
}
return 0;
}
int isName(char *string)
{
return 1;
}
int isAbbr(char *string)
{
int length = strlen(string);
if (length == 8 && string[4] == '-')
{
printf(" %s\n",string);
return 1;
}
return 1;
}
Just focus on strcpy:
char *namep = malloc(MAX);
namep = "hello";
here you just lose what you malloc for namep, use strcpy or something you want.
namep = malloc(sizeof(char));
strcpy(namep, token);
here you just malloc 1 char for namep, but strcpy auto add NULL terminator, so unless token is "", you overflow namep.
And every strcpy in create_course(), you just malloc 256 and strcpy, what if size of abbr, name, prof > 255? check size or use strncpy().