Related
I need to allocate memory using malloc or calloc, for a large file that looks like this:
2357 VKLYKK
7947 1WTFWZ
3102 F2IXK3
2963 EXMW55
2865 50CJES
2510 8PC1AI
There are around 10K of lines in that .txt file. How can I allocate the required memory?
What is the program supposed to do? The program has to read the whole .txt file. Sort it by the first number and send output to out.txt. But since the the input of the file is huge it won't let me.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#pragma warning(disable : 4996)
typedef struct {
int number;
char order[10];
} Data;
int sorting(const void *a, const void *b)
{
Data *dataA = (Data *)a;
Data *dataB = (Data *)b;
// return (dataA->number - dataB->number); // Ascending order
return (dataB->number - dataA->number); // Descending order
}
int main()
{
FILE *fp;
FILE *f = fopen("out.txt", "w");
Data data[20];
char *line[150]
int i = 0;
char file_name[10] = "";
printf("enter file name: ");
scanf("%s", &file_name);
fp = fopen(file_name, "r");
if (fp == NULL)
{
printf("\n%s\" File not found!", file_name);
exit(1);
}
while (1)
{
if (fgets(line, 150, fp) == NULL)
break;
char *pch;
pch = strtok(line, " ");
data[i].number = atoi(pch);
pch = strtok(NULL, " ");
strcpy(data[i].order, pch);
i++;
}
printf("#################\n");
printf("number\torder\n");
for (int k = 0; k < 10; k++)
{
printf("%d\t%s", data[k].number, data[k].order);
}
qsort(data, 10, sizeof(Data), sorting);
printf("\n#################\n");
printf("number\torder\n");
for (int k = 0; k < 10; k++)
{
printf("%d\t%s", data[k].number, data[k].order);
fprintf(f, "%d\t%s", data[k].number, data[k].order);
}
fclose(fp);
fclose(f);
return 0;
}
If your file contains 10,000 lines or so, your while loop will quickly overrun your data array (which you declared with only 20 elements). If the number of lines is not known in advance, the best way to do this is with a growing array. Start by initialing data (and new dataSize and dataCount variables) as follows:
int dataSize = 0;
int dataCount = 0;
Data *data = NULL;
Then as you use up the space in the array, when it reaches dataSize entries you will have to grow your array. Something like this:
while (1) {
if (dataCount >= dataSize) {
Data *new;
dataSize += 1000;
new = realloc(data,dataSize * sizeof *data);
if (new == NULL) {
perror("realloc");
free(data);
return 2;
}
data = new;
}
int cnt = fscanf(fp,"%d %9s", &data[dataCount].number, data[dataCount].order);
if (cnt == EOF)
break;
if (cnt != 2) {
printf("Error reading data\n");
return 1;
}
dataCount++;
}
When the while loop finishes (if there were no errors), the data array will contain all of the data, and dataCount will be the total number of data items found.
Note that I used fscanf instead of fgets, as this eliminates the need for intermediate step like calls to atoi and strcpy. I also put in some simple error checking. I chose 1000 as the growth increment, though you can change that. But too small and it fragments the heap more rapidly, and too big requires larger amounts of memory too quickly.
this line
char* line[150];
creates an array of 150 char pointers, this is not what you want if you are reading one line like this
if (fgets(line, 150, fp) == NULL) break;
I suspect you wanted one line of 150 chars
so do
char line[150];
You can use qsort to sort the array of lines, but that may not be the best approach. It may be more effective to insert the lines into a data structure that can be easily traversed in order. Although this simple minded solution is very much less than ideal, here's a simple-minded example of inserting into a tree. This sorts the lines lexicographically; modifying it to sort numerically based on the line is a good exercise.
/* Build an (unbalanced) binary search tree of lines in input. */
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void * xrealloc(void *buf, size_t num, size_t siz, void *end);
FILE * xfopen(const char *path, const char *mode);
struct entry {
const char *line;
struct entry *node[2];
};
static struct entry *
new_node(const char *line)
{
struct entry *e = calloc(1, sizeof *e);
if( e == NULL ){
perror("calloc");
exit(EXIT_FAILURE);
}
e->line = line;
return e;
}
/*
* Note that this tree needs to be rebalanced. In a real
* project, we would use existing libraries.
*/
static struct entry *
lookup(struct entry **lines, const char *line)
{
struct entry *t = *lines;
if( t ){
int cmp = strcmp(line, t->line);
return lookup(&t->node[cmp > 0], line);
} else {
return *lines = new_node(line);
}
}
/* In-order descent of the tree, printing one line per entry */
static void
print_table(const struct entry *t)
{
if( t ){
print_table(t->node[0]);
printf("%s", t->line);
print_table(t->node[1]);
}
}
static void *
xrealloc(void *buf, size_t num, size_t siz, void *endvp)
{
char **endp = endvp;
ptrdiff_t offset = endp && *endp ? *endp - (char *)buf : 0;
buf = realloc(buf, num * siz);
if( buf == NULL ){
perror("realloc");
exit(EXIT_FAILURE);
}
if( endp != NULL ){
*endp = buf + offset;
}
return buf;
}
int
main(int argc, char **argv)
{
FILE *ifp = argc > 1 ? xfopen(argv[1], "r") : stdin;
struct entry *lines = NULL;
char *line = NULL;
size_t cap = 0;
while( getline(&line, &cap, ifp) > 0 ){
(void) lookup(&lines, line);
line = NULL;
}
print_table(lines);
}
FILE *
xfopen(const char *path, const char *mode)
{
FILE *fp = path[0] != '-' || path[1] != '\0' ? fopen(path, mode) :
*mode == 'r' ? stdin : stdout;
if( fp == NULL ){
perror(path);
exit(EXIT_FAILURE);
}
return fp;
}
I am trying to read through a text file line by line and with each line I am trying to assign each word to a list. Do something with that list. After I do this, I am going go to the next line.
#define BUFSIZE 1000
int main(int argc, char* argv[]){
char buf[BUFSIZE];
FILE* fp;
fp=fopen(argv[1], "r"); //open the file
while(fgets(buf, BUFSIZE-1, fp)!= NULL){ //loop through each line of the file
char *myargs[5];
myargs[0]= ?? //some way to set the first word to this
myargs[4]= ?? //there will only be 4 words
myargs[5]=NULL;
//do something with myargs
}
}
You can use strtok to separate a line of text into tokens. Assuming each word is separated by a space, you can do the following:
while(fgets(buf, BUFSIZE-1, fp)!= NULL){ //loop through each line of the file
char *myargs[4] = { NULL };
char *p;
int i, count = 0;
p = strtok(buf, " ");
while (p && (count < 4)) {
myargs[count++] = strdup(p);
p = strtok(NULL, " ");
}
// operate on myargs
for (i = 0; i < count; i++) {
free(myargs[i]);
}
}
I want to change my input.txt file to an integer array.
But sadly I keep missing one integer whenever new-line-character is met.
Following is my main()
int main(int args, char* argv[]) {
int *val;
char *STRING = readFile();
val = convert(STRING);
return 0;
}
Following is my file input function
char *readFile() {
int count;
FILE *fp;
fp = fopen("input.txt", "r");
if(fp==NULL) printf("File is NULL!n");
char* STRING;
char oneLine[255];
STRING = (char*)malloc(255);
assert(STRING!=NULL);
while(1){
fgets(oneLine, 255, fp);
count += strlen(oneLine);
STRING = (char*)realloc(STRING, count+1);
strcat(STRING, oneLine);
if(feof(fp)) break;
}
fclose(fp);
return STRING;
}
Following is my integer array function
int *convert(char *STRING){
int *intarr;
intarr = (int*)malloc(sizeof(int)*16);
int a=0;
char *ptr = strtok(STRING, " ");
while (ptr != NULL){
intarr[a] = atoi(ptr);
printf("number = %s\tindex = %d\n", ptr, a);
a++;
ptr = strtok(NULL, " ");
}
return intarr;
}
There are many issues.
This is a corrected version of your program, all comments are mine. Minimal error checking is done for brevity. intarr = malloc(sizeof(int) * 16); will be a problem if there are more than 16 numbers in the file, this should be handled somehow, for example by growing intarr with realloc, similar to what you're doing in readFile.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
char *readFile() {
FILE *fp;
fp = fopen("input.txt", "r");
if (fp == NULL)
{
printf("File is NULL!n");
return NULL; // abort if file could not be opened
}
#define MAXLINELENGTH 255 // define a constant rather than hardcoding "255" at several places
char* STRING;
char oneLine[MAXLINELENGTH];
STRING = malloc(MAXLINELENGTH);
int count = MAXLINELENGTH; // count mus be initialized and better declare it here
assert(STRING != NULL);
STRING[0] = 0; // memory pointed by STRING must be initialized
while (fgets(oneLine, MAXLINELENGTH, fp) != NULL) // correct usage of fgets
{
count += strlen(oneLine);
STRING = realloc(STRING, count + 1);
strcat(STRING, oneLine);
}
fclose(fp);
return STRING;
}
int *convert(char *STRING, int *nbofvalues) { // nbofvalues for returning the number of values
int *intarr;
intarr = malloc(sizeof(int) * 16);
int a = 0;
char *ptr = strtok(STRING, " \n"); // strings may be separated by '\n', or ' '
*nbofvalues = 0;
while (ptr != NULL) {
intarr[a] = atoi(ptr);
printf("number = %s\tindex = %d\n", ptr, a);
a++;
ptr = strtok(NULL, " \n"); // strings are separated by '\n' or ' '
} // read the fgets documentation which
// terminates read strings by \n
*nbofvalues = a; // return number of values
return intarr;
}
int main(int args, char* argv[]) {
int *val;
char *STRING = readFile();
if (STRING == NULL)
{
printf("readFile() problem\n"); // abort if file could not be read
return 1;
}
int nbvalues;
val = convert(STRING, &nbvalues); // nbvalues contains the number of values
// print numbers
for (int i = 0; i < nbvalues; i++)
{
printf("%d: %d\n", i, val[i]);
}
free(val); // free memory
free(STRING); // free memory
return 0;
}
I'm not sure what your requirement is, but this can be simplified a lot because there is no need to read the file into memory and then convert the strings into number. You could convert the numbers on the fly as you read them. And as already mentioned in a comment, calling realloc for each line is inefficient. There is room for more improvements.
I'm new at programming, and I need help in my C project. I have to search for a city, confirm it exists in the first file (city.csv), and take its id from there. Then I have to match that id with the corresponding one in the second file (meteo.csv), and then edit its weather information, that is in that second file. However, I don't know how I can take the city id from the first file, and then how to edit the second file after obtaining all the new weather informations. Here is the code:
void addInfo() {
FILE * fp;
char id_city[100];
char city[100];
char humidity[100];
char temp_max[100];
char temp_min[100];
char pressure[100];
char date[100];
printf("Name of the city: ");
scanf("%s", city);
// I think it's here that I have to write the code for take the city's id from the first file
if (id_city != NULL) {
printf("Maximun temperature: ");
scanf("%s", temp_max);
printf("Minimun temperature: ");
scanf("%s", temp_min);
printf("Humidity: ");
scanf("%s", humidity);
printf("Pressure: ");
scanf("%s", pressure);
printf("Date, in the format YYYY-MM-DD: ");
scanf("%s", date);
fp = fopen ("meteo.csv", "a");
fprintf(fp, "%s, %s, %s, %s, %s \n", temp_max, temp_min, humidity, pressure, date); //I think there's something wrong here too...
fclose(fp);
printf("Information edited successfully");
}
The file city.csv has 152 lines and 4 columns:
(id_city,city,county,district)
such as
(56,Lisbon,Lisbon,Lisbon)
The file meteo.csv has 152 lines and 7 columns:
(id_meteo_city,id_city,temp_max,temp_min,humidity,pressure,date)
such as
(56,56,14,5,62,1025,2018-02-12)
The first thing I would do is encapsulate the data in a struct, that makes it
easier to map a line of a CSV file into an object representing a line.
If both files city.csv and meteo.csv have different columns, I'd create a
different struct for each file. If both files have the same columns, you could
use the struct. I assume that both files are different and that city has the
format meteo_id,city_id,name.
typedef struct city_t {
int meteo_id;
int city_id;
char name[100]; // no city should have
// longer than 100 chars
} city_t;
typedef struct meteo_t {
int meteo_id;
int city_id;
int tempt_max;
int tempt_mix;
double humidity;
double preassure;
char date[11];
} meteo_t;
Let's assume that both files are well formatted, otherwise you would have to
write code that checks for errors and handles them, that would be the next step
in the exercise, so I'm going to write only the basic version with basic error
recognition.
#include <stdio.h>
#include <string.h>
#include <errno.h>
// takes 2 params, the filename and a pointer
// to size_t where the number of cities is stored
city_t *read_cities(const char *filename, size_t *len)
{
if(filename == NULL || len == NULL)
return NULL;
FILE *fp = fopen(filename, "r");
if(fp == NULL)
{
fprintf(stderr, "Could not open %s: %s\n", filename, strerror(errno));
return NULL;
}
city_t *arr = NULL, *tmp;
*len = 0;
// assuming that no line will be longer than 1023 chars long
char line[1024];
while(fgets(line, sizeof line, fp))
{
tmp = realloc(arr, (*len + 1) * sizeof *arr);
if(tmp == NULL)
{
fprintf(stderr, "could not parse the whole file %s\n", filename);
// returning all parsed cities so far
if(*len == 0)
{
free(arr);
arr = NULL;
}
return arr;
}
arr = tmp;
// %99[^\n] is to read up to 99 characters until the end of the line
if(sscanf(line, "%d,%d,%99[^\n]", &(arr[*len].meteo_id),
&(arr[*len].city_id), arr[*len].name) != 3)
{
fprintf(stderr, "Invalid line format (skipping line):\n%s\n", line);
// skip this line, and decrement *len
(*len)--;
continue;
}
// incrementing only when parsing of line was OK
(*len)++;
}
fclose(fp);
// file is empty or
// all lines have wrong format
if(*len == 0)
{
free(arr);
arr = NULL;
}
return arr;
}
void print_cities(city_t *cities, size_t len, FILE *fp)
{
if(cities == NULL || fp == NULL)
return;
for(size_t i = 0; i < len; ++i)
fprintf(fp, "%d,%d,%s\n", cities[i].meteo_id, cities[i].citiy_id,
cities[i].name);
}
Now I've written the read and write functions for the file citiy.csv assuming the
format meteo_id;city_id;name. The print_cities allows you to print the CSV
content on the screen (passing stdout as the last argument) or to a file
(passing a FILE object as the last argument).
You can use these functions as templates for reading and writing meteo.csv, the
idea is the same.
You can use these function as follows:
int main(void)
{
size_t cities_len;
city_t *cities = read_cities("city.csv", &cities_len);
// error
if(cities == NULL)
return 1;
do_something_with_cities(cities, cities_len);
// update csv
FILE *fp = fopen("city.csv", "w");
if(fp == NULL)
{
fprintf(stderr, "Could not open city.csv for reading: %s\n",
strerror(errno));
free(cities);
return 1;
}
print_cities(cities, cities_len, fp);
fclose(fp);
free(cities);
return 0;
}
Now for your exercise: write a similar function that parses meteo.csv (using
my function as a template shouldn't be that difficult) and parse both files. Now
that you've got them in memory, it's easy to manipulate the data (insert,
update, delete). Then write the files like I did in the example and that's it.
One last hint: how to search for a city:
// returns the index in the array or -1 on error or when not found
int search_for_city_by_name(city_t *cities, size_t len, const char *name)
{
if(cities == NULL || name == NULL)
return -1;
for(size_t i = 0; i < len; ++i)
if(strcmp(name, cities[i].name) == 0)
return i;
// not found
return -1;
}
Now I have given you almost all parts of the assignment, all you have to do is
stick them together and write the same functions for the meteo.csv file.
To edit one field:
void _ERR(char a) {
if (a == "f") printf("\n\tError File !!\n\n");
if (a == "m") printf("\n\tError Memory !!\n\n");
exit(1); }
char* stmm(const char* src) {
char* dst = malloc(strlen(src) + 1);
if (dst == NULL) return NULL;
strcpy(dst, src);
return dst; }
const char* getfield(char* line, int num) {
const char* tok;
for (tok = strtok(line, ",");
tok && *tok;
tok = strtok(NULL, ",\n"))
{
if (!--num)
return tok;
}
return NULL; }
void edit_file(char* FName, char* NewValue, int row, int col) {
int i, r = 0, c;
char line[1024];
FILE* fr, * fw;
fr = fopen(FName, "r");
fw = fopen(FName, "r+");
if (fr == NULL|| fw == NULL) _ERR("f");
while (fgets(line, 1024, fr))
{
char* tmp = stmm(line);
if (tmp == NULL) _ERR("m");
for (i = 0, c = 1; i < strlen(tmp); i++) {
if (tmp[i] == 44) c++;
}
for (i = 0; i < c; i++) {
if (r == row && i+1 == col) {
fprintf(fw,"%s", NewValue);
} else {
free(tmp);
tmp = stmm(line);
if (tmp == NULL) _ERR("m");
fprintf(fw,"%s", getfield(tmp, i + 1));
}
(i < c - 1) ? fprintf(fw,",") : fprintf(fw,"\n");
}
free(tmp);
r++;
}
fclose(fr);
fclose(fw); }
edit_file(".\FileName.csv","NewValue",Row,Column);
I am trying to read strings and integers from a simple text file to my array. But the problem is that I get some random characters in a line in the middle of my list. It probably has to do with a newline problem, but I am not sure. The text file looks like this:
4
Mr Tambourine Man
Bob Dylan
1965
Dead Ringer for Love
Meat Loaf
1981
Euphoria
Loreen
2012
Love Me Now
John Legend
2016
The first number (4), indicates how many songs there are in the list. I have made a struct which will be able to hold the songs and dynamically allocate memory for each pointer.
Struct:
typedef struct Song {
char *song;
char *artist;
int *year;
} Song;
Allocated:
Song *arr;
arr = (Song*)malloc(sizeof(Song));
Function:
int loadFile(char fileName[], Song *arr, int nrOf) {
FILE *input = fopen(fileName, "r");
if (input == NULL) {
printf("Error, the file could not load!\n");
} else {
int i = 0;
fscanf(input, "%d\n", &nrOf);
for (int i = 0; i < nrOf; i++) {
arr[i].song = (char*)malloc(sizeof(char));
arr[i].artist = (char*)malloc(sizeof(char));
arr[i].year = (int*)malloc(sizeof(int));
fgets(arr[i].song, 100, input);
fgets(arr[i].artist, 100, input);
fscanf(input, "%d\n", arr[i].year);
}
printf("The file is now ready.\n");
fclose(input);
}
return nrOf;
}
Are you able to find the problem? Or do you have a better solution?
This is wrong:
arr[i].song = (char*)malloc(sizeof(char));
arr[i].artist = (char*)malloc(sizeof(char));
You are only allocating buffers of size 1, there's no scaling. This gives you undefined behavior when you overrun the buffers by loading more data into them than they can hold.
I would expect those to read:
arr[i].song = malloc(100);
and so on. Note that no cast is necessary, and sizeof (char) is always 1.
Also, this:
arr[i].year = (int*)malloc(sizeof(int));
is super-strange. There's absolutely no reason to dynamically allocate a single integer, just make the field an int and store the value there directly.
First Issue:
arr[i].song = (char*)malloc(sizeof(char));
arr[i].artist = (char*)malloc(sizeof(char));
Are only allocating 1 byte for your char* pointers, song and artist. You can allocate a size for this:
arr[i].song = (char*)malloc(100 * sizeof(char)); /* or malloc(100) */
arr[i].artist = (char*)malloc(100 * sizeof(char));
Or you can simply malloc() enough space from you buffer:
char buffer[100];
fgets(buffer, 100, input);
/* check for failure, remove newline */
arr[i].song = malloc(strlen(buffer)+1);
/* check error from malloc */
strcpy(arr[i].song, buffer);
Or even use strdup():
arr[i].song = strdup(buffer);
Which is a substitute for malloc()/strcpy().
Note: You can also read Do I cast the result of malloc?.
Second Issue:
Your current struct:
typedef struct Song {
char *song;
char *artist;
int *year;
} Song;
Can be simplified to:
typedef struct {
char *song;
char *artist;
int year;
} Song;
Because year does not need to be a pointer. Easier to manage if its just an int. This avoids having to do allocations like:
arr[i].year = (int*)malloc(sizeof(int));
Other Recommendations:
You should check the return of fscanf() and fgets() as its safe to do this. It helps just incase your file will have incorrect data. This goes the same for malloc(), which can return NULL is unsuccessfully allocated on the heap.
Here is some code with the above considerations in mind:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 100
typedef struct {
char *song;
char *artist;
int year;
} Song;
Song *create_array(FILE *input, int *nrof);
void load_data(Song *arr, FILE *input, int nrof);
void print_free_data(Song *arr, int nrof);
void get_buffer(char buffer[], FILE *input);
int main(void) {
FILE *input;
Song *arr;
int nrof;
input = fopen("artist.txt", "r");
if (input == NULL) {
fprintf(stderr, "Error reading file\n");
exit(EXIT_FAILURE);
}
arr = create_array(input, &nrof);
load_data(arr, input, nrof);
print_free_data(arr, nrof);
fclose(input);
return 0;
}
Song *create_array(FILE *input, int *nrof) {
Song *arr;
if (fscanf(input, "%d ", nrof) != 1) {
fprintf(stderr, "Cannot find number of songs\n");
exit(EXIT_FAILURE);
}
arr = malloc(*nrof * sizeof(*arr));
if (arr == NULL) {
fprintf(stderr, "Cannot allocate %d spaces for array\n", *nrof);
exit(EXIT_FAILURE);
}
return arr;
}
void load_data(Song *arr, FILE *input, int nrof) {
char buffer[SIZE];
for (int i = 0; i < nrof; i++) {
get_buffer(buffer, input);
arr[i].song = malloc(strlen(buffer)+1);
if (arr[i].song == NULL) {
fprintf(stderr, "Cannot allocate song\n");
exit(EXIT_FAILURE);
}
strcpy(arr[i].song, buffer);
get_buffer(buffer, input);
arr[i].artist = malloc(strlen(buffer)+1);
if (arr[i].artist == NULL) {
fprintf(stderr, "Cannot allocate artist\n");
exit(EXIT_FAILURE);
}
strcpy(arr[i].artist, buffer);
if (fscanf(input, "%d ", &arr[i].year) != 1) {
fprintf(stderr, "Cannot find year for Song: %s Album: %s\n",
arr[i].song, arr[i].artist);
exit(EXIT_FAILURE);
}
}
}
void get_buffer(char buffer[], FILE *input) {
size_t slen;
if (fgets(buffer, SIZE, input) == NULL) {
fprintf(stderr, "Error from fgets(), line not read\n");
exit(EXIT_FAILURE);
}
slen = strlen(buffer);
if (slen > 0 && buffer[slen-1] == '\n') {
buffer[slen-1] = '\0';
} else {
fprintf(stderr, "Too many characters entered\n");
exit(EXIT_FAILURE);
}
}
void print_free_data(Song *arr, int nrof) {
for (int i = 0; i < nrof; i++) {
printf("%s\n%s\n%d\n\n", arr[i].song, arr[i].artist, arr[i].year);
free(arr[i].song);
arr[i].song = NULL;
free(arr[i].artist);
arr[i].artist = NULL;
}
free(arr);
arr = NULL;
}
Which Outputs correct data:
Mr Tambourine Man
Bob Dylan
1965
Dead Ringer for Love
Meat Loaf
1981
Euphoria
Loreen
2012
Love Me Now
John Legend
2016
Your memory allocation is incorrect. The structure should have char arrays for the song and artist names and an int for the year, and you should modify your API to return the array and its size to the caller:
int loadFile(const char *fileName, Song **arr, int *numberp);
Here is a corrected and simplified of your program:
#include <stdio.h>
#include <stdlib.h>
typedef struct Song {
char song[100];
char artist[100];
int year;
} Song;
/* call as
if (loadFile(fileName, &songs, &songs_size) < 0) {
// deal with error...
}
*/
int loadFile(const char *fileName, Song **arrp, int *numberp) {
FILE *input;
Song *arr;
int i, nrOf;
input = fopen(fileName, "r");
if (input == NULL) {
fprintf(stderr, "Cannot open file %s\n", filename);
return -1;
} else {
if (fscanf(input, "%d\n", &nrOf) != 1) {
fprintf(stderr, "%s: missing number of items\n", filename);
fclose(intput);
return -1;
}
arr = calloc(sizeof(*arr), nrOf);
if (arr == NULL) {
fprintf(stderr, "cannot allocate memory for %d items\n", nrOf);
fclose(intput);
return -1;
}
for (int i = 0; i < nrOf; i++) {
char cc;
if (fscanf(input, "%99[^\n]%*c%99[^\n]%*c%d%c",
sarr[i].song, arr[i].artist,
&arr[i].year, &cc) != 4 || cc != '\n') {
fprintf(stderr, "%s: invalid format for item %d\n",
filename, i);
break;
}
}
printf("The file is now ready.\n");
fclose(input);
*arrp = arr;
*numberp = i;
return i;
}
}