while-loop read only first line from file - c

Welcome, I have problem with my while-loop. It only reads first line from file.txt. Before adding funcition to split my line by strtok_r ,my apps doesnt work good.The purpose of this while-loop is reads all line from file and split everysingle line by "|" and these parts add to appropriate tabs.
What should i do?
Its my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mem.h>
#include <assert.h>
struct movie {
char title[100];
int year;
char genre[100];
};
int i = 0;
struct movie *movies[50];
int porownaj(struct movie* first, struct movie* second)
{
if(first->year==second->year){
if(first->title>second->title){
return 1;
}
if(first->title<second->title){
return -1;
}
if(first->title==second->title){
if(first->genre>second->genre){
return 1;
}
if(first->genre<second->genre){
return -1;
}
if(first->genre==second->genre){
return 0;
}
}
}
if(first->year>second->year){
return 1;
}
if(first->year<second->year){
return -1;
}
if(first->title==second->title){
if(first->year>second->year){
return 1;
}
if(first->year<second->year){
return -1;
}
if(first->year==second->year){
if(first->genre>second->genre){
return 1;
}
if(first->genre<second->genre){
return -1;
}
if(first->genre==second->genre){
return 0;
}
}
}
if(first->title>second->title){
return 1;
}
if(first->title<second->title){
return -1;
}
if(first->genre==second->genre){
if(first->year>second->year){
return 1;
}
if(first->year<second->year){
return -1;
}
if(first->year==second->year){
if(first->title>second->title){
return 1;
}
if(first->title<second->title){
return -1;
}
if(first->title==second->title){
return 0;
}
}
}
if(first->genre>second->genre){
return 1;
}
if(first->genre<second->genre){
return -1;
}
}
void zamien(struct movie* movies[50], int x, int y)
{
struct movie* tmpMovie = movies[x];
movies[x] = movies[y];
movies[y] = tmpMovie;
}
int main()
{
struct movie *movies[50];
do
{
printf("\n");
printf("Projekt nr 6 \n");
printf("\n");
printf("\b MENU GLOWNE \n");
printf("|-----------------| \n");
printf("[1]Baza filmow \n");
printf("[2]Dodaj film \n");
printf("[3]Zakoncz Program \n");
printf("|-----------------| \n");
char znak;
printf("Wybierz opcje z menu: ");
scanf("%s", &znak);
system("cls");
switch (znak)
{
case '1':
system("cls");
printf("Wybrales opcje BAZA FILMOW \n");
printf("TYTUL | ROK | GATUNEK\n");
printf("----------------------\n");
FILE *baza;
if ((baza = fopen("movies.txt", "r")) == NULL)
{
system("cls");
printf("Blad otwarcia pliku\n");
exit(1);
}
char tekst[512];
char *title = NULL;
char *year = NULL;
char *genre = NULL;
char *buffer = NULL;
int x = 0;
while (fgets(tekst, 512, baza) != NULL)
{
printf("%s", tekst);
title = strtok_r(tekst, "|", &buffer);
assert(title != NULL);
strcpy(movies[x]->title, title);
year = strtok_r(NULL, "|", &buffer);
assert(year != NULL);
movies[x]->year = atoi(year);
genre = strtok_r(NULL, "|", &buffer);
assert(genre != NULL);
strcpy(movies[x]->genre, genre);
x++;
}fclose(baza);
do
{
printf("\n[1]Sortuj wg. tytulu");
printf("\n[2]Sortuj wg. roku produkcji");
printf("\n[3]Sortuj wg. gatunku filmu");
printf("\n[4]Wroc do glownego menu\n");
printf("|-----------------|\n");
char click;
printf("\nWybierz opcje: ");
scanf("%s", &click);
switch (click)
{
case '1':
system("cls");
printf("Sorotowanie wg. tytulu");
/*
for(int i=0;i<10-1;i++){
for(int j=0;j<10-i-1;j++){
if(porownaj(&title[j],&title[j+1])>0){
zamien(&title[j],&title[j+1]);
}
}
}
for(int i=0;i<10;i++){
printf("(%d, %d)", title[i].x, );
}
*/
break;
case '2':
system("cls");
printf("Sorotowanie wg. roku produkcji");
/*
for(int i=0;i<10-1;i++){
for(int j=0;j<10-i-1;j++){
if(porownaj(&year[j],&year[j+1])>0){
zamien(&year[j],&year[j+1]);
}
}
}
for(int i=0;i<10;i++){
printf("(%d, %d)", year[i].x, );
}
*/
break;
case '3':
system("cls");
printf("Sorotowanie wg. gatunku filmu");
break;
case '4':
system("cls");
return main();
default:
system("cls");
printf("Nie ma takiej opcji. Program sie wylaczy!");
return 0;
}
} while (1);
case '2':
system("cls");
printf("Wybrales opcje DODAJ FILM \n");
movies[i] = malloc(sizeof(movie));
printf("Podaj nazwe filmu: ");
while ((getchar()) != '\n');
gets(movies[i]->title);
printf("Podaj rok produkcji: ");
scanf("%d", &(movies[i]->year));
printf("Podaj gatunek filmu: ");
while ((getchar()) != '\n');
gets(movies[i]->genre);
fflush(stdin);
FILE *plik = fopen("movies.txt", "a+");
fprintf(plik, "%s | %d | %s \n", movies[i]->title, movies[i]->year, movies[i]->genre);
fclose(plik);
i++;
printf("Zapisane..");
continue;
case '3':
system("cls");
printf("ZAKONCZ PROGRAM \n");
return 0;
default:
printf("Nie ma takiej opcji! \n");
return main();
}
}while (1);
return (0);
}
movies.txt:
Title | 1234 | Scifi
Title_2 | 4321 | SciFI

I bet that every line is printed with printf("%s", tekst);.
But you forget that strtok does not make a copy of the string. Thus (if you have your assignments fixed the other way around), you still assign poinetrs into the same tekst variable to all your movies. Instead allocate memory and copy the strings:
title = strtok_r(tekst, "|", &buffer);
movies[x]->title= malloc(strlen(title)+1);
strcpy(movies[x]->title, title);
and the same for the other string variables.

There are a number of bugs in your program.
To start with this:
char title = NULL;
char year = NULL;
char genre = NULL;
together with this:
title = strtok_r(tekst, "|", &buffer);
year = strtok_r(NULL, "|", &buffer);
genre = strtok_r(NULL, "|", &buffer);
int year = atoi(year);
You define title as a char but strtok_r returns a char*. Consequently you overwrite memory by storing a "char pointer" in a "char" variable.
This could destroy the file-pointer. The error 0xC0000005 you get (as you mention in a comment) could indicate that:
Application Error 0xc0000005 (Access Violation) error is usually caused by your computer not being able to correctly process the files...
Change the definition to:
char *title = NULL;
char *year = NULL;
char *genre = NULL;
Further:
year = strtok_r(NULL, "|", &buffer); // A variable named year
genre = strtok_r(NULL, "|", &buffer);
int year = atoi(year); // A NEW variable with same name!!
Change it to:
year = strtok_r(NULL, "|", &buffer);
genre = strtok_r(NULL, "|", &buffer);
int yearN = atoi(year); // Use another name
Further you should always check that year is not NULL before calling atoi
So my suggestion is to simplify your code for debugging. Try:
FILE *baza;
if ((baza = fopen("movies.txt", "r")) == NULL)
{
system("cls");
printf("Blad otwarcia pliku\n");
exit(1);
}
char tekst[512];
char* title = NULL;
char* year = NULL;
char* genre = NULL;
char* buffer = NULL;
int x = 0;
printf("while-loop start\n");
while (fgets(tekst, 512, baza) != NULL)
{
printf("%s", tekst);
//x++;
//title = strtok_r(tekst, "|", &buffer);
//year = strtok_r(NULL, "|", &buffer);
//genre = strtok_r(NULL, "|", &buffer);
//int year = atoi(year);
//title=movies[x]->title;
//year=movies[x]->year;
//genre=movies[x]->genre;
}
printf("while-loop complete\n");
Now check the output you get from this code. If that works as expected, you can start to un-comment lines one-by-one.
In the end I guess your function should look like:
FILE *baza;
if ((baza = fopen("movies.txt", "r")) == NULL)
{
system("cls");
printf("Blad otwarcia pliku\n");
exit(1);
}
char tekst[512];
char* title = NULL;
char* year = NULL;
char* genre = NULL;
char* buffer = NULL;
int x = 0;
while (fgets(tekst, 512, baza) != NULL)
{
printf("%s", tekst);
title = strtok_r(tekst, "|", &buffer);
assert(title != NULL);
strcpy(movies[x]->title, title);
year = strtok_r(NULL, "|", &buffer);
assert(year != NULL);
movies[x]->year = atoi(year);
genre = strtok_r(NULL, "|", &buffer);
assert(genre != NULL);
strcpy(movies[x]->genre, genre);
x++;
}
The above assumes that you have already allocated memory for all pointers in movies. Like:
struct movie { char title[100]; int year; char genre[100]; };
int main() {
int i = 0;
struct movie *movies[50];
for(i=0; i<50; ++i) movies[i] = malloc(sizeof *movies);
. . .

out of any other possible problems these lines are problematic :
title=movies[x]->title;
year=movies[x]->year;
genre=movies[x]->genre;
as it is said in remark the assignments must be reversed ( movies[x]->foo = foo;)
you need to duplicate the strings else you save a sub addresses of tekst which is modified each loop and may be disappeared when you will use them
so
movies[x]->title = strdup(title);
movies[x]->year = year;
movies[x]->genre = strdup(genre);
Or course if movies[x]->title and movies[x]->genre are char[] rather than char* the code have to copy rather than duplicate :
strcpy(movies[x]->title, title);
movies[x]->year = year;
strcpy(movies[x]->genre, genre);
and if needed replace strcpy by strncpy to not overflow

Related

I can't get this function for creating strings from file

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <math.h>
#include <time.h>
#include <assert.h>
#define MAX_SIZE 100
#define ODIT "log_file.txt"
#define INVENTORY_N "inventory_names.txt"
#define INVENTORY_A "inventory_amount.txt"
#define CURR_DIR "main-2dynamic"
static int inventory_amount_array[MAX_SIZE];
static char inventory_names_array[MAX_SIZE][MAX_SIZE];
void print_avail_opt(){
printf("1) Read from the log file\n");
printf("2) Save the current inventory in the log file\n");
printf("3) Print current inventory item amounts\n");
printf("4) Print current inventory item names\n");
printf("5) Exit\n");
}
void get_inventory_int(){
int i,n;
char *token;
char help[256];
FILE *InputFile;
InputFile = fopen(INVENTORY_A, "r");
fscanf(InputFile, "%s", help);
token = strtok(help, ",");
i = 0;
while(token != NULL){
inventory_amount_array[i] = atoi(token);
token = strtok(NULL, ",");
i++;
}
n = i;
}
void get_inventory_string(){
int i,n;
char *token;
char help[256];
FILE *InputFile;
InputFile = fopen(INVENTORY_A, "r");
fscanf(InputFile, "%s", help);
token = strtok(help, ",");
i = 0;
while(token != NULL){
inventory_names_array[i][i] = token;
token = strtok(NULL, ",");
i++;
}
n = i;
}
void print_inventory_int(){
int n = 10;
get_inventory_int();
for (int i = 0; i<n; i++){
if( inventory_amount_array[i] == '\0'){
break;
}
else{
printf("Available stock from item:%d\n",inventory_amount_array[i]);
}
}
}
void print_inventory_string(){
int n = 10;
get_inventory_string();
for (int i = 0; i<n; i++){
if(inventory_names_array[i][i] == '\0'){
break;
}
else{
printf("Available stock from %s\n",inventory_names_array[i]);
}
}
}
void f_print_inventory_int(FILE * log_file){
int n;
get_inventory_int();
for (int i = 0; i<n; i++){
if( inventory_amount_array[i] == '\0'){
break;
}
else{
fprintf(log_file,"%d ",inventory_amount_array[i]);
}
}
}
int read_from_file(FILE * log_file){
log_file = fopen(ODIT, "r");
char str[MAX_SIZE];
while(fscanf(log_file,"%s", str)!=EOF){
printf("%s", str);
}
fclose(log_file);
}
int write_in_file(FILE * log_file, int tm_year, int tm_mon, int tm_mday,int tm_hour, int tm_min, int tm_sec){
log_file = fopen(ODIT, "a");
fprintf(log_file,"\nInventory at %02d.%02d.%02d - %02d:%02d:%02d\n", tm_mday, tm_mon, tm_year, tm_hour, tm_min,tm_sec);
f_print_inventory_int(log_file);
fclose(log_file);
}
int restock (){
}
int main(){
time_t T = time(NULL);
struct tm tm = *localtime(&T);
FILE * log_file;
bool loop = true;
while (loop == true){
print_avail_opt();
printf("Enter op:");
int op = 0;scanf("%d", &op);
switch (op){
case 1: read_from_file(log_file);
break;
case 2: write_in_file(log_file, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
break;
case 3: print_inventory_int();
break;
case 4: print_inventory_string();
break;
case 5: loop = false;
break;
default: printf("Not correct option\n");
break;
}
}
return 0;
}
I want to make case 4 in the main switch to work properly
The things that are not working are the way of creating strings arrays and printing it out - everything else works fine.
PS: And i would really appreciate a working functions, because i have it for homework at school and it's due tomorrow.
Note from my compiler (gcc):
main.c: In function ‘get_inventory_string’:
main.c:57:37: warning: assignment to ‘char’ from ‘char *’ makes integer from pointer without a cast [-Wint-conversion]
57 | inventory_names_array[i][i] = token;
|
Just as the compiler warning said, your error is here:
inventory_names_array[i][i] = token;
inventory_names_array[i][i] is a char; token is a pointer. You need to dereference the pointer (note: this will clear this error, but you have other problems in your code, too).
The compiler is warning you that you are assigning a char* pointer to a single char value in this statement:
inventory_names_array[i][i] = token;
That is not what you want or need. You need to copy the characters pointed at by token into the array. You can use strncpy() for that:
strncpy(inventory_names_array[i], token, MAX_SIZE);
That being said, there are other problems with your code:
not checking fopen() for failure.
not closing opened files with fclose().
not preventing buffer overflows.
your get functions are not storing n anywhere that your print function can reach, so you end up looping through the arrays using incorrect counts. You should have the get functions return the actual array counts to the caller.
read_from_file() and write_in_file() both take in a FILE* parameter that they don't use. Also, they are declared as returning an int, but they don't actually return anything.
With that said, try something more like this instead:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <math.h>
#include <time.h>
#include <assert.h>
#define MAX_SIZE 100
#define ODIT "log_file.txt"
#define INVENTORY_N "inventory_names.txt"
#define INVENTORY_A "inventory_amount.txt"
#define CURR_DIR "main-2dynamic"
static int inventory_amount_array[MAX_SIZE];
static char inventory_names_array[MAX_SIZE][MAX_SIZE];
void print_avail_opt(){
printf("1) Read from the log file\n");
printf("2) Save the current inventory in the log file\n");
printf("3) Print current inventory item amounts\n");
printf("4) Print current inventory item names\n");
printf("5) Exit\n")
}
int get_inventory_int(){
int i = 0;
char help[256];
FILE *InputFile = fopen(INVENTORY_A, "r");
if (InputFile == NULL) return 0;
fscanf(InputFile, "%255s", help);
fclose(InputFile);
char *token = strtok(help, ",");
while (token != NULL && i < MAX_SIZE){
inventory_amount_array[i] = atoi(token);
token = strtok(NULL, ",");
++i;
}
return i;
}
int get_inventory_string(){
int i = 0;
char help[256];
FILE *InputFile = fopen(INVENTORY_A, "r");
if (InputFile == NULL) return 0;
fscanf(InputFile, "%255s", help);
fclose(InputFile);
char *token = strtok(help, ",");
while (token != NULL && i < MAX_SIZE){
strncpy(inventory_names_array[i], token, MAX_SIZE);
token = strtok(NULL, ",");
++i;
}
return i;
}
void print_inventory_int(){
int n = get_inventory_int();
for (int i = 0; i < n; ++i){
if (inventory_amount_array[i] == 0){
break;
}
printf("Available stock from item: %d\n", inventory_amount_array[i]);
}
}
void print_inventory_string(){
int n = get_inventory_string();
for (int i = 0; i < n; ++i){
if (inventory_names_array[i][i] == '\0'){
break;
}
printf("Available stock from %s\n", inventory_names_array[i]);
}
}
void f_print_inventory_int(FILE * log_file){
int n = get_inventory_int();
for (int i = 0; i < n; ++i){
if (inventory_amount_array[i] != 0){
fprintf(log_file, "%d ", inventory_amount_array[i]);
}
}
}
void read_from_file(){
FILE *log_file = fopen(ODIT, "r");
if (log_file == NULL) return;
char str[MAX_SIZE];
while (fscanf(log_file, "%99s", str) == 1){
printf("%s", str);
}
fclose(log_file);
}
void write_in_file(int tm_year, int tm_mon, int tm_mday, int tm_hour, int tm_min, int tm_sec){
FILE *log_file = fopen(ODIT, "a");
if (log_file == NULL) return;
fprintf(log_file, "\nInventory at %02d.%02d.%02d - %02d:%02d:%02d\n", tm_mday, tm_mon, tm_year, tm_hour, tm_min,tm_sec);
f_print_inventory_int(log_file);
fclose(log_file);
}
int main(){
time_t T = time(NULL);
struct tm tm = *localtime(&T);
bool loop = true;
while (loop){
print_avail_opt();
printf("Enter op:");
int op = 0; scanf("%d", &op);
switch (op){
case 1:
read_from_file();
break;
case 2:
write_in_file(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
break;
case 3:
print_inventory_int();
break;
case 4:
print_inventory_string();
break;
case 5:
loop = false;
break;
default:
printf("Not correct option\n");
break;
}
}
return 0;
}

C problem with saving structure to text file and downloading it back to stdout

Hey I have a problem with my code project where I try to create a project that keeps up wit Olympic medals. I have a problem of creating a text file that contains the structure and is named by user. I also have a problem to download the structure.
PROBLEM: I have a problem to make a text file named by user that contains the structure and then download it back to stdout. I don't know how to fix my functions to do this correctly. Now my function save_file can't even produce the file.
Example if the input:
A Canada
A USA
M USA 2 1 1
M Canada 0 0 1
M USA 1 3 1
M USA -1 0 0
L
W medals
Q
I have defined my structure this way:
typedef struct Olympia
{
char* country;
int gold;
int silver;
int bronze;
}Olympia;
Then I have a function that adds country
int add_country(struct Olympia* data, char* str, int i)
{
if (str[0] == '\0') //checking that input is correct
{
printf("Error! Try again!\n");
}
else
{
data[i].country = malloc(strlen(str) + 2); //allocating memory for country name
strcpy(data[i].country, str); //adding country to database
data[i].gold = 0; //setting medals to zero
data[i].silver = 0;
data[i].bronze = 0;
i++;
}
return i;
}
Next I add medals to the each country
int update_medals(struct Olympia* data, char* str, int add_gold, int add_silver, int add_bronze, int i)
{
int a = 0;
int b = 0;
if (str[0] == '\0') //checking that input is correct
{
printf("Error! Try again!");
}
else
{
while (a < i)
{
if (strcmp(data[a].country, str) == 0) //adding medals to right country
{
data[a].gold = data[a].gold + add_gold;
data[a].silver = data[a].silver + add_silver;
data[a].bronze = data[a].bronze + add_bronze;
b++;
}
a++;
}
if (b == 0) //and if the country didn't participate to the olympics
{
printf("This country isn't in the Olympics! Try Again!\n");
}
}
}
Next there is print function
int print_data(struct Olympia* data, int i)
{
for (int a = 0; a < i; a++)
{
printf("%s %d %d %d\n", data[a].country, data[a].gold, data[a].silver, data[a].bronze);
}
}
And then there are the two function that doesn't work. What should I do?
Olympia *save_file(Olympia* data, const char* filename, int i)
{
if (strlen(filename) > 100)
{
printf("Filename is too long: Maxium lenght for filename is 100 characters");
return data;
}
char name[100];
int ret = sscanf(filename, "W %s", name);
if (ret != 1)
{
printf("Error! Try again!");
return data;
}
FILE* file = fopen(name, "w");
if (!file)
{
printf("Error saving file! Try again");
return data;
}
int a = 0;
while (data[a].country[0] != 0)
{
fprintf(file, "%s %d %d %d\n", data[a].country, data[a].gold, data[a].silver, data[a].bronze);
a++;
}
fclose(file);
return 0;
}
int load_file(struct Olympia* data, char* filename, int i)
{
int a = 0;
FILE* file = fopen(filename, "r");
if (!file)
{
printf("Error opening file! Try again");
}
struct Olympia* arr = malloc(sizeof(Olympia));
while (fscanf(file, "%s %d %d %d", data[a].country, data[a].gold, data[a].silver, data[a].bronze))
{
i++;
a++;
arr = realloc(arr, sizeof(Olympia) * (i + 2));
}
arr[a].country[0] = 0;
fclose(file);
return arr;
}
And the main function
int main(void)
{
char command;
int gold = 0;
int silver = 0;
int bronze = 0;
int i = 0;
char* line = (char*)malloc((100) * sizeof(char)); //allocating memory for one stdin line
char* countryname = (char*)malloc(20 * sizeof(char)); // allocating memory for country name
char* filename = (char*)malloc(100 * sizeof(char));
struct Olympia* countrydata = malloc(sizeof(struct Olympia) * 1); //allocating memory for structure
line = fgets(line, 100, stdin);
while(1)
{
sscanf(line, "%c %s %d %d %d", &command, countryname, &gold, &silver, &bronze);
switch (command)
{
case 'A':
i = add_country(countrydata, countryname, i);
countrydata = realloc(countrydata, sizeof(struct Olympia) * (i + 1));
break;
case 'M':
update_medals(countrydata, countryname, gold, silver, bronze, i);
break;
case 'L':
print_data(countrydata, i);
break;
case 'W':
save_file(countrydata, filename, i);
break;
case 'O':
i = load_file(countrydata,filename, i);
break;
case 'Q':
free(line);
free(countryname);
free(countrydata);
return(EXIT_SUCCESS);
}
line = fgets(line, 100, stdin);
if (line == NULL)
{
free(line);
free(countryname);
free(countrydata);
return(EXIT_SUCCESS);
}
}
}
You call save_file(countrydata, filename, i); without having set filename. Change to save_file(countrydata, line, i); since for whatever reason you expect the command character W to precede the name.
Then in save_file() the condition in while (data[a].country[0] != 0) is unusable, since the data element after the last one is not initialized. Use while (a < i) instead.

Program doesnt write to file and crashes when loading

So i need to write and read to and from a binary file, but cant seem to do it, and when using readFromFile, the program crashes. I need help write to binary file, and then reading from it and resuming my work later after turning off the program.I have no idea what i am doing wrong, and i have googled for a long time now, but with no results. Here is the code of my program:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
char *subjName;
char *lectName;
char *lectSurname;
int credits;
int num_students;
}Subject;
typedef struct{
Subject **subjs;
int num_subjs;
}Subjects;
int numOfSubjs=0;
void listInput();
void listEdit();
void listDelete();
void listPrint();
int userChoice(int select);
int enterNumber(char *name);
void saveToFile(Subjects *subjects);
void readFromFile(Subjects *subjects);
int main() {
Subjects *subjects = malloc(sizeof(Subjects));
subjects->num_subjs = 0;
subjects->subjs = NULL;
readFromFile(subjects);
int r=1;
while(r!=0){
int select=userChoice(select);
switch(select){
case 1:
listPrint(subjects);
break;
case 2:
listInput(&subjects);
break;
case 3:
listDelete(subjects);
break;
case 4:
listEdit(subjects);
break;
case 0:
r=0;
break;
}
}
saveToFile(subjects);
return 0;
}
int userChoice(int select){ // menu options
int choice,input=0;
printf("(1). View all the data\n");
printf("(2). Enter new data\n");
printf("(3). Delete data\n");
printf("(4). Edit data\n");
printf("(0). Exit\n");
printf("-----------------------------\n");
while(input!=1){
choice = enterNumber("menu");
if(choice>4 || choice<0){
printf("Invalid input \n");
}
else
input = 1;
}
return choice;
}
void listPrint(Subjects *subjects){ // print data
int i;
for(i=0; i< numOfSubjs; i++){
printf("%d, %s, %s, %s, %d, %d\n",i+1, subjects->subjs[i]->subjName, subjects->subjs[i]->lectName, subjects->subjs[i]->lectSurname, subjects->subjs[i]->credits, subjects->subjs[i]->num_students);
}
printf("Number of entries: %d \n", numOfSubjs);
}
char *getln() //dynamically allocate input string
{
char *line = NULL, *tmp = NULL;
size_t size = 0, index = 0;
int ch = 1;
while (ch) {
ch = getc(stdin);
if (ch == '\n')
ch = 0;
if (size <= index) {
size += 1;
tmp = realloc(line, size);
if (!tmp) {
free(line);
line = NULL;
break;
}
line = tmp;
}
line[index++] = ch;
}
return line;
}
void saveToFile(Subjects *subjects){
FILE *data;
data = fopen("data.bin","wb");
printf("%s", subjects->subjs[0]);
for(int i=0; i<numOfSubjs; i++){
fwrite(&subjects->subjs[i],sizeof(Subject*),1,data);
}
fclose(data);
}
void readFromFile(Subjects *subjects){
FILE *data;
int i=0;
data = fopen("data.bin","rb");
while(!feof(data))
{
fread(&subjects->subjs[i],sizeof(Subject*),1,data);
i++;
}
fclose(data);
}
int isText(char *str,char *name){ // check if is text
for(int i = 0; i < strlen(str);i++){
if((str[i]<'A' || str[i]>'z') && str[i]!=' '){
printf("Error, %s must be a text \n",name);
return 0;
}
}
return 1;
}
int enterNumber(char *name){ // enter number and check if is number
int input=0, crash=0, num=0;
while(input!=1)
{
crash=0;
printf("Enter the number of %s\n", name);
scanf("%d", &num);
while(getchar()!='\n')
{
crash++;
}
if(crash>0 || num<0)
printf("Error, enter a not negative number of %s\n", name);
else if(crash==0)
input=1;
}
return num;
}
void listInput(Subjects **p_subjects){ // input new data
Subject *new_subj = malloc(sizeof(Subject));
new_subj->subjName = NULL;
new_subj->lectName = NULL;
new_subj->lectSurname = NULL;
new_subj->credits = 0;
new_subj->num_students = 0;
do{
printf("Enter the name of the subject \n");
new_subj->subjName = getln();
}while(!isText(new_subj->subjName,"Subject name"));
do{
printf("Enter the name of the lecturer \n");
new_subj->lectName = getln();
new_subj->lectName[0] &= '_';
}while(!isText(new_subj->lectName,"Lecturer's name"));
do{
printf("Enter the surname of the lecturer\n");
new_subj->lectSurname = getln();
new_subj->lectSurname[0] &= '_'; //Convert to uppercase if lowercase
}while(!isText(new_subj->lectSurname,"Lecturer's name"));
new_subj->credits = enterNumber("credits");
new_subj->num_students = enterNumber("students");
(*p_subjects)->subjs = realloc((*p_subjects)->subjs,sizeof(Subject*)*(++(*p_subjects)->num_subjs));
(*p_subjects)->subjs[(*p_subjects)->num_subjs-1] = new_subj;
numOfSubjs++;
printf("Added a new entry.\n\n");
}
void listDelete(Subjects *subjects){ // delete entries
int del;
if(numOfSubjs==0)
printf("Number of entries is 0, can't delete anything\n");
else{
printf("Enter 0 to exit. Number of subjects : %d \n", numOfSubjs);
while(1){
del = enterNumber("entry which you would like to delete");
if(del<=numOfSubjs && del>0){
for(int i = del-1; i<numOfSubjs-1; i++){
subjects->subjs[i]=subjects->subjs[i+1];
subjects->subjs = realloc(subjects->subjs,sizeof(Subject*)*(--subjects->num_subjs));
}
numOfSubjs--;
break;
}
if(del>numOfSubjs)
printf("Error, input a number between 1 and %d (or enter 0 to exit)\n", numOfSubjs);
else
break;
}
}
}
void listEdit(Subjects *subjects){ // edit entries
int choice=0, editEntry=0, editSubj=0;
if(numOfSubjs == 0)
printf("Number of entries is 0, can't edit anthing\n");
else{
while(1){
printf("Number of entry must be between 1 and %d \n", numOfSubjs);
choice = enterNumber("entry you would like to edit.");
if(choice>0 && choice<=numOfSubjs){
while(1){
editEntry = enterNumber("what would you like to edit\n 1 - Subject name\n 2 - Lecturer's name\n 3 - Lecturer's surname\n 4 - Number of credits\n 5 - Number of students");
if(editEntry>0 && editEntry <=5){
switch(editEntry){
case 1:
do{
printf("Enter the name of the subject \n");
subjects->subjs[choice-1]->subjName = getln();
}while(!isText(subjects->subjs[choice-1]->subjName,"Subject name"));
break;
case 2:
do{
printf("Enter Lecturer's name \n");
subjects->subjs[choice-1]->lectName = getln();
}while(!isText(subjects->subjs[choice-1]->lectName,"Lecturer's name"));
break;
case 3:
do{
printf("Enter Lecturer's surname \n");
subjects->subjs[choice-1]->lectSurname = getln();
}while(!isText(subjects->subjs[choice-1]->lectSurname,"Lecturer's surname"));
break;
case 4:
subjects->subjs[choice-1]->credits = enterNumber("credits");
break;
case 5:
subjects->subjs[choice-1]->num_students = enterNumber("students");
break;
}
}
break;
}
}
break;
}
}
}
&subjects->subjs[i], This is Undefined behavior. Accessing garbage value. You need to properly initialize it proper memory address. You ddin't do it anywhere.
(*subjects).subjs or subjects->subjs -> This is not pointing anywhere. It is NULL.
Also here you don't need the double pointer. A single pointer would do the thing you want to do.
typedef struct{
Subject *subjs;
int num_subjs;
}Subjects;
For single pointer this would be like
Subjects *subjects = malloc(sizeof(Subjects));
subjects->num_subjs = 10;
subjects->subjs = malloc(subjects->num_subjs * sizeof Subject);
subjects->subjs[0].subjName = malloc(40);
Each of the malloc should be checked with it's return Value. If it's NULL then it would be error to proceed further or access it.
And free() it accordingly when you are done working with it.
Some basic things:-
typedef struct{
Subject *subjs;
int num_subjs;
}Subjects;
Now let's look a bit in the code.
Op asked why OP should initialize and isn;t subjects->num_subjs = 0;
subjects->subjs = NULL; not enough?
A pointer is a variable that is supposed to hold address. here Subject* will hold the address of the variables of type Subject.
Now here initially you initialized it.
You have allocated a memory and assigned it's address to the Subject* variable subjects.
Now let's see what else you do.
subjects->num_subjs = 0;
subjects->subjs = NULL;
You initialized it. And then you try to access it(subjects->subjs[i]). Can you tell me where it points to? (subject->subjs)?
Answer is nope. It is pointing to nowhere. It contains NULL value now. Don't you think you should tell it how many subject you want to hold and allocate accordingly? Yes you should and that's what I did precisely in the example shown.
Whenever you have a pointer variable ask yourself what it contains - and if the value is something you know about, not some random garbage value.

while loop terminating before it is supposed to C

This program is supposed to copy an existing txt file to a new txt code file. However is isn't working right. For some reason it always stops after the third iteration.
Suggestions?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char fileNameIn[100];
char fileNameOut[100];
FILE *ptrIn = NULL; //____ File Pointers
FILE *ptrOut = NULL;
char str[1000]; //this is used at fgets and it obtains sentences
/*_________________Counter variables)*/
char *token;
int ctr = 0;
int ndel = -1;
char wordA[10];
char sentence[101];
char del[10] = " !-,.";
;
int temp = 0;
printf("Enter the input filename: \n");
// gets(fileNameIn);
scanf("%s", fileNameIn);
//printf("You entered: %s\n",fileNameIn);
printf("Enter the output filename: \n");
scanf("%s", fileNameOut);
ptrIn = fopen(fileNameIn, "r"); // r is to read
ptrOut = fopen(fileNameOut, "w"); //w is to write on file
if (ptrIn == NULL || ptrOut == NULL) {
printf("Unable to open file\n");
exit(1);
}
//while(fgets (str,sizeof(str), ptrIn) )
while (fgets(str, sizeof(str), ptrIn)) { // while we are not at the end of the file
puts(str);
// if(temp==0)
// {
token = strtok(str, del);
temp = -1;
printf(
"Enter position of word to delete (Start counting at 0). Enter -1 to skip deletion:\n");
scanf("%d", &ndel);
printf("You selected: %d\n", ndel);
while (token != NULL) // while loop inside a sentence
{
if (ctr != ndel) {
strcpy(wordA, token);
}
token = strtok(NULL, del);
if (ctr != ndel) {
strcat(sentence, wordA);
strcat(sentence, " ");
printf("halfway?");
}
ctr++;
} // endof sentence loop
fprintf(ptrOut, "%s", sentence);
printf("the sentence is now:\n%s", sentence);
printf("___________________________________________");
printf("\n");
strcpy(sentence, "");
ctr = 0;
ndel = -1;
} //end of while loop eof
printf("Finish the main: ");
fflush(ptrOut);
fclose(ptrIn);
fclose(ptrOut);
return EXIT_SUCCESS;
}
This is an example of the existing file:
test.txt:
hello my name is john.
this is a test.
after the third line the while
loop stops
this does the get copied
You strcat() to senetence wihtout initializing it, strcat() will search for the terminating nul byte of it's first argument and start copying characters from it's second argument start from that position, so a simple
sentence[0] = '\0';
right after the outer while loop will fix it, but your code needs reformatting and you should make it safer by checking every single potential undefined behavior cause.
This is the code and it now works correctly
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char fileNameIn[100] = {0};
char fileNameOut[100] = {0};
FILE *ptrIn = NULL;
FILE *ptrOut = NULL;
char str[1024] = {0};
char *token = NULL;
int ctr = 0;
int ndel = -1;
char wordA[1024] = {0};
char sentence[1024] = {0};
char del[] = " !-,.";
int temp = 0;
printf("Enter the input filename > ");
fflush(stdout);
scanf("%99s", fileNameIn);
printf("Enter the output filename > ");
fflush(stdout);
scanf("%99s", fileNameOut);
ptrIn = fopen(fileNameIn, "r"); // r is to read
if (ptrIn == NULL)
{
printf("Unable to open file %s\n", fileNameIn);
return -1;
}
ptrOut = fopen(fileNameOut, "w"); // w is to write on file
if (ptrOut == NULL)
{
fclose(ptrIn);
printf("Unable to open file %s\n", fileNameOut);
return -1;
}
while (fgets(str, sizeof(str), ptrIn)) // while we are not at the end of the file
{
puts(str);
token = strtok(str, del);
temp = -1;
printf("Enter position of word to delete (Start counting at 0) `-1 to skip deletion' > ");
if (scanf("%d", &ndel) != 1)
continue;
printf("You selected: %d\n", ndel);
sentence[0] = '\0';
while (token != NULL)
{
if (ctr != ndel)
strcpy(wordA, token);
token = strtok(NULL, del);
if (ctr != ndel)
{
strcat(sentence, wordA);
strcat(sentence, " ");
}
ctr++;
}
fprintf(ptrOut, "%s", sentence);
printf("the sentence is now:\n%s", sentence);
printf("\n");
ctr = 0;
ndel = -1;
}
printf("Finish the main: ");
fflush(ptrOut);
fclose(ptrIn);
fclose(ptrOut);
return EXIT_SUCCESS;
}

Simple C exercise. Last position get overwritten

it is the all day that I edit my code, but can't find the reason why the last position of my array get overwritten!!
#include <stdio.h>
#include <math.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
typedef struct Person{
char *name;
char *surname;
char *address;
char *number;
} Person;
char * getString(void);
int main(void) {
struct Person *rub = NULL, *ttmp = NULL;
int idx=0,i,j,k;
char c;
char *tmp = NULL;
do{
printf("*******************************\ni - Insert new\n");
printf("n - Find by name\n");
printf("c - Find by surname\n");
printf("e - Delete\n");
printf("p - Print list\n");
printf("0 - Exit\n*******************************\n");
c = getchar();
printf("%d\n",c);
getchar();
switch(c){
case 'i':
ttmp = (struct Person *) realloc(rub, (idx+1)*sizeof(Person));
if(ttmp == NULL){
printf("Cannot allocate more memory.\n");
exit(1);
}
else
rub = ttmp;
printf("Nome: ");
tmp = getString();
rub[idx].name = (char *) malloc(strlen(tmp));
rub[idx].name = tmp;
//printf("Surname: "); //commented in order to test faster
//tmp = getString();
rub[idx].surname = (char *) malloc(strlen(tmp));
rub[idx].surname = tmp;
//printf("Address: ");
//tmp = getString();
rub[idx].address = (char *) malloc(strlen(tmp));
rub[idx].address = tmp;
//printf("Number: ");
//tmp = getString();
rub[idx].number = (char *) malloc(strlen(tmp));
rub[idx].number = tmp;
idx++;
for(k=0;k<idx;k++){
printf("%d) %s %s\n%s\n%s\n-------------------\n", k+1, rub[k].name,rub[k].surname,rub[k].address,rub[k].number);
}
break;
case 'n':
printf("What name are you looking for? ");
scanf("%s",tmp);
for(k=0;k<idx;k++){
if(strcmp(rub[k].name,tmp) == 0){
printf("%s\n%s\n%s\n%s\n", rub[k].name,rub[k].surname,rub[k].address,rub[k].number);
}
}
break;
case 'c':
printf("What surname are you looking for? ");
scanf("%s",tmp);
for(k=0;k<idx;k++){
if(strcmp(rub[k].surname,tmp) == 0){
printf("%s\n%s\n%s\n%s\n", rub[k].name,rub[k].surname,rub[k].address,rub[k].number);
}
}
break;
case 'e':
printf("Select number to delete record:\n ");
for(k=0;k<idx;k++){
printf("%d) %s %s\n", k+1, rub[k].name,rub[k].surname);
}
scanf("%d",&j);
ttmp = NULL;
for(k=0,i=0;k<idx;k++){
if(k+1 != j){
ttmp = (struct Person *) realloc(ttmp, (i+1)*sizeof(Person));
ttmp[i].name = (char *) malloc(strlen(rub[k].name));
ttmp[i].surname = (char *) malloc(strlen(rub[k].surname));
ttmp[i].address = (char *) malloc(strlen(rub[k].address));
ttmp[i].number = (char *) malloc(strlen(rub[k].number));
ttmp[i].name = rub[k].name;
ttmp[i].surname = rub[k].surname;
ttmp[i].address = rub[k].address;
ttmp[i].number = rub[k].number;
i++;
}
}
--idx;
rub = (struct Person *) realloc(ttmp, (idx)*sizeof(Person));
for(k=0;k<idx;k++){
printf("%d/%d) %s %s\n%s\n%s\n-------------------\n", k,idx, rub[k].name,rub[k].surname,rub[k].address,rub[k].number);
}
break;
case 'p':
for(k=0;k<idx;k++){
printf("%d) %s %s\n%s\n%s\n-------------------\n", k+1, rub[k].name,rub[k].surname,rub[k].address,rub[k].number);
}
break;
case '0':
return 0;
break;
}
fseek(stdin,0,SEEK_END);
}
while(c != 0);
return 0;
}
char * getString(void){
char *stringa = NULL, c;
int i=0;
stringa = malloc(sizeof(char));
while((c=getchar()) != '\n'){
stringa = (char *) realloc(stringa, (i+1)*sizeof(char));
stringa[i++] = c;
}
stringa[i] = '\0';
return stringa;
}
Here is my input (please enter the same input, and tell me if you get the same error). I will use some stupid and random words for this example:
i
asd
i
qwe
i
zxc
p
n
asd
p
Here is the output of my last 'p' command:
1) asd asd
asd
asd
-------------------
2) qwe qwe
qwe
qwe
-------------------
3) asd asd
asd
asd
-------------------
Why the last position of the array became the same as the first??
Any other advice or suggestion for the code will be welcome!!
thanks
Why the last position of the array became the same as the first?
case 'n':
printf("What name are you looking for? ");
scanf("%s",tmp);
tmp are reused. (case 'c': too)
change to
E.g
case 'n':
printf("What name are you looking for? ");
tmp=getString();
for(k=0;k<idx;k++){
if(strcmp(rub[k].name,tmp) == 0){
printf("%s\n%s\n%s\n%s\n", rub[k].name,rub[k].surname,rub[k].address,rub[k].number);
}
}
free(tmp);
break;
and
rub[idx].name = (char *) malloc(strlen(tmp));
rub[idx].name = tmp;
//As well as in other like
memory leak.
only
rub[idx].name = tmp;//by getString()
I din't read the whole code but found this code that seems incorrect:
stringa = malloc(sizeof(char));
while((c=getchar()) != '\n'){
stringa = (char *) realloc(stringa, sizeof(char));
You are realloc-ing always one byte, the string nevers grows up!
You should realloc depending on the variable i

Resources