I'm trying to print an int array on a file but it is giving me an error.
write_error:Bad address.
My int array is something like :
1 2 3 4 5 6 7 8 9
And I want to print it on a file as follows :
1 2 3
4 5 6
7 8 9
This is the code I'm using :
void printToFile(int listBoard[]) {
int file_write;
char buffer[100];
char buffer2[10];
if ((file_write = open("./board.txt", O_WRONLY | O_CREAT | O_TRUNC, 0700)) < 0) {
err_sys("error output file");
}
if (write(file_write, snprintf(buffer2, 10, "%d",listBoard[2]), 18) != 18){
err_sys("write_error");
}
if (close(file_write) != 0){
err_sys("error close write");
}
}
I also tried (char) but it converts the int to the ascii char.
Could you tell me what I'm missing?
Edit
My file output is :
3#\00\00펈㰙\00ጠ
Code edited :
void printToFile(int listBoard[]){
int file_write;
char buffer[100];
int value;
int cont = 0;
char buffer2[10];
if ((file_write = open("./board.txt", O_WRONLY | O_CREAT | O_TRUNC, 0700)) < 0) {
err_sys("error output file");
}
int len = snprintf(buffer2, 10, "%d", listBoard[2]);
if (write(file_write, buffer2, len) != len) {
err_sys("write_error");
}
if (close(file_write) != 0) {
err_sys("error close write");
}
}
Output file :
3
Last edit
This is how I did now to print it as the output that I want
if ((file_write = open("./board.txt", O_WRONLY | O_CREAT | O_TRUNC, 0700)) < 0) {
err_sys("error output file");
}
for (int index = 0; index < SIZE_BOARD; index++) {
if (cont == 3) {
int len = snprintf(buffer2, 1, "%d \n", ' ');
if(write(file_write, buffer2, len) != len) {
err_sys("write_error");
cont=0;
}
}
int len = snprintf(buffer2, 10, "%d ", listBoard[index]);
if (write(file_write, buffer2, len) != len) {
err_sys("write_error");
cont++;
}
}
if(close(file_write) != 0) {
err_sys("error close write");
}
But it is not doing the \n correctly. What I'm missing?
The definition of write is as follows:
ssize_t write(int fd, const void *buf, size_t count);
The definition of snprintf is as follows:
int snprintf(char *str, size_t size, const char *format, ...);
Now you're feeding snprintf to where write is expecting void *buf. i.e. the address to where the data is.
So you'll have to do
snprintf(buffer2, 10, "%d", listBoard[2]);
then
write(file_write, buffer2, 18);
EDIT:
That will fix the syntax error. Now semantically you can see that you're writing 10 bytes to buffer2 but you're writing 18 to the file. This will fill the file with junk. So i suggest.
int len = snprintf(buffer2, 10, "%d", listBoard[2]);
write(file_write, buffer2, len);
EDIT 2:
int len = snprintf(buffer2, 1, "%d \n", ' ');
First off your format specifier has 3 bytes while you're only writing 1 byte to the buffer2. Second, why is your argument ' ' when you're supposed to give the listBoard[n]?
Use dprintf() to write formatted strings to files:
dprintf(file_write, "%d", listBoard[2]);
dprintf will handle all the write stuff for you, so this is the only call you need with open and close.
dprintf is the fprintf for file descriptors. More informations here: https://linux.die.net/man/3/dprintf
The snprintf (and family) functions returns an integer.
You use this integer in the write call as a pointer to a buffer. That will lead to undefined behavior.
Call snprintf separately, and then pass buffer2 as the second argument. And use strlen to get the actual length of the string in buffer2, not hard-code the magic number 18 which will lead to reading from out-of-bounds and another case of UB.
First of all snprintf returns an integer that is the number of chars that would have been written if the string were not truncated (as you can read on the snprintf manual)
you cannot then use it in the write command. You can then use:
if ( snprintf(buffer2, 10,"%d",listBoard[2]) >= 10 ) {
/* handle truncation error*/
}
if(write(file_write,buffer2,18)!=18){
err_sys("write_error");
Anyway since buffer2 is maximum 10 characters why do you expect to write 18 bytes?
Other possible error: buffer2 should be at least of 10 + 1 byte for null termination.
You never specify that you must use raw file descriptors, so let's port your code up one level to C's standard library's FILE abstraction. It's easier to work with.
void printToFile(const int listBoard[]) {
FILE * const out = fopen("board.txt", "wt");
if (out == NULL) {
err_sys("error output file");
}
for(int j = 0; j < 3; ++j) {
for (int i = 0; i < 3; ++i)
fprintf(out, "%d ", listBoard[3 * j + i]);
fprintf(out, "\n");
}
fclose(out);
}
Note that this uses loops to iterate over the elements of the board array, this seemed to be missing from your original code and part of the problem you had with it.
This prints:
1 2 3
4 5 6
7 8 9
There's a trailing space on each line due to me being lazy, but hopefully that's fine. Also I omitted some inner error checking.
Related
I am trying to read ints from stdin line by line and store this into an array. I will know that I am done reading input when I get an empty line. However, when I run this code I don't seem to be exiting the loop because the program just hangs. What am I doing wrong here?
int *nums;
const int datacount = 10000;
nums = malloc(sizeof(int) * datacount);
if (!nums) {
perror("Error allocating memory");
abort();
}
memset(nums, 0, sizeof(int)*datacount);
int cnt = 0;
char line[64];
while ((fgets(line, sizeof line, stdin) != NULL) && (line[0] !='\n') ) {
if (sscanf(line, "%d", &nums[cnt]))
{
cnt++;
fflush(stdout);
}
}
Program will hang on sample input:
1
6
5
4
2
3
8
7
\n
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
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...
For example, I code :
fp = popen("wc -l < myfile", "r");
But myfile should be any file's name which is parsed to this project. It could be file abc.txt or 123.txt or xy.txt etc.
Then I want to get the output of executing this wc -l < myfile. But the problem is that I don't know which function in C can help me to parse the name of the myfile to this shell command and I can also get the output.
Can anyone gives me some suggestions?
Edit:
The file I want to read is very large. I want to read its data into an array.I cannot use list to store it, because it is too slow to locate a specific data in list. The problem is that if I use one dimensional array to malloc() memory space to the array, there is no enough continuous memory space on the laptop. Therefore, I plan to use two dimensional array to store it. So I have to get the num of lines in the file and then decide the size of each dimensional in this array via log.
Thanks for all answers. This project is about reading two files. The first file is much larger than the second file. The second file is like:
1 13 0
2 414 1
3 10 0
4 223 1
5 2 0
The third num in each line is called "ID". For example, num "1" has ID 0, num "2" has ID 1, num "3" has ID "0". (Ignore the middle num in each line)
And the first file is like:
1 1217907
1 1217908
1 1517737
1 2
2 3
2 4
3 5
3 6
If each num in the first file has the ID "0", I should store the both of num in each line into an data structure array. For example, we can see that num "1" has ID "0" in second file, so I need to store:
1 1217907
1 1217908
1 1517737
1 2
from my first file into the data structure array. The num "2" has ID"1" but num "3" has ID "0" and num "4" has ID "1", so need to store : 2 3 but not store 2 4 from my first file. That's why I need use array to store the two files. If I use two arrays to store them, I can check whether this num's ID is "0" fast in the array belongs to second file because using array is fast to locate a specific data, the index can be the value of the num directly.
I think, you need to make use of snprintf() to generate the string to be passed to popen() first and then you can call popen() with that string.
Pseudo-code
char buf[32] = {0};
snprintf(buf, 32, "wc -l < %s", myfile);
fp = popen(buf, "r");
EDIT
To make it work for any length of myfile
int len = strlen(myfile) + strlen("wc -l < ") + 1;
char *buf = malloc(len);
snprintf(buf, len, "wc -l < %s", myfile);
fp = popen(buf, "r");
...
free(buf);
Note: As mentioned by Ed Heal in the comment, the 32 here is used here for just demo purpose. You should choose your temporary array length based on the length of the string held by myfile, plus the mandatory characters, plus null terminator, obviously.
If you're not going to do this yourself (without a shell), which you should, at least pass the filename in such a way that the shell will only ever interpret it as data rather than code to avoid potential for security incidents.
setenv("filename", "myfile"); /* put filename in the environment */
fp = popen("wc -l <\"$filename\"", "r"); /* check it from your shell script */
Forget popen - do it yourself
i.e.
FILE *f = fopen(argv[1], "r");
int lines = 0;
int ch;
while ((ch = fgetc(f)) != EOF) {
if (c == '\n') lines++;
}
EDIT - As the poster wants to load the whole file into memory
Add the checking for errors
FILE *f = fopen(argv[1], "r");
struct stat size;
fstat(fileno(f), &size);
char buf = malloc(size.st_size)
fread(buf, size.st_size, 1, f);
fclose(f);
All of the code below is untested. If I find time to test, I'll remove this caveat.
You can create your own wrapper to popen() to allow you to form an arbitrary command.
FILE * my_popen (const char *mode, const char *fmt, ...) {
va_list ap;
int result = 511;
for (;;) {
char buf[result+1];
va_start(ap, fmt);
result = vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
if (result < 0) return NULL;
if (result < sizeof(buf)) return popen(buf, mode);
}
/* NOT REACHED */
return NULL;
}
Then, you can call it like this:
const char *filename = get_filename_from_input();
FILE *fp = my_popen("r", "%s < %s", "wc -l", filename);
if (fp) {
/* ... */
pclose(fp); /* make sure to call pclose() when you are done */
}
Here, we assume that get_filename_from_input() transforms the filename input string into something safe for the shell to consume.
It is rather complex (and error prone) to reliably fix up a filename into something the shell will treat safely. It is more safe to open the file yourself. However, after doing so, you can feed the file to a command, and then read out the resulting output. The problem is, you cannot use popen() to accomplish this, as standard popen() only supports unidirectional communication.†
†Some variations of popen() exist that support bidirectional communication.
FILE * my_cmd_open (const char *cmd) {
int s[2], p, status, e;
if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) < 0) return NULL;
switch (p = fork()) {
case -1: e = errno; close(s[0]); close(s[1]); errno = e; return NULL;
case 0: close(s[0]); dup2(s[1], 0); dup2(s[1], 1); dup2(s[1], 2);
switch (fork()) {
case -1: exit(EXIT_FAILURE);
case 0: execl("/bin/sh", "-sh", "-c", cmd, (void *)NULL);
exit(EXIT_FAILURE);
default: exit(0);
}
default: for (;;) {
if (waitpid(p, &status, 0) < 0 && errno == EINTR) continue;
if (WIFEXITED(status) && WEXITSTATUS(status) == 0) break;
close(s[0]); close(s[1]); errno = EPIPE;
return NULL;
}
}
close(s[1]);
return fdopen(s[0], "r+");
}
To efficiently read an entire file into memory, you can use mmap().
void * mmap_filename (const char *filename, size_t *sz) {
int fd = open(filename, O_RDONLY);
if (fd < 0) return NULL;
struct stat st;
if (fstat(fd, &st) < 0) {
close(fd);
return NULL;
}
*sz = st.st_size;
void *data = mmap(NULL, *sz, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd);
return data != MAP_FAILED ? data : NULL;
}
Then, you can call it like this:
size_t sz;
void *data = mmap_filename(filename, &sz);
if (data) {
/* ... */
munmap(data, sz);
}
The example code above maps the entire file at once. However, the mmap() API allows you to map portions of the file from a particular offset into the file.
I am coding up a C program that extracts from a standard UNIX archive ar and creates the files it stores.
Here is an example of what an ar looks like if I open it in vim:
!<arch>
yo 1382105439 501 20 100644 10 `
test1 lol
yo2 1382105444 501 20 100644 10 `
test2 lol
...where "test1 lol" and "test2 lol" are the contents of each file, "yo" and "yo2" are two different file names, and the rest is metadata stored in a format corresponding to the standard ar.h (read more on it here: http://www.lehman.cuny.edu/cgi-bin/man-cgi?ar.h+3)
Anyway, I am still in the process of writing out the function but here is what I have so far:
static void extract_files (int argc, char *argv[])
{
int fd;
int new_file_fd;
int num_read = 0;
int new_file_size;
struct ar_hdr current_header;
char name_buffer[16];
char date_buffer[12];
char uid_buffer[6];
char gid_buffer[6];
char mode_buffer[8];
char size_buffer[10];
char fmag_buffer[2];
// grab the fd #
fd = open(argv[2], O_RDWR | O_CREAT, 0666);
// go to the first header
lseek(fd, SARMAG, SEEK_CUR);
// store the number of bits read in a struct current_header
// until its size equal to the size of the entire
// header, or in other words, until the entire
// header is read
while ((num_read = read(fd, (char*) ¤t_header,
sizeof(struct ar_hdr))) == sizeof(struct ar_hdr))
{
// scans the current string in header and stores
// in nameStr array
sscanf(current_header.ar_name, "%s", name_buffer);
sscanf(current_header.ar_date, "%s", date_buffer);
sscanf(current_header.ar_uid, "%s", uid_buffer);
sscanf(current_header.ar_gid, "%s", gid_buffer);
int mode;
sscanf(current_header.ar_mode, "%o", &mode);
sscanf(current_header.ar_size, "%s", size_buffer);
int size = atoi(size_buffer);
sscanf(current_header.ar_fmag, "%s", fmag_buffer);
// Create a new file
new_file_fd = creat(name_buffer, mode);
// Grab new file size
new_file_size = atoi(size_buffer);
int io_size; // buffer size
char buff[size];
int read_cntr = 0;
// from copy.c
while ((io_size = read (fd, buff, new_file_size)) > 0)
{
read_cntr++;
if (read_cntr > new_file_size)
break;
write (new_file_fd, buff, new_file_size);
}
close(new_file_fd);
printf("%s\n", name_buffer);
printf("%s\n", date_buffer);
printf("%s\n", uid_buffer);
printf("%s\n", gid_buffer);
printf("%s\n", mode_buffer);
printf("%s\n", size_buffer);
printf("%s\n", fmag_buffer);
/* Seek to next header. */
lseek(fd, atoi(current_header.ar_size) + (atoi(current_header.ar_size)%2), SEEK_CUR);
}
}
The issue I am having lies in the second while loop in the above code:
// from copy.c
while ((io_size = read (fd, buff, new_file_size)) > 0)
{
read_cntr++;
if (read_cntr > new_file_size)
break;
write (new_file_fd, buff, new_file_size);
}
For some reason, the files written in this while loop don't run to the length specified by write. The third argument for the standard read()/write() should be the number of bytes to write. For some reason though, my code results in the entire archive being read in and written into the first file.
If I open up the resulting "yo" file, I find the entire archive file has been written to it
test1 lol
yo2 1382105444 501 20 100644 10 `
test2 lol
instead of terminating after reading 10 bytes and giving the expected outcome "test1 lol".
I can also confirm that the "new_file_size" value is indeed 10. So my question is: what am I reading wrong about this while loop?
Note: Expected input would be a command line argument that looks something like:
./extractor.c -x name_of_archive_file
The only relevant information I think I need to deal with in this function is the name of the archive file which I get the fd for at the beginning of extract_files.
Added:
Misc -- the output from when this is run:
yo
1382105439
501
20
X
10
`
As you can see, it never sees the yo2 file or prints out its header because it gets written to "yo" before that can happen...because of this stray while loop :(
You read a value, size_buffer, and assign it to size and new_file_size, you also create a buffer[size] of that same size,
int size = atoi(size_buffer);
sscanf(current_header.ar_fmag, "%s", fmag_buffer);
//...
new_file_size = atoi(size_buffer);
//...
char buff[size];
Read returns a ssize_t count of bytes in range [0..new_file_size], which you set into io_size, realize that read(2) may return < new_file_size bytes, which is why you need the while loop. So you need to write everything you have read, until you reach your write limit. I have made some comments to guide you.
// from copy.c
while ((io_size = read (fd, buff, new_file_size)) > 0)
{
read_cntr++;
//perhaps you mean read_cntr += io_size;
//you probably mean to write io_size bytes here, regardless
//write(new_file_fd, buff, io_size);
if (read_cntr > new_file_size) //probably you want >= here
break;
//you may have broke before you write...
write (new_file_fd, buff, new_file_size);
}
A more typical idiom for this copy would be something where you pick a read/write buffer size, say 4*1024 (4K), 16*1024 (16K), etc, and read that blocksize, until you have less than that blocksize remaining; for example,
//decide how big to make buffer for read()
#define BUFSIZE (16*1024) //16K
//you need min(
#define min(x,y) ( ((x)<(y)) ? (x) : (y) )
ssize_t fdreader(int fd, int ofd, ssize_t new_file_size )
{
ssize_t remaining = new_file_size;
ssize_t readtotal = 0;
ssize_t readcount;
unsigned char buffer[BUFSIZE];
for( ; readcount=read(fd,buffer,min(sizeof(buffer),remaining)); )
{
readtotal += readcount;
if( readcount > remaining ) //only keep remaining
readcount = remaining;
write( ofd, buffer, readcount);
remaining -= readcount;
if( remaining <= 0 ) break; //done
}
return readtotal;
}
Try this,
#include<stdio.h>
#include<stdlib.h>
void usage(char*progname)
{
printf("need 2 files\n");
printf("%s <infile> <outfile>\n",progname);
}
//decide how big to make buffer for read()
#define BUFSIZE (16*1024) //16K
//you need min(
#define min(x,y) ( ((x)<(y)) ? (x) : (y) )
ssize_t fdreader(int fd, int ofd, ssize_t new_file_size )
{
ssize_t remaining = new_file_size;
ssize_t readtotal = 0;
ssize_t readcount;
unsigned char buffer[BUFSIZE];
for( ; readcount=read(fd,buffer,min(sizeof(buffer),remaining)); )
{
readtotal += readcount;
if( readcount > remaining ) //only keep remaining
readcount = remaining;
write( ofd, buffer, readcount);
remaining -= readcount;
if( remaining <= 0 ) break; //done
}
return readtotal;
}
int main(int argc,char**argv)
{
int i=0; /* the infamous 'i' */
FILE*infh;
FILE*outfh;
if( argc < 3 )
{
usage(argv[0]);
return 0;
}
printf("%s %s\n",argv[1],argv[2]); fflush(stdout);
if( !(infh=fopen(argv[1],"r")) )
{
printf("cannot open %s\n",argv[2]); fflush(stdout);
return(2);
}
if( !(outfh=fopen(argv[2],"w+")) )
{
printf("cannot open %s\n",argv[3]); fflush(stdout);
return(3);
}
int x = fdreader(fileno(infh), fileno(outfh), 512 );
return 0;
}
Your while() loop should probably have braces ({ ... }) after it, otherwise you're just incrementing read_cntr without doing anything else.