I've got a file with 2-3 lines, and every line I want to store in a char* variable, then translate it and store it to other appropriate variables.
not in unix, just in c, there's a fscanf(%d,%s,%s, 1,2,3); and thats it, but in unix it is somewhat weird.
For example: a abc 12 12
Storing it in char msg[20], and then msg[20] will be stored in 4 variables, one char, one char* and two integers. How can It be done?
Here what I got so far:
int ret_in, in1,file;
char buffer1[BUF_SIZE];
int i =0;
char fn[5] = "file";
char msg[20];
file = open(fn,O_WRONLY|O_CREAT,0644);
//msg = "test";
while(((ret_in = read (file, &buffer1, BUF_SIZE)) > 0))
{
for(i; i<ret_in; i++)
{
if(buffer1[i]!='\n')
msg[i] = buffer1[i];
}
}
printf("%s", msg); //TEST: check msg
close(file);
It stores it fine in the msg variable, but if it composed of 4 'items' i want to store in different variables, how can I do it efficiently?
You can use fopen() to open a file and get a pointer to a file stream. This pointer can be passed to fgets() to retrieve lines from the file and store them in a buffer. This buffer can then be parsed by using sscanf().
Here is an example of how this might work. Note that here I am using arrays to store the components of the fields from each line; you may have different requirements.
#include <stdio.h>
#include <stdlib.h>
#define MAX_LINES 100
int main(void)
{
FILE *fp = fopen("my_file.txt", "r");
if (fp == NULL) {
perror("Unable to open file");
exit(EXIT_FAILURE);
}
char buffer[1000];
char id[MAX_LINES];
char msg[MAX_LINES][10];
int val_a[MAX_LINES];
int val_b[MAX_LINES];
size_t lines = 0;
while (fgets(buffer, sizeof buffer, fp) != NULL) {
if (sscanf(buffer, "%c%9s%d%d",
&id[lines], msg[lines], &val_a[lines], &val_b[lines]) == 4) {
++lines;
}
}
for (size_t i = 0; i < lines; i++) {
printf("Line %zu: %c -- %s -- %d -- %d\n",
i+1, id[i], msg[i], val_a[i], val_b[i]);
}
fclose(fp);
return 0;
}
Using this text file as input:
A abc 12 34
B def 24 68
C ghi 35 79
gives the following output:
Line 1: A -- abc -- 12 -- 34
Line 2: B -- def -- 24 -- 68
Line 3: C -- ghi -- 35 -- 79
Related
Suppose I have a txt file that looks like this, where there is only one space between the number and the string:
123 apple
23 pie
3456 water
How can I save apple, pie, and water to an array?
You have a many solutions for this case, i propose some solutions for reading the string from your file:
using fscanf, see one example: ``scanf() and fscanf() in C
using fgets to read line by line then using ssanf to read the string from each line, see the examples: sscanf() and fgets
For storing the string in an array, you can use the 2D array or the array of char pointer:
char str_array[100][256]; // maximum 100 row and max length of each row ups to 256.
// OR
// You have to allocate for two declarations, and do not forget to free when you do not still need to use them below
char *str_array[100];
char **str_array;
For copy string to string, you should use strcpy function. Do not use = to assign string to string in c.
For example, i use fscanf:
#include <stdio.h>
#include <string.h>
int main()
{
FILE *fp = fopen("input.txt", "r");
if(!fp) {
return -1;
}
char line[256];
char array[100][256];
int a, i = 0;
while(fscanf(fp, "%d %255s",&a, line) == 2 && i < 100) {
strcpy(array[i], line);
i++;
}
// print the array of string
for(int j = 0; j < i; j++ ) {
printf("%s\n", array[j]);
}
fclose(fp);
return 0;
}
The input and output:
#cat input.txt
123 apple
23 pie
3456 water
./test
apple
pie
water
//This code will read all the strings in the file as described
FILE *fp = fopen("file.txt","r"); //open file for reading
int n = 3;
char *list[n]; //for saving 3 entities;
int i,a;
for(i=0;i<n;i++)
list[i] = (char *)malloc(sizeof(char)*10); //allocating memory
i = 0;
while(!feof(fp))
fscanf(fp," %d %s",&a,list[i++]);
printf("%s %s %s\n",list[0],list[1],list[2]);
I'm looking to sort a txt file that contains 1199 numbers in 10 columns per row, and I know that the last row will have 10 or fewer columns.
However, I'm getting 11 columns on the first row.
Thanks for the help.
#include <stdio.h>
#define t 1024
int main()
{
int i=0, c;
char p[t];
FILE *f;
f = fopen("CMB.txt", "r");
while ((c = getc(f)) != EOF)
{
fscanf(f, "%s", p);
if(i%10 == 0 && i > 0)
{
printf("\n");
}
printf("%s ", p);
if (c == '\n')
{
i++;
}
}
printf("\n %d", i+1);
fclose(f);
}
When I try your code it prints correctly the 10 columns you are expecting , perhaps you didn't recompile after modifying.
This is your code , I only removed the file reading and printing char.
#include <stdio.h>
int main()
{
int i=0;
//, c;
// char p[t];
// FILE *f;
// f = fopen("CMB.txt", "r");
while (i<30)
{
// fscanf(f, "%s", p);
if(i%10 == 0 && i > 0)
{
printf("\n");
}
printf("%d ", i);
// if (c == '\n')
// {
i++;
// }
}
// printf("\n %d", i+1);
// fclose(f);
}
Continuing from my earlier comment, when reading columns of data from a text file, it is generally better to read a line of input at a time with a line-oriented input function such as fgets or POSIX getline and then to parse the data from the buffer filled with sscanf (or walking a pointer down the buffer picking out what you need)
In your case when dealing with a fixed number of columns (10) where less than all values may be present, sscanf provides a way to determine exactly how many values are present in each row while allowing you to make use of the data if less than 10 are present.
sscanf (as with all scanf functions) returns the number of successful conversions took place based on the format string you provide (or returning EOF if the end of input is encountered before a conversion takes place). If you want to read 10-integer values from each line of data into an integer array names arr, you could use fgets to read the line into a buffer (say buf) and then separate the integer values head in buf with sscanf, e.g.
...
while (fgets (buf, MAXC, fp)) { /* read each line into buf */
/* parse into integer values with sscanf saving return */
int rtn = sscanf (buf, "%d %d %d %d %d %d %d %d %d %d",
&arr[0], &arr[1], &arr[2], &arr[3], &arr[4],
&arr[5], &arr[6], &arr[7], &arr[8], &arr[9]);
...
Then you simply validate the return (rtn) using whatever if..else or switch... statements you need. Here we can simply sum the number of values read and output the row number for any row containing less than COL number of values for purposes of this example, e.g.
...
if (rtn > 0) /* did at least one conversion take place? */
n += rtn; /* increment count of values read */
if (rtn < COL) /* were less than COL values read? */
printf ("row[%zu]: %d values read.\n", row + 1, rtn);
row++; /* increment row count */
}
Putting it altogether, you could do something like the following:
#include <stdio.h>
#define COL 10
#define MAXC 1024
int main (int argc, char **argv) {
char buf[MAXC];
int arr[COL] = {0};
size_t n = 0, row = 0;
/* 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 into buf */
/* parse into integer values with sscanf saving return */
int rtn = sscanf (buf, "%d %d %d %d %d %d %d %d %d %d",
&arr[0], &arr[1], &arr[2], &arr[3], &arr[4],
&arr[5], &arr[6], &arr[7], &arr[8], &arr[9]);
if (rtn > 0) /* did at least one conversion take place? */
n += rtn; /* increment count of values read */
if (rtn < COL) /* were less than COL values read? */
printf ("row[%zu]: %d values read.\n", row + 1, rtn);
row++; /* increment row count */
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
printf ("%zu values read from file.\n", n);
}
Example Input File
Reading a data file with 10-integers per-row for 119 rows and reading a final row with 9-integers as you describe in your question, you could use an input file like:
$ head -n4 dat/1199_10col.txt; echo "<snip>"; tail -n4 dat/1199_10col.txt
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30
31 32 33 34 35 36 37 38 39 40
<snip>
1161 1162 1163 1164 1165 1166 1167 1168 1169 1170
1171 1172 1173 1174 1175 1176 1177 1178 1179 1180
1181 1182 1183 1184 1185 1186 1187 1188 1189 1190
1191 1192 1193 1194 1195 1196 1197 1198 1199
Example Use/Output
Running the code against the above file would yield the expected results of reading 1199 values, 10-integers per-row with 9-integers read from the final row with notice of the short row:
$ ./bin/read10col <dat/1199_10col.txt
row[120]: 9 values read.
1199 values read from file.
While there are many ways to do this, and arguably using fgets with strtol provides opportunity for finer grained error detection, this is probably one of the more simple and straight-forward approaches.
Look things over and let me know if you have further questions.
Why do you read a character before the first number? Why do you only increment i if this character is a newline?
If the file contains just numbers, you can simplify the code this way:
#include <stdio.h>
int main() {
int i, n;
FILE *f = fopen("CMB.txt", "r");
if (f != NULL) {
for (i = 0; fscanf(f, "%d", &n) == 1; i++) {
/* output the number followed by a tab, or by a newline every 10 numbers */
printf("%d%c", n, "\t\n"[i % 10 == 9]);
}
if (i % 10 != 0) {
printf("\n");
}
fclose(f);
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE * fp;
char *line;
int i;
size_t len = 0;
fp = fopen("CMB.txt", "r");
while (getline(&line, &len, fp) != -1)
{
fscanf(fp, "%s", line);
if(i%10 == 0 && i > 0)
{
printf("\n");
}
printf("%s\t ", line);
i++;
}
printf("\n\n%d", i);
fclose(fp);
return 0;
}
So now the numbers from the file are sorted in 10 columns, but the last line only have 8 columns when it should have 9. When I count (i) to see how many lines the while loop reads it only reads 1198, but i should read 1199. So I'm guessing it's skipping the first line? Appreciate the help :D
i'm trying to read variables from a txt file.
The file .txt is like:
john 10
mark 230
peter 1
I would like to transfer and save this values in an array, for example array[0] = 10, array[1] = 230 etc without minding of names. I pasted my code below and I would like to know how can i edit it using this code below
int conf[4], i = 0, c;
FILE *file_conf;
file_conf = fopen("conf.txt", "r");
if(file_conf == NULL){
fprintf(stderr, "Error\n");
exit(EXIT_FAILURE);
} else {
while((c = fgetc(file_conf)) != EOF) {
fscanf(file_conf, "%d", &conf[i]);
printf("%d\n", conf[i]);
i++;
}
}
You should not be using fgetc() at all--that gets a single character. Instead, add the name format to your fscanf(), something like this:
char name[100];
fscanf(file_conf, "%s %d", name, &conf[i]);
You can prefix scanf() family conversion specifiers with * to suppress assignment. Note that in the posted code, failure to check the value returned from fscanf() could lead to problems with malformed input. Also, the input loop should exit when the array index i grows too large to avoid buffer overflow. The following code exits the loop when i is too large, or when malformed input is encountered:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int conf[4], i = 0;
FILE *file_conf;
file_conf = fopen("conf.txt", "r");
if(file_conf == NULL){
fprintf(stderr, "Error\n");
exit(EXIT_FAILURE);
} else {
while(i < 4 && fscanf(file_conf, "%*s%d", &conf[i]) == 1) {
printf("%d\n", conf[i]);
i++;
}
}
fclose(file_conf);
return 0;
}
Output using using the posted sample input:
10
230
1
I am trying to read in a file that is formatted like this sample:
3 3 1.5 50
0 2 46.0 0
* 1 46.0 1
2 * 46.0 0
0 0 50.0 0
* * 42.0 0
2 2 36.1
2 1 42 0
0 1 48.0 0
1 0 48 0
First I want to store the contents of the file in a string. Then, I want to scan through the string and see if there are any asterisks *. For some reason I can't get it to store as a string. Whenever I try to print the string, it gives me blank lines. Is there an easy way to read in data from a file and store it into a string? I will later convert the numerical data into arrays.
Code snippet:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]){
FILE *id; //Input Data
double *detect;
int nx, ny, i, j, k, n, count, t, frequency;
double a;
char val;
n = 0;
id = fopen(argv[1], "r");
frequency = atoi(argv[2]);
if(id){
fscanf(id, "%d %d %lf %d", &nx, &ny, &a, &tn);
}
detect = (double *) malloc(nx*nx*4*sizeof(double));
if(id){
for(i=0; i<2; i++){
fscanf(id,"%s", (detect+i));
}
}
//~ The rest of the code is left out ~
return 0;
}
You can put the data into a string like this.
It uses the following:
fgets to read each line from the file and store in a string buffer.
malloc to allocate space for string, char *detect on the heap. Uses realloc to reallocate more space when needed.
strcat to append buffer to the pointer *detect.
free to deallocate memory requested by malloc().
The code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFSIZE 100
#define STARTSIZE 10
int
main(int argc, char *argv[]) {
FILE *id;
char *detect;
char buffer[BUFFSIZE];
size_t slen, currsize = STARTSIZE, len = 0;
const char *separate = " ";
id = fopen(argv[1], "r");
if (!id) {
fprintf(stderr, "%s\n", "Error reading file");
exit(EXIT_FAILURE);
}
detect = malloc(currsize * sizeof(*detect));
if (!detect) {
printf("Error allocating memory\n");
exit(EXIT_FAILURE);
}
*detect = '\0';
while (fgets(buffer, BUFFSIZE, id) != NULL) {
slen = strlen(buffer);
len += slen-1;
if (slen > 0) {
if (buffer[slen-1] == '\n') {
buffer[slen-1] = '\0';
} else {
printf("Error: Exceeded Buffer length of %d.\n", BUFFSIZE);
exit(EXIT_FAILURE);
}
}
if (currsize == len) {
currsize *= 2;
detect = realloc(detect, currsize * sizeof(*detect));
if (!detect) {
printf("Error reallocating memory\n");
exit(EXIT_FAILURE);
}
}
strcat(detect, separate);
strcat(detect, buffer);
}
printf("Your string = %s\n", detect);
free(detect);
return 0;
}
As I Understand from the above code, You declared detect pointer as Double. In 2nd fscanf you are using "%s" to read data from files as string But detect pointer is Double type, which is causing the problem. Declare the detect pointer as char.
char *detect;
What I would do is create a structure of all the data type being stored in a file and create an array of that struct depending on the number of lines in the file,then using a loop I will use fread to read data into those structures and check my each data type after explicit conversion to int of all the data types with ASCII value of asterisk.
There are several ways to do so... You can use fscanf, regular expressions, tokenizers, parse generators, finite state machines...
All have advantages and disavantages... fscanf can misbahave with invalid inputs, regular expressions might take too long to parse the whole file, a tokenizer is a complex tool and you might take a while to learn (Flex is the guy for you), and to use FSM you need to really really know what you are doing...
Trying to create a program that takes in a text file and reads it line by line. It then finds the two integers that are on each line and adds them together. It then outputs the new line with the original string and total to a new text file. I need help adding the two integers, getting them from each line, and then putting the new line to a text file.
input text file
good morning hello 34 127
ann 20 45
10 11
fun program and you find the same 90 120
news paper said that 56 11
how do you like 20 5
line number 90 34
Outputs first like would look like: and then continue on
good morning hello 161
Code:
int processTextFile(char * inputFileName, char * outputFileName)
{
FILE *fp = fopen(inputFileName, "r");//open file to to read
char buff[1024];
char *p, *p1;
int num;
while (fgets(buff, 1024, fp)!=NULL)
{
printf("%s\n", buff);
while(scanf(buff, "%*[^0-9]%d", &num)== 1)
printf("%d\n", num);
//fscanf(fp, "%s", buff);
}
return 0;
}
EDIT!!!!::
So now that I've been able to accomplish this. How would I sort it by the number produced? for example:
Time is money 52
here I am 3
21
Would output to a new text file in order like
here I am 3
21
Time is money 52
My version using strcspn() is supposed to work with stdin for input and stdout for output. (so you can do executable <textfile >newtextfile)
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char line[1000];
while (fgets(line, sizeof line, stdin)) {
char *ptr;
size_t x = strcspn(line, "0123456789");
if (line[x]) {
errno = 0;
int n1 = strtol(line + x, &ptr, 10);
if (*ptr && !errno) {
errno = 0;
int n2 = strtol(ptr, &ptr, 10);
if (*ptr && !errno) {
int n3 = n1 + n2;
printf("%.*s%d\n", (int)x, line, n3);
} else {
printf("%s", line); // line includes ENTER
}
} else {
printf("%s", line); // line includes ENTER
}
} else {
printf("%s", line); // line includes ENTER
}
}
return 0;
}
The same version without the error checking
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char line[1000];
while (fgets(line, sizeof line, stdin)) {
char *ptr;
size_t x = strcspn(line, "0123456789");
int n1 = strtol(line + x, &ptr, 10);
int n2 = strtol(ptr, &ptr, 10);
int n3 = n1 + n2;
printf("%.*s%d\n", (int)x, line, n3);
}
return 0;
}
The approach should be:
open two files, one for input, one for output.
use sscanf() to read the input buffer.
scan the leading string, and then two number.
if previous sscanf() fails, only check for two number.
if either of the above scanning is success, print the sum to the output file.
A sample code, should look like
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
FILE *fpin = fopen("ipfile", "r");//open file to to read
if (!fpin)
{
printf("Error in ipfile opening\n");
exit (-1);
}
FILE *fpout = fopen("opfile", "w");//open file to to write
if (!fpout)
{
printf("Error in opfile opening\n");
exit (-1);
}
char buff[1024] = {0};
char str[1024] = {0};
int num1 =0, num2= 0;
while (fgets(buff, 1024, fpin)!=NULL)
{
memset(str, 0, sizeof(str));
//printf("%s\n", buff);
if(sscanf(buff, "%[^0-9]%d %d", str, &num1, &num2)== 3)
fprintf(fpout, "%s %d\n", str, (num1+num2));
else if (sscanf(buff, "%d %d", &num1, &num2)== 2)
fprintf(fpout, "%d\n", (num1+num2));
}
return 0;
}
Note:
The above procedure, is a kind of workaround. If the data pattern in the file changes, lot of changes will be required to maintain a code like that. Instead of usinf sscnaf(), for a better and roubust approach, you should
read the line from file
start tokenizing the input buffer (strtok()) and check for ints as tokens (strtol()).
save the returned tokens and ints seperately.
once the strtok() returns NULL, you print the string tokens and the sum of the ints to the o/p file.
I intend not to change your code completely, so I just added some snippets for improvement.
int processTextFile(char *inputFileName, char *outputFileName) {
FILE *fp = fopen(inputFileName, "r");
FILE *out = fopen(outputFileName, "w");
char line[1024];
if (!fp) {
perror(inputFileName);
return;
}
while (fgets(line, sizeof(line), fp) != NULL) {
int num1 = 0, num2 = 0;
char textPart[1024] = "";
if ( !sscanf(line, "%[a-zA-Z' ']%d%d", textPart, &num1, &num2) {
sscanf(line, "%d%d", &num1, &num2);
}
fprintf(out, "%s %d\n", textPart, num1 + num2);
}
fclose(fp);
fclose(out);
}
Explanation:
I scanned the text file, extracted the text part and the two ints. Since I noticed that the ints are placed at the end of each line, I just used sscanf() for that matter.
sscanf(line, "%[a-zA-Z' ']%d%d", textPart, &num1, &num2);
Here, "%[a-zA-Z' ']%d%d" format specifiers means to get only alphabets and spaces.
Since it will only get letters and spaces, the line "10 11" in your input file won't be put to num1 and num2. Because the code inspects first for a string containing letters and spaces. Since 10 and 11 are not of the qualified types, then the line is just skipped.
That's why I added an if-else statement, which checks if sscanf wrote anything to memory. If sscanf returned 0, then it means that no text part is present. Just digits. So the program will scan the two digits.
if ( !sscanf(line, "%[a-zA-Z' ']%d%d", textPart, &num1, &num2) ) {
sscanf(line, "%d%d", &num1, &num2);
}
I also added file checking for input file. It checks if file doesn't exist or can't be opened by the filestream.
if (!fp) {
perror(inputFileName);
return;
}
Here is the content of output file after execution:
good morning hello 161
ann 65
21
fun program and you find the same 210
news paper said that 67
how do you like 25
line number 124