Spent an hour or two trying to debug this, but cannot figure out why it won't read my file correctly.
FILE *input;
int numAccounts = 7;
char **accountNames = malloc(sizeof(char)*numAccounts*10);
int *accountNumbers = malloc(sizeof(int)*numAccounts);
float *accountValues = malloc(sizeof(float)*numAccounts);
char *fileName = malloc(sizeof(char)*20);
input=fopen("input.txt","r");
int i;
for(i=0;i<numAccounts;i++) {
fscanf(input,"%s%d%f",*(accountNames+i),accountNumbers+i,accountValues+i);
printf("\n%s %d %f", *(accountNames+i), *(accountNumbers+i), *(accountValues+i));
}
fclose(input);
return 0;
And here is input.txt
Brown 1435 234.55
Dunn 2091 2011.75
Smith 8766 945.05
Stone 4530 0.0
Becker 9073 6235.75
Rich 1003 -42.00
Doe 6739 3655.80
Thank you!
You should start with non-dynamic allocation,
int main()
{
FILE *input = NULL;
int numAccounts = 7;
char accountNames[20] = "";
int accountNumbers = 0;
float accountValues = 0;
input=fopen("input.txt","r");
int i;
for(i=0;i<numAccounts;i++)
{
fscanf(input,"%s %d %f",accountNames,&accountNumbers,&accountValues);
printf("\n%s %d %f\n", accountNames, accountNumbers, accountValues);
}
fclose(input);
return 0;
}
If you must do dynamic allocation, then this pointer-to-pointer to char allocation is incorrect:
char **accountNames = malloc(sizeof(char)*numAccounts*10);
You'd need to allocate numAccounts of char * first, then for each char *, allocate 10 char. That can be done as follows:
char **accountNames = malloc(sizeof(char*)*numAccounts); // allocate numAccounts of char *
int i;
for( i=0; i < numAccounts; i++ )
{
*(accountNames + i) = malloc(sizeof(char)*10); // allocate 10 of char
}
So this should work:
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *input = NULL;
int numAccounts = 7;
char **accountNames = malloc(sizeof(char*)*numAccounts); // allocate numAccounts of char *
int i;
for( i=0; i < numAccounts; i++ )
{
*(accountNames + i) = malloc(sizeof(char)*10); // allocate 10 of char
}
int *accountNumbers = malloc(sizeof(int)*numAccounts);
float *accountValues = malloc(sizeof(float)*numAccounts);
input=fopen("input.txt","r");
for(i=0; i<numAccounts; i++)
{
fscanf(input,"%s%d%f",*(accountNames+i), accountNumbers+i, accountValues+i);
printf("\n%s %d %f", *(accountNames+i), *(accountNumbers+i), *(accountValues+i));
}
fclose(input);
return 0;
}
If the account values are currency. You may want to save them as ints and divide by the lowest unity of that currency.
So instead of saving float accountValue = 23.25 as 23.25, save it as 2335 (23.25 * 100).
Then when you read it divide by 100 to get that value back.
float accountValueDollars;
int accountValueInCents;
fscanf(..., &accountValueInCents);
accountValueDollars = accountValueInCents / 100;
Also, you may want to consider saving in binary format, this way you don't have to worry about parsing the text.
typedef struct _account_t{
char name[50];
int account_number;
double amount;
} account_t;
int how_many = 0;
account_t * accounts = NULL;
// error checking skipped
fread(&how_many, 1, sizeof(int), input);
accounts = (account_t*)malloc(sizeof(account_t) * how_many);
for(int i = 0; i < how_many; i++){
fread(&accounts[i], 1, sizeof(account_t), input);
// print here or whatever
}
fclose(input);
NOTE: Untested code.
Related
Excuse me for the sloppy code, I am still a beginner. But after putting a long time into this programming question I got from my Uni I don't know where to turn.
The question itself is: we need to read from the "staedte.csv" (which displays the population and cities of German states) and then return an array of strings with the strings formatted like this: The city ***** has a population of ****.
You are supposed to pass in 2 arguments into the cli: the number 100 and the state you want to check the cities and population for: example Bayern (Bavaria).
My plan was to make a 2d array. First I would dynamically allocate the memory for the first one by making a for loop and iterating over the original csv to check how many states in the csv = the state from the arguments. Then I would make a dynamic array using the amount of states in the csv matching. Then I would iterate (with for loop) over the list of matching states and then first check the length of the formatted string then: The city ***** has a population of ****., then allocate that memory and store the pointer to that info in the previously created array. Then I try to print the first item of that array, meaning the pointer.
I checked and there are 8 elements in the csv with Bavaria as their state, but in the for loop
for (j = 0; j < 8; j++)
if j is larger than 4 then I Get a segmentation fault even though the space is supposed to be allocated.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "input3.h"
/* Die Konstanten:
* int MAX_LAENGE_STR - die maximale String Länge
* int MAX_LAENGE_ARR - die maximale Array Länge
* sind input3.c auf jeweils 255 und 100 definiert
*/
int main(int argc, char **argv)
{
if (argc < 3)
{
printf("Aufruf: %s <anzahl> <bundesland>\n", argv[0]);
printf("Beispiel: %s 100 Bayern\n", argv[0]);
printf("Klein-/Großschreibung beachten!\n");
exit(1);
}
// int anzahl = atoi(argv[1]);
char *bundesland = argv[2];
// Statisch allokierter Speicher
char staedte[MAX_LAENGE_ARR][MAX_LAENGE_STR];
char laender[MAX_LAENGE_ARR][MAX_LAENGE_STR];
int bewohner[MAX_LAENGE_ARR];
read_file("staedte.csv", staedte, laender, bewohner);
// printf("%s %s", bundesland, laender[5]);
int CityCounter = 0;
int CopyCounter = 0;
int *CityArray;
CityArray = (int *)malloc(0);
for (int i = 0; i < MAX_LAENGE_ARR; i++)
{
if (strncmp(laender[i], bundesland, strnlen(bundesland, 10)) == 0)
{
CityArray = realloc(CityArray, sizeof(CityArray) + sizeof(int) * 1);
CityArray[CityCounter] = i;
CityCounter++;
}
}
// printf("%d", CityCounter);
char **string = (char **)malloc(CityCounter * sizeof(int));
int j;
printf("%d", (int)sizeof(CityArray));
int numOfCities = (int)sizeof(CityArray);
for (j = 0; j < 8; j++)
{
char buffer[100];
size_t size = snprintf(buffer, 50, "Die Stadt %s hat %d Einwohner.\n", staedte[CityArray[j]], bewohner[CityArray[j]]);
string[j] = malloc(sizeof(char) * size);
// string[j][size] = "\0";
strncpy(string[j], buffer, size);
}
// printf("%s", string[2]);
for (int i = 0; i < numOfCities; i++)
{
printf("%s", string[i]);
}
// write_file(string, sizeof(string));
free(string);
}
this is the code I wrote.
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include "input3.h"
int MAX_LAENGE_STR = 255;
int MAX_LAENGE_ARR = 100;
void write_file(char *result[], int len)
{
FILE *fp = fopen("resultat.txt", "w");
if (fp == NULL)
{
perror("resultat.txt");
exit(1);
}
for (int i = 0; i < len; i++)
{
fprintf(fp, "%s\n", result[i]);
}
fclose(fp);
}
int read_file(char *dateiname, char staedte[][MAX_LAENGE_STR], char laender[][MAX_LAENGE_STR], int bewohner[])
{
FILE *fp = fopen(dateiname, "r");
if (fp == NULL)
{
perror(dateiname);
exit(1);
}
char stadt[MAX_LAENGE_STR];
char land[MAX_LAENGE_STR];
int anzahl;
int i = 0;
int len;
while (fscanf(fp, "\"%[^\"]\";\"%[^\"]\";%d\n", stadt, land, &anzahl) != EOF)
{
if (i >= MAX_LAENGE_ARR)
{
printf("ERROR: Die Datei ist größer als erwartet!");
return i;
}
len = strlen(stadt) + 1;
strncpy(staedte[i], stadt, len - 1);
staedte[i][len - 1] = '\0';
len = strlen(land) + 1;
strncpy(laender[i], land, len - 1);
laender[i][len - 1] = '\0';
bewohner[i] = anzahl;
i++;
}
fclose(fp);
return i;
}
extern int MAX_LAENGE_ARR;
extern int MAX_LAENGE_STR;
void write_file(char *result[], int len);
int read_file(char *dateiname, char staedte[][MAX_LAENGE_STR], char laender[][MAX_LAENGE_STR], int bewohner []);
This code was supplied by our Uni but it should be correct.
So I changed the
char **string = (char **)malloc(CityCounter * sizeof(int)); to char
**string = (char *)malloc(CityCounter * sizeof(char)); and now I don't get null.
But if I once again change the
for (j = 0; j < 4; j++) {}
and modify the j larger then 4 then I get a bus error
so I have this file:
Jane
18
5.3
John
23
5.8
and I need to create a program to store this two persons details on a array of structs.
I have done this:
#include <stdio.h>
typedef struct
{
char name[100];
int age;
float height;
} PERSON;
main()
{
PERSON *X = NULL;
FILE *f;
char ch;
int lines = 1;
f = fopen("filename.txt", "r");
while ((ch = fgetc(f)) !=EOF)
{
if (ch == '\n')
lines++;
}
rewind(f);
X = (PERSON*) malloc ((lines/3) * sizeof(PERSON));
StoreInArray(X, f, lines);
}
StoreInArray(PERSON *X, FILE *f, int lines)
{
int i = 0;
for (i=0; i < lines/3; i++)
{
fscanf(f, "%s%d%f", (*(X+i)).name[100], &(*(X+i)).age, &(*(X+i)).height);
}
//for testing//
for (i=0; i < lines/3; i++)
printf("%s\n%d \n%f\n",X[i].name[100], X[i].age, X[i].height);
}
But all it prints is:
(null)
0
0.000000
If you could help me figure out what is wrong I'd be very appreciated!
Thank you in advance.
I'd compile with -Wall -O2 to catch warnings, which would have pointed out an error.
In your fscanf and printf, you don't want name[100] but name. You want to point to the name array, but name[100] is a single char [fetching past the end of the array (i.e.) undefined behavior], and would be flagged by the compiler.
Here's a version of your code with the bugs annotated/corrected:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char name[100];
int age;
float height;
} PERSON;
void StoreInArray(PERSON * X, FILE * f, int lines);
int
main()
{
PERSON *X = NULL;
FILE *f;
char ch;
int lines = 1;
f = fopen("filename.txt", "r");
while ((ch = fgetc(f)) != EOF) {
if (ch == '\n')
lines++;
}
rewind(f);
X = (PERSON *) malloc((lines / 3) * sizeof(PERSON));
StoreInArray(X, f, lines);
return 0;
}
void
StoreInArray(PERSON * X, FILE * f, int lines)
{
int i = 0;
for (i = 0; i < lines / 3; i++) {
#if 0
fscanf(f, "%s%d%f", (*(X + i)).name[100], &(*(X + i)).age, &(*(X + i)).height);
#else
fscanf(f, "%s%d%f", (*(X + i)).name, &(*(X + i)).age, &(*(X + i)).height);
#endif
}
//for testing//
for (i = 0; i < lines / 3; i++) {
#if 0
printf("%s\n%d \n%f\n", X[i].name[100], X[i].age, X[i].height);
#else
printf("%s\n%d \n%f\n", X[i].name, X[i].age, X[i].height);
#endif
}
}
Note that using *(X + i)).name is cumbersome, so here's a simplified and more readable version that uses an extra pointer variable:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char name[100];
int age;
float height;
} PERSON;
void StoreInArray(PERSON * X, FILE * f, int lines);
int
main()
{
PERSON *X = NULL;
FILE *f;
char ch;
int lines = 1;
f = fopen("filename.txt", "r");
while ((ch = fgetc(f)) != EOF) {
if (ch == '\n')
lines++;
}
rewind(f);
X = (PERSON *) malloc((lines / 3) * sizeof(PERSON));
StoreInArray(X, f, lines);
return 0;
}
void
StoreInArray(PERSON * X, FILE * f, int lines)
{
int i = 0;
PERSON *p;
p = X;
for (i = 0; i < lines / 3; i++, p++)
fscanf(f, "%s%d%f", p->name, &p->age, &p->height);
//for testing//
p = X;
for (i = 0; i < lines / 3; i++, p++)
printf("%s\n%d \n%f\n", p->name, p->age, p->height);
}
It isn't really necessary to preread the file to get a line count. It is possible to grow your array dynamically, as lines are read in, using realloc:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char name[100];
int age;
float height;
} PERSON;
int
main()
{
PERSON *X = NULL;
FILE *f;
int i;
PERSON *p;
int count = 0;
f = fopen("filename.txt", "r");
while (1) {
X = realloc(X,sizeof(PERSON) * (count + 1));
p = &X[count];
if (fscanf(f, "%s%d%f", p->name, &p->age, &p->height) == EOF)
break;
++count;
}
fclose(f);
// trim the array
X = realloc(X,sizeof(PERSON) * count);
p = X;
for (i = 0; i < count; i++, p++)
printf("%s\n%d \n%f\n", p->name, p->age, p->height);
return 0;
}
Here's a further refinement that reduces the number of realloc calls needed:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char name[100];
int age;
float height;
} PERSON;
int
main()
{
PERSON *X = NULL;
FILE *f;
int i;
PERSON *p;
size_t count = 0;
size_t alloc = 0;
f = fopen("filename.txt", "r");
while (1) {
if (count >= alloc) {
alloc += 100;
X = realloc(X,sizeof(PERSON) * alloc);
}
p = &X[count];
if (fscanf(f, "%s%d%f", p->name, &p->age, &p->height) == EOF)
break;
++count;
}
fclose(f);
// trim the array to what was actually used
X = realloc(X,sizeof(PERSON) * count);
p = X;
for (i = 0; i < count; i++, p++)
printf("%s\n%d \n%f\n", p->name, p->age, p->height);
return 0;
}
I'm trying to make an array of structs in c, but I can't make it work. When I try to run it, the program crashes.
typedef struct{
char name[20];
char manufacturer[20];
unsigned int price;
} product;
unsigned int stringToNr(char *numbers){
unsigned int nr = 0;
unsigned int i;
for (i = 0; i < strlen(numbers); i ++)
{
nr *= 10; nr += numbers[i] - '0';
}
return nr;
}
I have a function that would print the list to a file, sometimes it reaches this function, sometimes it crashes before.
void printList(product *products, unsigned int nr){
unsigned int i;
FILE *f;
f = fopen("output.txt", "w");
for (i = 0; i < nr; i ++){
fprintf(f, "%s ", products[i].name);
fprintf(f, "%s ", products[i].manufacturer);
fprintf(f, "%d\n", products[i].price);
}
fclose(f);
}
I have to use a separate function to read the list from file.
void readList(product **products, unsigned int *nr){
FILE *f;
f = fopen("input.txt", "r");
char *row;
row = malloc(sizeof(char) * 45);
unsigned int rowLength;
fgets(row, 45, f);
rowLength = strlen(row);
if (row[rowLength - 1] == '\n'){
rowLength--;
row[rowLength ] = '\0';
}
*nr = stringToNr(row);
products = malloc((*nr) * sizeof(product*));
unsigned int i;
char *rowElement;
for (i = 0; i < *nr; i ++){
fgets(row, 45, f);
rowElement = strtok(row, " ");
strcpy((*products)[i].name, rowElement);
rowElement = strtok(NULL, " ");
strcpy((*products)[i].manufacturer, rowElement);
rowElement = strtok(NULL, " ");
rowLength = strlen(row);
if (row[rowLength- 1] == '\n'){
rowLength--;
row[rowLength] = '\0';
}
(*products)[i].price = stringToNr(rowElement);
}
free(row);
fclose(f);
}
Obviously the program has more features, but those work fine.
int main(){
product *products;
unsigned int nr;
readList(&products, &nr);
printList(products, nr);
free(products);
return 0;
}
My input file looks like this:
3
AAA FactoryA 300
BBB FactoryC 550
ZZZ Factory5 100
Code ignores value of products.
What ever readList() receives in products is overwritten with the malloc() call.
void readList(product **products, unsigned int *nr){
...
// bad
products = malloc((*nr) * sizeof(product*));
Instead, use *products. Also allocate by the size of the referenced variable, not by the size of the type. Easier to code, review and maintain.
*products = malloc(sizeof *(*products) * (*nr));
if (*products == NULL) Handle_OOM();
Minor: After fgets(row, ..., ...); , following is not safe from a hacker exploit of reading an initial null character.
rowLength = strlen(row);
// What happens when rowLength == 0
if (row[rowLength- 1] == '\n'){
...
Instead code could use below to rid the optional trailing '\n'.
row[strcspn(row, "\n")] = '\0';
int main(int argc, char **argv) {
char *input = "input.txt";
int *account;
char **name;
float *balance;
int count;
int check;
if (argc < 4 || argc > 4) {
printf("Insufficient arguments. Check your command line arguments\n");
return 1;
}
count = atoi(*(argv + 2));
name = malloc(sizeof(char) * 20 * count);
account = malloc(sizeof(int) * count);
balance = malloc(sizeof(float) * count);
check = load_data(input, name, account, balance, count);
if (check == 0) {
printf("File cannot be open\n");
}
print_data(name, account, balance, count);
free(name);
return 0;
}
//load data from input file the according arrays
int load_data(char *input, char **name, int *acct, float *amt, int n) {
int *a = acct;
float *b = amt;
FILE *file = fopen("input.txt", "r");
int i;
if (file == NULL) {
return 0;
} else {
for (i = 0; i < 9; i++, acct++, amt++) {
fscanf(file, "%s %d %f", *(name + i), acct, amt);
}
}
fclose(file);
acct = a; //return pointer to original position
amt = b;
return 1;
}
//print data from arrays
void print_data(char **name, int *acct, float *amt, int n) {
int i;
for (i = 0; i < n; i++) {
printf("%-10s%-13s%s\n", "Name", "Account No.", "Amount");
printf("%-10s%-13d%7.2f\n", *(name + i), *(acct + i), *(amt + i));
}
}
I have this load_data function that suppose to read from a file and store the data values in different pointers, but for some reason when I print out using print_data function, the pointer contain all null and 0? (Please answer using pointers arithmetic and not array)
I expect that you have not properly prepared the arrays before calling the function... the below main function will work with your code:
int main(int argc, char* argv[]) {
int n = 10;
char ** name = malloc(n * sizeof(char*));
int* acct = malloc(n * sizeof(int));
float* amt = malloc(n * sizeof(float));
for (int i = 0; i < n; i++) {
// this is allocating some space for each line
// this is quite bad you should range check.
name[i] = malloc(256);
}
load_data("", name, acct, amt, n);
print_data(name, acct, amt, n);
// TODO: free everything
}
in load_data: a and b are not required and as amt and acct are "passed by value" there is no need to restore their values at the end of your function. That is to say that the values in all your arguments will be discarded when this function returns only the values that are "pointed to" are updated.
Example input.txt file:
Adam 1 900.9
Daniel 2 800.8
Joe 3 700.7
Foo 4 600.6
Bar 5 500.5
Alice 6 400.4
Bob 7 300.3
Nick 8 200.2
Eve 9 100.1
After altering your code slightly (see below) the above input file does work, here is the output I get:
$ ./test 5 5 5
Name Account No. Amount
Adam 1 900.90
Name Account No. Amount
Daniel 2 800.80
Name Account No. Amount
Joe 3 700.70
Name Account No. Amount
Foo 4 600.60
Name Account No. Amount
Bar 5 500.50
Updated main function based on the one you provided in the question:
int main(int argc, char **argv) {
char *input = "input.txt";
int *account;
char **name;
float *balance;
int count;
int check;
int i;
if (argc < 4 || argc > 4) {
printf("Insufficient arguments. Check your command line arguments\n");
return 1;
}
count = atoi(*(argv + 2));
name = malloc(sizeof(char *) * count);
for (i = 0; i < count; i ++) {
*(name+i) = malloc(20);
}
account = malloc(sizeof(int) * count);
balance = malloc(sizeof(float) * count);
check = load_data(input, name, account, balance, count);
if (check == 0) {
printf("File cannot be open\n");
}
print_data(name, account, balance, count);
free(balance);
free(account);
for (i = 0; i < count; i++) {
free(*(name+i));
}
free(name);
return 0;
}
... also in load_data I changed i < 9 to i < n.
I had my program printing out the words in a file and incrementing when they appeared more than once. I am now getting just "NULL" and the count as "17" instead. I can't find anything that I changed but am not sure if it is because I haven't figured out how to properly free up my arrays.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define BASE 5
#define MAX 50
typedef char *string;
struct wordCount
{
string word;
unsigned int count;
};
int main (void)
{
unsigned int i;
unsigned int found;
unsigned int arraysize;
unsigned int newsize;
char temp [40];
struct wordCount* wordArray;
FILE *infile;
arraysize = 0;
infile = fopen("input.txt","r");
wordArray = malloc(BASE * sizeof(struct wordCount));
/*store in word from infile to struct, increment counter each time it appears*/
while (fscanf(infile, "%s", temp) == 1) {
found = 0;
for (i = 0; i < arraysize; i++){
if(strcmp(temp,wordArray[i].word) == 0){
wordArray[i].count++;
found++;
}
}
if (found== 0){
if (arraysize<BASE){
wordArray[arraysize].word = (char
*)malloc((strlen(temp)+1) * sizeof(char));
strcpy(wordArray[arraysize].word,temp);
wordArray[arraysize].count = 1;
arraysize++;
} else {
wordArray = realloc(wordArray, arraysize * sizeof(struct wordCount));
wordArray[arraysize].word = (char *)malloc((strlen(temp)+1) *
sizeof(char));
strcpy(wordArray[arraysize].word,temp);
wordArray[arraysize].count = 1;
arraysize++;
}
}
}
fclose(infile);
/*newsize = SearchAndDestroy(wordArray, arraysize); */
for (i = 0; i < arraysize; i++) {
printf("%s ", wordArray[arraysize].word);
printf("%d\n", wordArray[arraysize].count);
/*free(wordArray[i].word);*/
}
/* and when done:*/
free(wordArray);
return 0;
}
You aren't tracking things properly. You need to pay more attention to the fact that "How many words I have", "how many words I have room for", and "how many words I would like to have room for" are three distinct items that need to all be tracked separately. In particular, it doesn't look like your call to realloc() is correct.