How to sum up numbers from each lines in file in c? - c

I need to sum up the numbers from each line in the file like this e.g.:
1 2 3
10 -1 -3
and the result I should write to another file in each line likes this:
6
6
And I have the problem when in each line after the last number in reading file have more spaces, for example, maybe I use the '_' to show this problem:
When my function works:
10_11_12 '\n'
1_2_3 '\n'
and when my function doesn't work:
10_11_12_ _ _ '\n'
1_2_3 '\n'
I think I know where is the problem, but I have no idea how to fix it.
It's my function here:
int num=0;
char s;
while(fscanf(file, "%d", &num)==1){
fscanf(file, "%c", &s);
sum+=num;
if(s=='\n'){
fprintf(res_file, "%d\n", sum);
sum=0;
}
}

The problem is that fscanf is expecting a pointer to a char. Within your function, you are using a regular char, s.
char s;
You can fix your issue by making s a pointer. First, Allocate memory.
char *s = malloc(sizeof(char) + 1);
Now we can properly scan into the variable, s, and then check for the newline character. The only difference here is now we check for the newline by dereferencing s.
if (*s == '\n')
Don't forget to clean up the memory leak with free()!
free(s);
I was able to get the desired output using the code below.
#include <stdio.h>
#include <stdlib.h>
int processInputFile(char *filename)
{
FILE *ifp;
int buffer = 0;
char *newline = malloc(sizeof(char) + 1);
int sum = 0;
if ((ifp = fopen(filename, "r")) == NULL)
{
fprintf(stderr, "Failed to open \"%s \" in processInputFile.\n", filename);
return -1;
}
while(fscanf(ifp, "%d", &buffer) == 1)
{
fscanf(ifp, "%c", newline);
sum += buffer;
if (*newline == '\n')
{
printf("%d\n", sum);
sum = 0;
}
}
free (newline);
fclose(ifp);
}
int main(int argc, char **argv)
{
if (argc < 2)
{
printf("Proper syntax: ./a.out <n>\n");
return -1;
}
processInputFile(argv[1]);
return 0;
}

Any kind of line-by-line processing in C is easier done by reading the line first, and then processing it. fgets(3) handles end-of-line for you; then you just need to scan what it read. Plus, in the real world, some lines won't scan: either they'll have errors, or your scan won't be general enough. When that happens, it's awfully handy to write the input to standard error, so you can see what you're looking at.
Here's a complete program that does what you want. It assumes lines are less than 80 bytes long and doesn't protect against invalid input, though.
#include <stdio.h>
#include <err.h>
int main( int argc, char *argv[] ) {
char line[80];
static const char *filename = "sum.dat";
FILE *input;
if( (input = fopen(filename, "r")) == NULL ) {
err(1, "could not open %s", filename);
}
for( int nlines = 0;
fgets(line, sizeof(line), input) != NULL;
nlines++ )
{
double value, sum = 0;
int n;
for( char *p = line; sscanf(p, "%lf%n", &value, &n) > 0; p += n ) {
sum += value;
}
printf( "line %d: sum = %lf\n", nlines, sum );
}
return 0;
}

Reading with a line-oriented input function like fgets() or POSIX getline() ensures that a complete line of input is consumed on each call. (don't skimp on buffer size). strtol was created to convert an unknown number of values per-line into long. You walk-a-pointer down your buffer by utilizing the endptr parameter filled by strtol after a successful conversion to point to the next character after the last digit converted.
This allows a simple method to use a pair of pointers, p your start-pointer and ep your end-pointer to work through an entire line converting values as you go. The basic approach is to call strtol, validate it succeeded, and then set p = ep; to advance to the start of your next conversion. strtol ignores leading whitespace.
Putting it altogether, you could do:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#define MAXC 1024 /* if you need a constant, #define one (or more) */
/* (don't skimp on buffer-size) */
int main (int argc, char **argv) {
char buf[MAXC]; /* buffer to hold each line read */
size_t n = 0; /* line-counter */
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
while (fgets (buf, MAXC, fp)) { /* read each line */
char *p = buf, *ep = p; /* pointer and end-pointer */
int sum = 0; /* variable to hold sum */
if (*buf == '\n') /* ignore empty lines */
continue;
while (*p && *p != '\n') {
errno = 0;
long tmp = strtol (p, &ep, 0); /* convert to temp long */
if (p == ep) { /* validate digits were converted */
fputs ("error: no digits extracted.\n", stderr);
break;
}
else if (errno) { /* validate no under/overflow occurred */
fputs ("error: underflow/overflow occurred.\n", stderr);
break;
}
else if (tmp < INT_MIN || INT_MAX < tmp) { /* validate in range */
fputs ("error: tmp exceeds range of int.\n", stderr);
break;
}
sum += tmp; /* add tmp to sum */
p = ep; /* set p to end-ptr (one past last digit used) */
}
n++; /* advance line counter */
printf ("sum line [%2zu] : %d\n", n, sum); /* output sum */
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
return 0;
}
(note: the if (*buf == '\n') which tests if the first character in the line is a newline character and simple skips to the next line, no need to worry about converting values in a empty line)
Example Use/Output
Using your data in dat/sumlines.txt produces the expected results.
$ ./bin/sumline dat/sumlines.txt
sum line [ 1] : 6
sum line [ 2] : 6
Let me know if you have further questions.

Related

Going Through multiple columns of a csv file in C

I want to write a program, that reads a very large csv file. I want the file to read the columns by name and then print the entirety of the column. However it only prints out one of the columns in the datalist. So it only prints out the unix timestamp columns out of the entirety of the program. I want the code to be able to print out the other columns as well Unix Timestamp,Date,Symbol,Open,High,Low,Close,Volume BTC,Volume USD
csv file:
Unix Timestamp,Date,Symbol,Open,High,Low,Close,Volume BTC,Volume USD
1605139200.0,2020-11-12,BTCUSD,15710.87,15731.73,15705.58,15710.01,1.655,26014.29
1605052800.0,2020-11-11,BTCUSD,15318,16000,15293.42,15710.87,1727.17,27111049.25
1604966400.0,2020-11-10,BTCUSD,15348.2,15479.49,15100,15318,1600.04,24521694.72
1604880000.0,2020-11-09,BTCUSD,15484.55,15850,14818,15348.2,2440.85,37356362.78
1604793600.0,2020-11-08,BTCUSD,14845.5,15672.1,14715.98,15484.55,987.72,15035324.13
Current code:
#include<stdio.h>
#include<stdlib.h>
void main()
{
char buffer[1001]; //get line
float timestampfile;
FILE *fp;
int i=1; //line
fp = fopen("filename.csv", "r"); //used to read csv
if(!fp)
{
printf("file not found"); //file not found
exit(0);
}
fgets(buffer,1000, fp); //read line
printf("Expected output print the first column:\n");
while(feof(fp) == 0)
{
sscanf(buffer,"%f",&timestampfile); //read data line
printf("%d: %f\n",i,timestampfile); //used to print data
i++;
fgets(buffer, 1000, fp);
}
printf("end of the column");
fclose(fp);
}
Current output:
1: 1605139200.000000
2: 1605052800.000000
3: 1604966400.000000
4: 1604880000.000000
5: 1604793600.000000
end of the column
You have started out in the right direction, but you have stumbled a bit in handling separating the comma separated values. The standard C library provides all you need to handle separating the values.
Simple Implementation Using strtok()
The easiest implementation would be to take the filename to read and the index of column to extract as the first two arguments to your program. Then you could simply discard the heading row and output the requested value for the column index. That could be done with a simple loop that keeps track of the token number while calling strtok(). Recall on the first call to strtok() the variable name for the string is passed as the first parameter, ever successive call passes NULL as the first argument until no more tokens are found.
A short example would be:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXC 1024 /* if you need a constant, #define one (or more) */
#define DELIM ",\n"
int main (int argc, char **argv) {
if (argc < 3) { /* validate filename and column given as arguments */
fprintf (stderr, "usage: %s filename column\n", argv[0]);
return 1;
}
char buf[MAXC]; /* buffer to hold line */
size_t ndx = strtoul (argv[2], NULL, 0); /* column index to retrieve */
FILE *fp = fopen (argv[1], "r"); /* file pointer */
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
if (!fgets (buf, MAXC, fp)) { /* read / discard headings row */
fputs ("error: empty file.\n", stderr);
return 1;
}
while (fgets (buf, MAXC, fp)) { /* read / validate each line */
char *p = buf;
size_t i = 0;
/* loop until the ndx token found */
for (p = strtok(p, DELIM); p && i < ndx; p = strtok (NULL, DELIM))
i++;
if (i == ndx && p) /* validate token found */
puts (p);
else { /* handle error */
fputs ("error: invalid index\n", stderr);
break;
}
}
}
(note: strtok() considers multiple delimiters as a single delimiter. It cannot be used when empty fields are a possibility such as field1,field2,,field4,.... strsep() was suggested as a replacement for strtok() and it does handle empty-fields, but has shortcomings of its own.)
Example Use/Output
first column (index 0):
$ ./bin/readcsvbycol_strtok dat/largecsv.csv 0
1605139200.0
1605052800.0
1604966400.0
1604880000.0
1604793600.0
second column (index 1)
$ ./bin/readcsvbycol_strtok dat/largecsv.csv 1
2020-11-12
2020-11-11
2020-11-10
2020-11-09
2020-11-08
thrid column (index 2)
$ ./bin/readcsvbycol_strtok dat/largecsv.csv 2
BTCUSD
BTCUSD
BTCUSD
BTCUSD
BTCUSD
forth column (index 3)
$ ./bin/readcsvbycol_strtok dat/largecsv.csv 3
15710.87
15318
15348.2
15484.55
14845.5
request out of range:
$ ./bin/readcsvbycol_strtok dat/largecsv.csv 9
error: invalid index
More Involved Example Displaying Headings as Menu
If you wanted to provide a short interface for the user to choose which column to output, you could count the columns available. You can determine the number of commas present (and adding one more provides the number of columns). You can then save the headings to allow the user to select which column to output by allocating column number of pointers and then by allocating storage for each heading and copying the heading to the storage. You can then display the headings as a menu for the user to select from.
After determining which column to print, you simply read each line into your buffer, and then tokenize the line with either strtok() or strcspn() (the downside to strtok() is that it modifies the buffer, so if you need to preserve it, make a copy). strcspn() returns the length of the token, so it provides the advantage of not modifying the original and providing the number of characters in the token. Then you can output the column value and repeat until you run out of lines.
An example would be:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXC 1024 /* if you need a constant, #define one (or more) */
int main (int argc, char **argv) {
char buf[MAXC], *p = buf, **headings = NULL;
size_t cols = 1, ndx = 0, nchr;
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
if (!fgets (buf, MAXC, fp)) { /* read / validate headings row */
fputs ("error: empty file.\n", stderr);
return 1;
}
while (*p && (p = strchr (p, ','))) { /* loop counting ',' */
cols++;
p++;
}
p = buf; /* reset p to start of buf */
/* allocate cols pointers for headings */
if (!(headings = malloc (cols * sizeof *headings))) {
perror ("malloc-heading pointers");
return 1;
}
/* loop separating headings, allocate/assign storage for each, copy to storage */
while (*p && *p != '\n' && (nchr = strcspn (p, ",\n"))) {
if (!(headings[ndx] = malloc (nchr + 1))) { /* allocate/validate */
perror ("malloc headings[ndx]");
return 1;
}
memcpy (headings[ndx], p, nchr); /* copy to storage */
headings[ndx++][nchr] = 0; /* nul-terminate */
p += nchr+1; /* advance past ',' */
}
if (ndx != cols) { /* validate ndx equals cols */
fputs ("error: mismatched cols & ndx\n", stderr);
return 1;
}
puts ("\nAvailable Columns:"); /* display available columns */
for (size_t i = 0; i < cols; i++)
printf (" %2zu) %s\n", i, headings[i]);
while (ndx >= cols) { /* get / validate selection */
fputs ("\nSelection: ", stdout);
if (!fgets (buf, MAXC, stdin)) { /* read input (same buffer) */
puts ("(user canceled input)");
return 0;
}
if (sscanf (buf, "%zu", &ndx) != 1 || ndx >= cols) /* convert/validate */
fputs (" error: invalid index.\n", stderr);
}
printf ("\n%s values:\n", headings[ndx]); /* display column name */
while (fgets (buf, MAXC, fp)) { /* loop displaying column */
char column[MAXC];
p = buf;
/* skip forward ndx ',' */
for (size_t col = 0; col < ndx && (p = strchr (p, ',')); col++, p++) {}
/* read column value into column */
if ((nchr = strcspn (p, ",\n"))) {
memcpy (column, p, nchr); /* copy */
column[nchr] = 0; /* nul-terminate */
puts (column); /* output */
}
}
if (fp != stdin) /* close file if not stdin */
fclose (fp);
for (size_t i = 0; i < cols; i++) /* free all allocated memory */
free (headings[i]);
free (headings);
}
Example Use/Output
$ ./bin/readcsvbycol dat/largecsv.csv
Available Columns:
0) Unix Timestamp
1) Date
2) Symbol
3) Open
4) High
5) Low
6) Close
7) Volume BTC
8) Volume USD
Selection: 1
Date values:
2020-11-12
2020-11-11
2020-11-10
2020-11-09
2020-11-08
Or the open values:
$ ./bin/readcsvbycol dat/largecsv.csv
Available Columns:
0) Unix Timestamp
1) Date
2) Symbol
3) Open
4) High
5) Low
6) Close
7) Volume BTC
8) Volume USD
Selection: 3
Open values:
15710.87
15318
15348.2
15484.55
14845.5
Column out of range canceling input with Ctrl + d (Ctrl + z on windows):
$ ./bin/readcsvbycol dat/largecsv.csv
Available Columns:
0) Unix Timestamp
1) Date
2) Symbol
3) Open
4) High
5) Low
6) Close
7) Volume BTC
8) Volume USD
Selection: 9
error: invalid index.
Selection: (user canceled input)
Both approaches accomplish the same thing, it all depends on your program needs. Look things over and let me know if you have further questions.
In order to extract more than one field by name, you must get the names of the fields to extract, for example as command line arguments, determine the corresponding columns, and for each line of the CSV file, output the requested columns.
Below is a simple program that extracts columns from a CSV file and produces another CSV file. It does not use strtok() nor strchr() but analyses the line one character at a time to find the starting and ending offset of the columns and acts accordingly. The source file is passed as redirected input and the output can be redirected to a different CSV file.
Here is the code:
#include <stdio.h>
#include <string.h>
int find_header(const char *line, const char *name) {
int len = strlen(name);
int i, n, s;
for (i = n = s = 0;; i++) {
if (line[i] == ',' || line[i] == '\n' || line[i] == '\0') {
if (len == i - s && !memcmp(line + s, name, len))
return n;
if (line[i] != ',')
return -1;
s = i + 1;
n++;
}
}
}
int main(int argc, char *argv[]) {
char buffer[1002];
int field[argc];
char *name[argc];
int i, n;
if (argc < 2) {
printf("usage: csvcut FIELD1 [FIELD2 ...] < CSVFILE\n");
return 2;
}
// read the input header line
if (!fgets(buffer, sizeof buffer, stdin)) {
fprintf(stderr, "missing header line\n");
return 1;
}
// determine which columns to extract
for (n = 0, i = 1; i < argc; i++) {
int f = find_header(buffer, argv[i]);
if (f < 0) {
fprintf(stderr, "field not found: %s\n", argv[i]);
} else {
name[n] = argv[i];
field[n] = f;
n++;
}
}
// output new header line
for (i = 0; i < n; i++) {
if (i > 0)
putchar(',');
printf("%s", name[i]);
}
putchar('\n');
// parse the records, output the selected fields
while (fgets(buffer, sizeof buffer, stdin)) {
for (i = 0; i < n; i++) {
int j, s, f, start, length;
if (i > 0)
putchar(',');
// find field boundaries
for (j = s = f = start = length = 0;; j++) {
if (buffer[j] == ',' || buffer[j] == '\n' || buffer[j] == '\0') {
if (f == field[i]) {
start = s;
length = j - s;
break;
}
if (buffer[j] != ',')
break;
s = j + 1;
f++;
}
}
printf("%.*s", length, buffer + start);
}
putchar('\n');
}
return 0;
}
Sample run:
./csvcut Date Close < sample.csv
Date,Close 2020-11-12,15710.01
2020-11-11,15710.87
2020-11-10,15318
2020-11-09,15348.2
2020-11-08,15484.55
Note that fields cannot contain embedded commas. The program could be extended to handle quoted contents to support these.

Inconsistent reading of string from pipe

I read some data from a file, and send it through a pipe. When I read the data from the pipe, sometimes there's extra characters inside. The extra characters are also inconsistent, but normally is an extra "R" at the end.
The data I read from the file is correct, as it is always as it should be. It's only after reading it from the pipe that I encounter problems.
Could you help me find the error? I've been staring at this for ages and I can't find it.
This is the part of my code that is giving me trouble.
Thanks for your help.
int main (int argc, char **argv) {
int nClients;
int file_name_HTML[2];
create_pipes(file_name_HTML, server_access_request);
init_free_pipes();
nClients = getHTMLFilesIntoPipe(file_name_HTML);
int clients[nClients];
for(int i=0; i < nClients; i++)
{
if((clients[i] = fork()) == 0)
{
clientFunction(file_name_HTML, server_access_request);
}
}
.....
}
int getHTMLFilesIntoPipe(int *file_name_HTML)
{
int i, n = 0;
char (*lines)[MAXCHAR] = NULL;
FILE *fp;
fp = fopen("./data/listado_html.txt", "r");
if (!fp) { /* valdiate file open for reading */
err_exit("error: file open failed.\n");
}
if (!(lines = malloc (MAXLINES * sizeof *lines))) {
err_exit("error: virtual memory exhausted 'lines'.\n");
}
while (n < MAXLINES && fgets (lines[n], MAXCHAR, fp)) /* read each line */
{
char *p = lines[n]; /* assign pointer */
for (; *p && *p != '\n'; p++) {} /* find 1st '\n' */
if (*p != '\n') /* check line read */
{
int c;
while ((c = fgetc (fp)) != '\n' && c != EOF) {} /* discard remainder of line with getchar */
}
*p = 0, n++; /* nul-termiante */
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
for (int i = 0; i < n; i++)
{
write(file_name_HTML[WRITE], lines[i], strlen(lines[i]));
}
free(lines);
return n;
}
void clientFunction(int *file_name_HTML, int *server_access_request)
{
char fileName[MAXCHAR];
close(file_name_HTML[WRITE]);
//Read HTML file name
read(file_name_HTML[READ], fileName, MAXCHAR - 1);
printf("%s\n", fileName);
.......
}
Expected output:
abcd1.html
abcd2.html
abcd3.html
abcd4.html
abcd5.html
Current output:
abcd1.htmlR
abcd2.htmlR
abcd3.htmlR
abcd4.htmlR
abcd5.htmlR
It is because your string is not null(\0) terminated.
As you write to the pipe excluding null(\0) terminator.
write(file_name_HTML[WRITE], lines[i], strlen(lines[i])+1);
^--- +1 to include null character.
strlen returns the length excluding null terminator.

C read entire line of file [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I am trying to program a tool in C. Part of this program is to use a text file and read it line by line, while storing all lines into an array to have it available for future use.
That's what I have so far:
int main(){
FILE *fp = fopen("file.txt", "ab+");
if (fp == NULL) {
printf("FILE ERROR");
return 1;
}
int lines = 0;
int ch = 0;
while(!feof(fp)){
ch = fgetc(fp);
if(ch == '\n'){
lines++;
}
}
printf("%d\n", lines);
if (lines>0){
int i = 0;
int numProgs = 0;
char* programs[lines];
char line[lines];
FILE *file;
file = fopen("file.txt", "r");
while(fgets(line, sizeof(line), file) != NULL){
programs[i] = strdup(line);
i++;
numProgs++;
}
for (int j= 0; j<sizeof(programs); j++){
printf("%s\n", programs[j]);
}
fclose(file);
fclose(fp);
return 0;
}
My problem is im getting this output:
6 (the number of lines in the file)
Segmentation fault
How can I read a complete line by line , without knowing how long the line is in the beginning. in PHP I can do that very easily, but how can I do that in C?
Thanks for any hint!
fix like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void){
FILE *fp = fopen("file.txt", "r");//!
if (fp == NULL) {
fprintf(stderr, "FILE ERROR\n");
return 1;
}
int lines = 0;
int ch = 0;
int len = 0;//! length of line
int max_len = 0;//! max length of line
while((ch = fgetc(fp))!=EOF){//!
++len;
if(ch == '\n'){
if(max_len < len)
max_len = len;
++lines;
len = 0;
}
}
if(len)
++lines;
fprintf(stderr, "%d lines.\n", lines);
if (lines > 0){
int numProgs = 0;
char *programs[lines];//use malloc, char **programs = malloc(lines * sizeof(*programs));
char line[max_len+1];//!
rewind(fp);//!
while(fgets(line, sizeof(line), fp))
programs[numProgs++] = strdup(line);//!
for (int j= 0; j < numProgs; j++){//!
printf("%s", programs[j]);//!
free(programs[j]);//!
}
}
fclose(fp);
return 0;
}
If you truly want to read an unknown number of characters from an unknown number of lines and store those lines in an array (or, actually, in an object created from a pointer-to-pointer-to-char), then you have a number of options. POSIX getline is a line oriented input function (like fgets) which will read a line of text from the give file each time it is called, and will allocate sufficient storage to hold the line regardless of the length. (as a bonus getline returns the actual number of characters read, eliminating a subsequent call to strlen if the length is needed)
getline eliminates the need for repeated checks on whether fgets actually read the whole line, or just a partial. Further, if your lines are more than a few characters long, the buffered read provided by getline (and fgets) is quite a bit faster than character oriented input (e.g. fgetc). Don't get me wrong, there is nothing wrong with fgetc, and if your files are small and your lines short, you are not going to notice any difference. However, if you are reading a million lines of 500,000 chars each -- you will notice a significant difference.
As for an array, since you don't know how many lines you will read, you really need a pointer-to-pointer-to-char (e.g a double-ponter, char **array) so you can allocate some reasonable number of pointers to begin with, allocate and assign the lines to individual pointer until your limit is reached, then realloc array to increase the number of pointers available, and keep on reading/storing lines.
As with any code that dynamically allocates memory, your must (1) preserve a pointer to each block of memory allocated, so (2) the memory can be freed with no longer in use. You should also validate each allocation (and reallocation) to insure the allocations succeed. When using realloc, always use a temporary pointer so you can validate that realloc succeeds before assigning the new block to the original pointer. If you don't, and realloc fails, you have lost the pointer to your original block of memory that is left untouched, not freed, and you have just created a memory leak.
Lastly, always verify your memory use with a memory error check program such as valgrind on Linux. There are a number of subtle ways to misuse a block of memory.
Putting all that together, you could do something like the following. The code will read all lines from the filename provided as the first argument (or from stdin if no filename is given):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { MAXA = 128 }; /* initial allocation size, MAXA must be >= 1 */
int main (int argc, char **argv) {
char *line = NULL;
char **arr = NULL;
size_t i, maxa = MAXA, n = 0, ndx = 0;
ssize_t nchr = 0;
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
/* allocate MAXA pointers to char -- initially & validate */
if (!(arr = calloc (maxa, sizeof *arr))) {
fprintf (stderr, "error: virtual memory exhausted.\n");
return 1;
}
while ((nchr = getline (&line, &n, fp)) != -1) { /* read each line */
while (line[nchr-1] == '\n') line[--nchr] = 0; /* remove '\n' */
if (!(arr[ndx] = strdup (line))) { /* allocate, copy, add to arr */
fprintf (stderr, "error: virtual memory exhausted.\n");
break; /* leave read loop, preserving existing arr */
}
if (++ndx == maxa) { /* if allocation limit reached, realloc arr */
size_t asz = sizeof *arr;
void *tmp = realloc (arr, (maxa + MAXA) * asz);
if (!tmp) { /* validate realloc succeeded */
fprintf (stderr, "error: realloc, memory exhausted.\n");
break; /* preserving original arr */
}
arr = tmp; /* assign & zero (optional) new memory */
memset (arr + (maxa + MAXA) * asz, 0, MAXA * asz);
maxa += MAXA; /* update current allocation limit */
}
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
if (line) free (line); /* free mem allocated by getline */
for (i = 0; i < ndx; i++) /* output array */
printf (" arr[%4zu] : %s\n", i, arr[i]);
for (i = 0; i < ndx; i++) /* free allocated memory */
free (arr[i]); /* free each line */
free (arr); /* free pointers */
return 0;
}
Example Use/Output
$ ./bin/getline_realloc_arr < dat/words_554.txt
arr[ 0] : Aam
arr[ 1] : Aard-vark
arr[ 2] : Aard-wolf
arr[ 3] : Aaronic
...
arr[ 549] : Accompaniment
arr[ 550] : Accompanist
arr[ 551] : Accompany
arr[ 552] : Accompletive
arr[ 553] : Accomplice
Look things over and let me know if you have any questions.
Try Online
#include <stdio.h>
#include <stdlib.h>
char * readLine (FILE * file)
{
size_t len = 0;
int c = 0, i = 0;
long pos = ftell(file);
char * out = 0;
// read the whole line
do { c = fgetc(file); len++; }
while (c!='\0' && c!='\n' && c!=EOF);
// if the cursor didn't move return NULL
if (pos == ftell(file) && c == EOF) return 0;
// allocate required memory
out = (char*)malloc(len+1);
// rewind cursor to beginning of line
fseek (file, pos, SEEK_SET);
// copy the line
do { out[i++] = fgetc(file); }
while (c!='\0' && c!='\n' && c!=EOF);
// make sure there's \0 at the end
out[i] = '\0';
return out;
}
int main (void)
{
// FILE * file = fopen("test.txt", "r");
char * line = readLine(stdin);
while(line)
{
printf(line); // print current line
free(line); // free allocated memory
line = readLine(stdin); // recur
}
return 0;
}
Read up on malloc / realloc and friends.
A first approach for reading a single line might be something along the lines of the following (note that this is a toy program, and as such omits error-checking):
size_t line_length = 0;
char *line = NULL;
char ch;
while ((ch = fgetc(fp)) != '\n') {
line = realloc(line, line_length+1);
line[line_length++] = ch;
}
// Add null character at end of line
line = realloc(line, line_length+1);
line[line_length] = 0;
The biggest problem with this is that it's slow, and especially slow for long lines. A better approach would be to keep track of the allocated and written size, and exponentially-grow size of the array as necessary, and then trim to the actual required length at the end.
Also, it'd probably be better (and simpler) to use fgets for that approach.
For reading multiple lines, you can nest this approach.

Read file word by word and output WITH white spaces

The input text file is like so:
Hello my
name is
mark.
and
im
going
to
love
c!
Code:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]){
FILE *pFile;
char x[60];
pFile = fopen("test0.txt","r");
if(pFile != NULL){
while(fscanf(pFile, " %60s", x) == 1){
printf("%s",x);
}
}
}
Output text file is:
Hellomynameismark.andimgoingtolovec!
I want the Output to be like:
Hello my name is mark. and im going to love c!
Very new C programmer so only know the basics.
Edit----
int main(int argc, char *argv[]){
FILE *pFile;
char x[60],line[60];
pFile = fopen("test0.txt","r");
while(!feof(pFile)){
fgets(line, 60, pFile);
strtok(line, "\r\n");
printf("%s", line );
}
fclose(pFile);
Output:
Hello myname is mark.andim goingtolovec!
This does not leave spaces between new lines. However if I take out the strtok line the output will be like this:
Hello my
name is
mark.
and
im
going
to
love
c!
--Edit
.sp 2
.ce
This is an example file for formatting.
.sp 1
The above line
was formatted using a .ce 1 command, which means 'centre
the following line',
so it should appear in the
centre of the page.
The paragraph was separated from the heading using
a .sp 1 command to create a single blank line.
There should also be two blank lines above the centred heading to make reading it slightly easier.
The simple answer is:
while(fscanf(pFile, " %59[^\n]%*c", x) == 1)
Here %[^\n] uses the character class [stuff] to read everything up to the newline. %*c simply reads and discards the newline without adding it to the match count for fscanf.
However for line-oriented input, you should really use one of the line-oriented functions provided by the standard library (e.g. fgets or POSIX getline).
Using fgets & strtok
As you have taken from the comment, the use of feof is going to cause you nothing but grief. You will want to simply use the return of fgets to determine end of file. Here is an example that puts all the pieces of the puzzle together:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXWDS 20
#define MAXCHR 60
int main (int argc, char **argv) {
char line[MAXCHR] = {0};
char *words[MAXWDS] = {NULL};
FILE *pFile = NULL;
size_t i, index = 0;
/* open file for reading (if provided), or read from stdin */
if (!(pFile = argc > 1 ? fopen (argv[1], "r") : stdin)) {
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
while (fgets (line, 60, pFile))
{
char *p = line;
/* split line into tokens, stored in words[] */
for (p = strtok (p, " \r\n"); p; p = strtok (NULL, " \r\n")) {
words[index++] = strdup (p); /* allocate & copy */
if (index == MAXWDS) /* check pointer limit */
break;
}
}
if (pFile != stdin) fclose (pFile);
/* output in a single line */
for (i = 0; i < index; i++) {
printf (" %s", words[i]);
free (words[i]); /* free allocated memory */
}
putchar ('\n');
return 0;
}
Compile
gcc -Wall -Wextra -o bin/fgets_strtok fgets_strtok.c
Output
$ ./bin/fgets_strtok dat/hellomark.txt
Hello my name is mark. and im going to love c!
Note: to simply print the line out with spaces between the words, as long as there is already a space between each of the words in each line, there is no reason to go to the trouble to separate each line into individual words, you can simply print the contents of each line out in a space separate fashion. The only issue you run into using fgets is that it will also read the newline (or carriage return, newline) as part of the string. That is simple to remove. You can replace the entire read loop with:
while (fgets (line, 60, pFile))
{
size_t len = strlen (line);
/* strip trailing newline (or carriage return newline ) */
while (len && (line[len-1] == '\n' || line[len-1] == '\r'))
line[--len] = 0; /* overwrite with null-terminating char */
words[index++] = strdup (line); /* allocate & copy */
if (index == MAXWDS) /* check pointer limit */
break;
}
Output
$ ./bin/fgets_mark <dat/hellomark.txt
Hello my name is mark. and im going to love c!
Standard Way to Read from File Only (not File or stdin)
I apologize for the getting ahead of you a bit by including a way to either open a file (if provided on the command line) or read from stdin (if no filename was provided). The standard way is to first check that the correct number of arguments were provided on the command line, and then open the filename provided, validate it is open, and then process input. What I did was throw a ternary operator into the fopen command that said.
pFile = argc > 1 ? fopen (argv[1], "r") : stdin
The right side of the '=' sign is a ternary operator, which is simply a shorthand for if -> then -> else. What it does is ask is argc > 1? If that tests true, then pFile = fopen (argv[1], "r");. If argc > 1 tests false, then pFile = stdin;
See if the standard way makes more sense:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXWDS 20
#define MAXCHR 60
int main (int argc, char **argv) {
char line[MAXCHR] = {0};
char *words[MAXWDS] = {NULL};
FILE *pFile = NULL;
size_t i, index = 0;
/* validate sufficient input */
if (argc < 2 ) {
fprintf (stderr, "error: insufficient input, usage: %s filename\n", argv[0]);
return 1;
}
/* open file provided on command line for reading */
pFile = fopen (argv[1], "r");
if (!pFile) {
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
while (fgets (line, 60, pFile)) /* read each line in file */
{
size_t len = strlen (line);
/* strip trailing newline (or carriage return newline ) */
while (len && (line[len-1] == '\n' || line[len-1] == '\r'))
line[--len] = 0; /* overwrite with null-terminating char */
words[index++] = strdup (line); /* allocate & copy */
if (index == MAXWDS) /* check pointer limit */
break;
}
if (pFile != stdin) fclose (pFile);
/* output in a single line */
for (i = 0; i < index; i++) {
printf (" %s", words[i]);
free (words[i]); /* free allocated memory */
}
putchar ('\n');
return 0;
}
A simple state machine does the trick - no line length limitation.
#include <stdio.h>
int main(void) {
FILE *pFile = fopen("test0.txt","r");
if(pFile != NULL) {
int previous_isspace = 0;
int ch;
for (;;) {
ch = fgetc(pFile);
if (ch == EOF) break;
if (isspace(ch)) {
previous_isspace = 1;
} else {
if (previous_isspace == 1) {
fputc(' ', stdout);
}
previous_isspace = 0;
fputc(ch, stdout);
}
}
fclose(pFile);
fputc('\n', stdout); // If code should have a \n at the end
}
}
I think, It is sufficient take a look am i miss anything.
if(pFile != NULL){
// while(fscanf(pFile, " %60s", x) == 1){
while (fgets(x, sizeof(x), pFile) != NULL) {
token = strtok(x,"\r\n");
if(token != NULL)
printf("%s ",x);
else
printf("%s",x);
}
fclose(pFile);
}

Error LNK2019: unsresolved external symbol

Hey I'm getting this error and I'm not sure why. I'm pretty new to C so hopefully it won't be too complicated.
heres my main
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "binToDec.c"
#include "verifyMIPS.c"
int binToDec(char string[], int begin, int end);
int verifyMIPS (char string[]);
int main(int argc, char *argv[])
{
char buffer[BUFSIZ];
FILE* fptr; /* file pointer */
int lineNum = 0;
int i;
char *count;
/* Was a file passed in a parameter (e.g., on the command line)? */
if ( argc == 2 )
{
/* Open the file for reading */
if ((fptr = fopen (argv[1], "r")) == NULL)
{
fprintf (stderr, "Error: Cannot open file %s.\n", argv[1]);
return 1;
}
}
else /* No file passed in; use standard input. */
fptr = stdin;
/* Continuously read next line of input until EOF is encountered.
* Each line should contain only 32 characters and newline.
*/
while (fgets (buffer, BUFSIZ, fptr)) /* fgets returns NULL if EOF */
{
lineNum++;
if (strlen (buffer) == 33 && buffer[32] == '\n')
buffer[32] = '\0'; /* convert newline to null byte */
else
{
(void) fprintf (stderr,
"Error: line %d does not have 32 chars.\n", lineNum);
continue; /* error: get next line */
}
/* Verify that the string is 32 0's and 1's. If it is, do
* various tests to ensure that binToDec works correctly.
* If the string contains invalid characters, print an error
* message.
*/
/* CODE MISSING !!! */
int i;
for(i=0; i<33; i++)
{
if(verifyMIPS(buffer[i])==1)
{
binToDec(buffer[i],0,32);
}
else
{
(void) fprintf (stderr,
"Error: line %d does not have 32 chars.\n", lineNum);
continue; /* error: get next line */
}
}
}
/* End-of-file encountered; close the file. */
fclose (fptr);
return 0;
}
and now my two other files
#include <string.h>
int verifyMIPSInstruction (char * instr)
/* returns 1 if instr contains 32 characters representing binary
* digits ('0' and '1'); 0 otherwise
*/
{
int i;
for(i = 0; i<32; i++)
{
if(instr[i] == '1' || instr[i] == '0')
{
return 1;
}
}
if(instr[32] != '\0')
{
(void) printf("is not an instruction");
}
return 0;
}
and
int binToDec(char string[], int begin, int end)
{
int i, remainder;
int j = 1;
int decimal = 0;
i = atoi(string);
while(i !=0)
{
remainder = i%10;
decimal = decimal+remainder*j;
j=j*2;
i = i/10;
}
printf("equivalent decimal value: %i", decimal);
return decimal;
}
the output I'm getting is
error LNK2019: unresolved external symbol _verifyMIPS referenced in function _main
I'm also using the Microsoft Visual Studios developer command prompt for all of this.
Thanks for your help!
EDIT: new problem, When I run the code, and I put in 32 characters, it will not run verifyMIPSInstructions or binToDec. It will only give me the error that it doesn't have 32 characters when it clearly does. Any advice?
I agree with the linker. I don't see the verifyMIPS() function ether. Perhaps main() should call verifyMIPSInstruction() instead?

Resources