First I open a CSV file (Cars.csv) using my C file cars.c. My CSV file would look like:
toyota, 100, 20, 150.50
nissan, 200, 50, 100.75
BMW, 400, 80, 323.00
The 1st column is names, 2nd column is stock, 3rd column is order, 4th column is price.
Then I have to do two works(I will call the program in the commandline with the work name and any other argument I need to pass):
List all the items in the CSV file while the commas cannot be a part of the output. I also have to print headers for each column. (./cars list)
I would send an argument when running the program from the command line. The argument would be one the name of the items in my csv file. Then I would have to subtract 1 from the stock and update the CSVfile. (./cars reduce nissan)
This is how I opened the CSV file.
void main(int argc, char *argv[]) {
FILE *in = fopen ("Cars.csv" ,"rt");
if (in == NULL) {
fclose (in); return 0;
}
//I need to store the data from the CSV file in an array of pointers. I know how to do that, but Im having a problem in storing them without the commas and then doing what I need to do in part 1.
//This is the only code I could write for the 2nd part.
int p =0;
for(p =0; p<; p = p + 4) {
if(strcmp(argsv[2],save[p]) == 0) { //save is the array of pointers where I
int r = int(save[p +1]); //store the data from the csv file
int s = r - 1;
char str[15];
sprintf(str, "%d", s);
save[p +1] = str; // not sure if this line actually makes sense
}
}
There are a couple of possible solutions.
Here's one:
Read the lines into an array of pointers. Allocate array with malloc and reallocate as needed with realloc. Read lines with fgets.
For each line, use strtok to split the line, and do whatever you need with each field.
Another solution:
Use your favorite search engine to search for an existing CSV-reading library (there are many out there, which can handle very advanced CSV files).
Think how the data should be represented and define a structure.
typedef struct {
char *name;
int stock;
int order;
double price;
} car_type;
Open the file: See OP's code
Find how many lines and allocate memory
char buf[100];
size_t n = 0;
while (fgets(buf, sizeof buf, in) != NULL) n++;
rewind(in);
car_type *car = malloc(n * sizeof *car);
if (car == NULL) OutOfMemory();
Read the cars
for (size_t i=0; i<n; i++) {
if (fgets(buf, sizeof buf, in) == NULL) Handle_UnexpectedEOF();
char car_name[100];
if (4 != sscanf(buf, "%s ,%d ,%d, %lf", car_name,
&car[i].stock, &car[i].order, &car[i].price) Handle_FormatError();
car[i].name = strdup(car_name);
}
// Use `car` ...
When done
fclose(in);
for (size_t i=0; i<n; i++) {
free(car[i].name);
}
free(car);
Related
I need to read a file of ints into an array in C. A sample of the file I need to read is below, though note the files this will process can have thousands or hundreds of thousands of lines.
127
234
97
8723
I've gotten the file open in C, read how many lines there are so I know how many spaces my array needs, but I can't seem to read/parse each line into the array.
FILE *file;
int N = 0;
char filePath[30];
char endFile;
printf("What file should be used?\n");
scanf("%s", filePath);
file = fopen(filePath, "r");
if(file == NULL) {
printf("This file failed to open.\n");
break;
}
for(endFile = getc(file); endFile!=EOF; endFile=getc(file))
if(endFile == '\n') {
N = N+1;
}
int myArray[N];
while(fscanf(file, "%d\n", &a) != EOF) {
fscanf(file, "%d\n", &a); // I'm not sure this line is needed...
printf("%d\n", a);
M[i] = a;
}
From here, I need to read the file contents into myArray, with each line being the corresponding spot in the array (i.e. line zero is myArray[0], line one is myArray[1], etc.). I can't seem to find a way to do this, though I see several methods to do tab-delimited 2d arrays or csv multi-dimensional arrays.
Please also let me know if creating the array/determining the array size can be done in a better way than literally counting new-line characters...
There's no need to first "count the number of lines".
The following code cautiously grows an array of integers (by increments of 10).
#define GROW 10
int *rec = NULL, nRec = 0, sz = 0;
while( fgets( buf, sizeof buf, ifp ) != NULL ) {
if( nRec == sz ) {
rec = realloc( rec, (nRec+GROW) * sizeof *rec );
/*omitting test for failure */
sz += GROW;
}
rec[ nRec++ ] = atoi( buf );
}
This shows what is possible.
Note that realloc() can fail, returning NULL... It's up to you to add a bit of code to handle that condition.
Further, some conventional thought is to double the size of the allocation when needed (because realloc() may not be 'cheap'.) You can decide if you want to grow the array in increments (of 1024?) or grow it exponentially.
Im Completely new to programming but need to get a program running as part of my training. The programs ultimate goal is to read files from a database and then send them to the client who is asking for it.
Currently im just learning how to read strings from a file and write it to a different file. But my problem is that I want to print data out every time i hit a new line.
The data in the file im using is in the following format:
<DESCRIPTION>data,<DESCRIPTION>data,<DESCRIPTION>data etc.
The data is both int and chars.
Since the data is seperated with a "," i was thinking of first puting all "<DESCRIPTION>data" into substrings with the strtok function i managed to find while googling, after that i would scan only for the "DESCRIPTION" part and then put the desired data into an array that I then would print out when reaching the end of the array (end of the line) and then move on to the next line until End of file.
What functions can I use to fix this? Or how do I set up a loop that wont take forever by scanning all chars in the line everytime it wants data? If what im saying and what im doing is 2 different things I again apologize for being a total beginner at programming. I have been prgramming for a week now and this is all I could produce
#include <stdio.h>
#include <ctype.h>
void get9202() {
char
const * str;
const char s = ",";
char * token;
/*open database file*/
FILE * fp = fopen("datafile.dat", "r");
/*create array with all lines of data
I would like it to be able to handle unknown amounts of data.
current file is ~177000 lines of data.*/
int i = 0;
char line[i];
/*checking until end of file*/
while (fgets(line, sizeof(line), fp)) {
/*This part has to be included in the loop somehow but put in here
so that you might get a picture of what im trying to do.*/
while ( * str) {
if (!isspace( * str++))
i++;
else break;
/*not entirely sure how to exit this subloop
to print out the data and go to new line*/
}
/*trying to segment the string into an array of substrings
but dont know when to introduce x*/
token[x] = strtok(str, s);
while (token[x] != NULL) {
printf("%s\n,", token);
}
}
return result;
/* dont know how to return the file to main*/
flclose("datafile.dat");
}
If the data looks like this:
<SYMBOL>9202.T,<SYMSTAT>2,<MSGSTAT>0,<TIME>20:50:40.905246,<SYS_DT>2018/07/19,<SYS_TIM>20:50:40.503,<SYS_TIMU>20:50:40.503236
<SYMBOL>9202.T,<SYMSTAT>2,<MSGSTAT>0,<TIME>20:51:40.000235,<SYS_DT>2018/07/19,<SYS_TIM>20:51:39.598,<SYS_TIMU>20:51:39.598597
the expected file could look like
9202.T,2,0,20:50:40.905246
9202.T,2,0,20:51:40.000235
as the wanted pieces are being selected some will fall away.
Few problems:
Will declare zero length array.
int i=0;
char line[i];
fclose is never executed because of return also fclose needs FILE * as argument.
return result;
/* dont know how to return the file to main*/
flclose("datafile.dat");
Suggestions:
trying to segment the string into an array of substrings but dont
know when to introduce x
Use fgets with fscanf to parse your line since all the lines are identical.
dont know how to return the file to main
Define a structure with needed fields and return it to main.
Example:
typedef struct {
char symbol[50];
char symstat;
char msgstat;
char time[50];
}data;
data *get9202(int *numData) {
int memAllocated = 10;
data *mData = malloc(sizeof(*mData) * memAllocated);
FILE *fp = fopen("datafile.dat", "r");
char buf[3000];
int i = 0;
while (fgets(buf, sizeof buf, fp) != NULL) {
if (i == memAllocated) {
memAllocated *= 2;
void *temp = realloc(mData, sizeof( *mData) * memAllocated);
if (temp != NULL) mData = temp;
else break; //error
}
if (sscanf(buf, "<SYMBOL>%[^,],<SYMSTAT>%c,<MSGSTAT>%c,<TIME>%[^,]",
mData[i].symbol, &mData[i].symstat, &mData[i].msgstat, mData[i].time) == 4) {
i++;
} else {
printf("error\n"); //error
}
}
fclose(fp);
*numData = i;
return mData;
}
int main() {
int len = 0;
data *mData = get9202( &len);
int i = 0;
for (i = 0; i < len; i++)
printf("%s,%c,%c,%s\n", mData[i].symbol, mData[i].symstat, mData[i].msgstat,
mData[i].time);
if (mData) free(mData);
}
void inputData()
{
FILE* fp = fopen("input_001.txt", "r");
if(fp == NULL)
{
exit(FILE_FAILED_TO_OPEN);
}
fseek(fp, 0, SEEK_END); //set position to end of file
int size = ftell(fp);
if(size == 0)
{
exit(PARSING_ERROR_EMPTY_FILE);
}
int i;
char *input;
char *errPtr = NULL;
char *data;
fgets(input, 64, fp);
for(i = 0; i < size; i++)
{
strtol(input[i], *errPtr, 10);
//testing the output
printf("%d\n", input[i]);
}
fclose(fp);
if(fclose(fp) != 0)
{
exit(FILE_FAILED_TO_CLOSE);
}
}
I am trying to input data from a text file of unknown size into an array and keep only the integers. The format of the text file is one number per line and there can be any number of lines. I have included my attempt at trying to input the data, but my coding was not going so well. I want to use fgets() and then strtol() to convert the lines I get from fgets() into integers and put them in an array so I can work with that data. Any help is appreciated!
You haven't allocated any space for input to point to. I saw your
earlier version had a malloc; you can use that, or just a char
array.
Did you mean to use data? Because you're not, yet.
fgets reads at most one line at a time, so you need to put your reads
in a loop.
You appear to be converting the string to a number multiple times. For
instance, if the first line were "12345", this code would get 12345,
then 2345, 345, etc. This was presumably not your intention.
You're incrementing i up to size. size is the file size and might
be quite large, but you only read a maximum of 64 characters into the
buffer. (Or would have, if space had been allocated.)
In short, this code is very confused and I recommend starting over from
scratch. Decide whether you want to read the entire file at once, or one
line at a time; I recommend the latter, it takes less memory and is
simpler. If you want to store them in an array, you can do that with
malloc and then realloc as needed to grow the array dynamically.
do not use strtol, use atoi instead.
and use a loop to read the lines.
just a quick answer:
int count = 0;
while( fgets (input, 64, fp) != NULL )
{
count++;
}
fseek(fp, 0, SEEK_SET);
int* arr = new int[count];
count = 0;
while( fgets (input, 64, fp) != NULL )
{
int a =atoi(input);
arr[count++] = a;
}
If you don't know how many lines are in the file, you have a few options:
Loop through the file, counting the number of lines (call it nlines). Then declare the array int numbers[nlines].
Use a linked list instead of an array to store the numbers.
Dynamically allocate blocks of an array.
As for reading the integer data itself, something like this would work if you decide to go with the first option:
void inputData(const char* fname, const unsigned int nlines)
{
FILE* fp = fopen(fname, "r");
if (fp == NULL) {
exit(EXIT_FAILURE);
}
int numbers[nlines];
double d = 0;
fscanf(fp, "%lf", &d);
int i = 0;
while (!feof(fp)) {
numbers[i++] = (int)floor(d);
fscanf(fp, "%lf", &d);
}
fclose(fp);
}
I want to parse information from a CSV file and display it to my screen. My issue is that I keep receiving Segmentation fault core dumped from my while loop, which is supposed to be storing the CSV file info into different arrays to represent the different columns in the CSV. A sample line in my CSV would be rice,10,20,$2.00 which represents the food, stock, reorder limit, and cost per unit.
char buffer[1024];
char *line=buffer;
FILE *file=fopen("inventory.csv", "rw");
int x;
int i=0;
int j=0;
char *food [100];
int stock [100];
double cost [100];
int reorder [100];
while (fgets(line, 2048, file) != NULL){
food[i] = (strtok(line, ","));
stock [i] = (atoi(strtok(NULL, ",")));
reorder[i] = (atoi(strtok(NULL, ",")));
cost[i] = (atof(strtok(NULL, ",")));
line=line+25;
i++; }
First, your code has a basic problem: you want to read an infinite amount of data and store it into finite space.
In more details:
You keep advancing line by 25 after each line, it points to buffer which has a size of 1024, so after 40 lines you will be writing after the end of it.
Your arrays have a size of 100, so after 100 lines you will be writing after the end of them.
Do you need to store everything you read forever?
Now if this is not the problem, it could also be that strtok fails to find the "," and returns NULL, you should always check the return of strtok before using the result. It may for example fail if your file finishes with some empty lines, or just that you don't have a "," after the last element of the line that you read.
My bet is that you're trying to access a position in your arrays that doesn't exist. Try looking the last i value before your program crashes.
Please take a look at the following class. You may call it with
main.cpp
Stock line_stock;
file >> line_stock; //Use it in a loop cause it only reads a line
Stock.h
#include <iostream>
#include <string>
class Stock {
public:
private:
std::string food;
unsigned int stock;
double cost;
unsigned int reorder;
friend std::istream& operator >> (std::istream& is, Stock& s){
char coma;
is >> s.food >> coma>>
s.stock >> coma >>
s.cost >> coma >>
s.reorder;
return is;
}
};
//double doesn't work well on money, use unsigned int instead. Divide by 100 to get the dollar and % 100 to get the cents.
Using that class reads a line, then you process it and you're up to the next line.
When trying to read a file with an unknown number of data lines 2 approaches come to mind:
1) Read line by line and adjust memory allocation as needed.
2) Parse the file twice. First to find needed length.
A robust program typically uses method #1. But #2 is simpler for learners. #2 follows.
FILE *file = fopen("inventory.csv", "rw");
// Test for file == NULL
char buffer[100];
size_t n = 0;
// Find number of lines
while (fgets(buffer, sizeof buffer, file) != NULL)
n++;
char *food = malloc(n * sizeof *food);
int stock = malloc(n * sizeof *stock);
double *cost = malloc(n * sizeof *cost);
int *reorder = malloc(n * sizeof *reorder);
// TBD: Add checks for failed malloc
rewind(file);
size_t i = 0;
for (i = 0; i<n; i++) {
char name[sizeof buffer];
if (fgets(buffer, sizeof buffer, file) != NULL) Handle_UnexpectedError();
int cnt = sscanf(buffer, "%s ,%d ,%d , $%lf",
name, &stock[i], &reorder[i], &cost[i]);
if (cnt != 4) Handle_FormatError();
food[i] = strdup(name);
}
fclose(file);
// Use food, stock, reorder, cost
// When done
for (i = 0; i<n; i++) {
free(food[i]);
}
free(food);
free(stock);
free(reorder);
free(cost);
This is for a beginner's C programming unit. I'm trying to read a text file containing MAC addresses and the data they received, separate out the relevant data (address and number of packets), copy the addresses to an array without repeating any of them and sum the associated number of packets if an identical address is encountered.
I can read the file in just fine, and get the bits of each line I want without issue, but when I try to check each address read against those already in the array I hit a problem. Depending on the location of the integer counting the number of full lines, the program either fails to recognise identical strings and prints them all as they are in the file, or prints them over one another in addresses[0], leaving me with only the last address. I'm stumped and need some fresh eyes on this - any suggestions would be greatly appreciated.
My code follows:
static void readadds(char filename[])
{
FILE* packetfile = fopen(filename, "r");
FILE* datafile = fopen("packdata.txt", "w+");
// Open file from input; create temporary file to store sorted data.
char line[100];
char addresses[500][18];
int datasize[500];
int addressno = 0;
// Create storage for lines read from text file, addresses and related data.
if(packetfile != NULL)
{
while(fgets(line, sizeof line, packetfile) != NULL)
{
int linenum = 0;
char thisadd[18];
int thisdata;
//Create arrays to temp store data from each line
sscanf(line, "%*s %*s %s %i", thisadd, &thisdata);
for(int i = 0; i < 500; i++)
{
if(strcmp(thisadd, addresses[i]) == 0)
{ //check if the address is already in the array
int x = datasize[i];
datasize[i] = x + thisdata; //sum packet data if address already exists
printf("Match!\n");
break;
}
else
{
strcpy(addresses[linenum], thisadd); //initialize new address
datasize[linenum] = thisdata; //initialize assoc. data
linenum++;
addressno++;
printf("Started!\n");
break;
}
}
}
for(int i = 0; i <= addressno; i++)
{
printf("%s %i\n", addresses[i], datasize[i]);
fprintf(datafile,"%s %i\n", addresses[i], datasize[i]);
}
}
fclose(packetfile);
fclose(datafile);
}
This version prints over addresses[0]. If linenum is replaced by addressno in the for() loop, identical strings are not recognised. My dataset is arranged like this:
1378251369.691375 84:1b:5e:a8:bf:7f 68:94:23:4b:e8:35 100
1378251374.195670 00:8e:f2:c0:13:cc 00:11:d9:20:aa:4e 397
1378251374.205047 00:8e:f2:c0:13:cc 00:11:d9:20:aa:4e 397
1378251374.551604 00:8e:f2:c0:13:cc 00:11:d9:20:aa:4e 157
1378251375.551618 84:1b:5e:a8:bf:7c cc:3a:61:df:4b:61 37
1378251375.552697 84:1b:5e:a8:bf:7c cc:3a:61:df:4b:61 37
1378251375.553957 84:1b:5e:a8:bf:7c cc:3a:61:df:4b:61 37
1378251375.555332 84:1b:5e:a8:bf:7c cc:3a:61:df:4b:61 37
I'm almost certain this is what you're trying to do. The logic to add a new entry was incorrect. You only add one if you have exhausted searching all the current ones, which means you need to finish the current for-search before the add.
Note: Not tested for compilation, but hopefully you get the idea.
static void readadds(char filename[])
{
// Open file from input; create temporary file to store sorted data.
FILE* packetfile = fopen(filename, "r");
FILE* datafile = fopen("packdata.txt", "w+");
// Create storage for lines read from text file, addresses and related data.
char addresses[500][18];
int datasize[500];
int addressno = 0;
if (packetfile != NULL)
{
char line[100];
while(fgets(line, sizeof line, packetfile) != NULL)
{
char thisadd[18];
int thisdata = 0;
//Create arrays to temp store data from each line
if (sscanf(line, "%*s %*s %s %i", thisadd, &thisdata) == 2)
{
// try to find matching address
for(int i = 0; i < addressno; i++)
{
if(strcmp(thisadd, addresses[i]) == 0)
{
//check if the address is already in the array
datasize[i] += thisdata;;
printf("Match!\n");
break;
}
}
// reaching addressno means no match. so add it.
if (i == addressno)
{
printf("Started!\n");
strcpy(addresses[addressno], thisadd); //initialize new address
datasize[addressno++] = thisdata; //initialize assoc. data
}
}
else
{ // failed to parse input parameters.
break;
}
}
for(int i = 0; i <= addressno; i++)
{
printf("%s %i\n", addresses[i], datasize[i]);
fprintf(datafile,"%s %i\n", addresses[i], datasize[i]);
}
}
fclose(packetfile);
fclose(datafile);
}