I am trying to write a program that has to store an ASCII picture (every line has a different length) in an 2D-Array and then print it out again. Either I have to cut the array at "\n" or I have to create an array with dynamic size. Here is what I have so far. It is printing out in the right way, but every line has 255 chars.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define MAX_LENGTH 255
int main(void) {
FILE *iFile, *oFile;
char elements[MAX_LENGTH][MAX_LENGTH];
memset(elements, 0, MAX_LENGTH);
int zeile = 0, position = 0, size = 0;
char c;
bool fileend = false;
//open files
iFile = fopen("image.txt", "r");
oFile = fopen("imagerotated.txt", "w+");
if ((iFile == NULL) || (oFile == NULL))
{
perror("Error: File does not exist.");
exit(EXIT_FAILURE);
}
//read File to a 2D-Array
while (1) {
if ((c = fgetc(iFile)) != EOF) {
if (c == '\n') {
zeile++;
position = 0;
}
elements[zeile][position] = c;
position++;
}
else {
fileend = true;
}
if (fileend == true) {
break;
}
}
//Write 2D-Array into the output file
fwrite(elements, MAX_LENGTH, MAX_LENGTH, oFile);
fclose(iFile);
fclose(oFile);
return EXIT_SUCCESS;
}
So my question is what is the best solution to print out an array and cut each line at "\n"? (Or create an array with dynamic length/size).
I thought about creating an int countRows and get the number from 'zeile' when fileend becomes true, but how do i get countColoumns?
The main goal is rotate the ASCII image in 90 degree steps, but i'm stuck at the output. So i have to use a 2D-Array so i can swap chars easily.
Thanks for your help.
I,
You can try to make a function prototyped like that :
char **myFileToArray(char *contentOfFile);
The purpose of this function is to create an array who will contain each line of your picture.
In this function you count the number of lines (= number of '/n'), you create a dynamic array with this size. For each dimension of your array, you dynamically allocate of the length of your line plus one for the '/0'. You copy your line into the dimension and put the '/0' at each end of dimension.
after this you can return your array.
For example, if your file is :
1. /\_/\
2. =( °w° )=
3. ) ( //
4. (__ __)//
you will have a array of size 5 composed like that :
array[0] = " /\_/\"
array[1] = "=( °w° )="
array[2] = " ) ( //"
array[3] = " (__ __)//"
array[4] = "/0"
For the printing you can create an other function that write the array an replace each '/0' by a '/n'.
This solution is bit more complex but it's still a solution and a clean one i think.
I hope my explanation was clear sorry for my bad english i try to improve !
To write your array data to a binary file with fwrite, you will need to know the number of characters you are writing. All you care about is the number of used characters (or used lines in your case), not the uninitialized/empty part of your array. You will probably also want to write the number of lines and the size of each array element as the first two values to the file so you will know how many of x-size array to read back. (handling strings, you can also write the null-terminating char to the file if you choose) If you have the number of lines numlines as an unsigned int, then something simple like the following for type char where sizeof (char) = 1:
unsigned maxl = MAX_LENGTH;
fwrite (&numlines, sizeof numlines, 1, oFile);
fwrite (&maxl, sizeof maxl, 1, oFile);
fwrite (elements, MAX_LENGTH, numlines, oFile);
Then to read it back, you read the first 2 unsigned int values which the number an array (or row) size to read back from the file.
If elements contains something other than char where sizeof type > 1, then you would change the fwrite for maxl and elements to (example for int):
unsigned maxl = MAX_LENGTH * sizeof (int);
...
fwrite (&maxl, sizeof maxl, 1, oFile);
fwrite (elements, MAX_LENGTH * sizeof (int), numlines, oFile);
or the last line would normally be seen as just:
fwrite (elements, maxl, numlines, oFile);
The goal is to write the file (or record) in a way that you can easily read it back in. Knowing the number of elements and the size and saving those as the first two numbers written to the file allows you to query the file for the size/type needed to hold the values and then to read them back into your program and validate your read.
With not much additional effort, you can write a jagged array out as well, just include the number of character (or bytes) to be read before each line in your output. That will allow you to write a number of unevenly sized groups of elements to your file saving some file size in the process.
Related
I am new to C, coming from Python. I want to read a .xyz file into a dynamically sized array, to use for various calculations later on in the program. The file is formatted as follows:
Title
Comment
Symbol 0.000 0.000 0.000
Symbol 0.000 0.000 0.000
....
The two first lines are not needed, and should just be skipped. The "Symbol" part of the file are chemical symbols--e.g. H, Au, C, Mn--as the .xyz file format is used for storing 3D coordinates of atoms. They need to be ignored as well. I'm interested in the space separated decimal numbers. I therefore want to:
Skip the first two lines, or just ignore them in some way.
Skip the first part of each line until the first space.
Store the three columns of numbers (coordinates) in an array.
So far I have been able to open a file for reading, and then I've attempted to check how long the file is, in order to have the size of the array change depending on how many coordinate sets needs to be stored.
// Variable declaration
FILE *fp;
long file_size;
// Open file and error checking
fp = fopen ("file_name" , "r");
if(!fp) perror("file_name"), exit(1);
// Check file size
fseek(fp, 0, SEEK_END);
file_size = ftell(fp);
rewind(fp);
// Close file
fclose(fp);
I've been able to skip the first two lines using fscanf(fp, "%*[^\n]"), to skip to the end of the line. But, I haven't been able to figure out how to loop through the rest of the file, while storing only the decimal numbers in an array.
If I understand correctly, I need to allocate memory for the array, using something like malloc() in combination with my file_size and then copy the data into the array using fread().
Here is an example of the contents of an actual .xyz file:
10 atom system
Energy: -914941.6614699
Ag 0.96834 1.51757 0.02281
Ag 0.96758 -1.51824 -0.02206
Ag -1.80329 2.27401 0.03179
Ag -3.58033 0.00046 0.00126
Ag -1.80447 -2.27338 -0.03537
Ag -0.96581 0.02246 -1.51755
Ag -0.96929 -0.02231 1.51463
Ag 1.80613 0.03321 -2.27213
Ag 3.58027 0.00028 0.00206
Ag 1.80086 -0.03407 2.27455
Here is a general approach in C for reading a file into an array of cstrings (pointers to cstrings, so the rough equivalent of a Python list of strings).
int count = 0; // line counter;
int char_count = 0; // char counter;
int max_len = 0; // for storing the longest line length
int c; // for measuring each line length
char **str_ptr_arr; // array of pointers to c-string
//extract characters from the file, looking for endlines; note that
//the EOF check has to come AFTER the getc(fp) to work properly
for (c = getc(fp); c != EOF; c = getc(fp)) { //edit see comments
char_count += 1;
if (c == '\n') { //safe comparison see comments
count += 1;
if (max_len < char_count) {
max_len = char_count; //gets longest line
}
char_count = 0;
}
}
//should probably do an feof check here
rewind(fp);
So now you have the number of lines and the length of the longest line, (You can try using the above loop to exclude lines if you want but it might just be easier to read the whole thing into an array of c-strings, then process that into an array of doubles). Now allocate the memory for the array of pointers to c-strings and for the c-strings themselves:
//allocate enough memory to hold all the strings in the file, by first
//allocating the arr of ptrs then a slot for each c-string pointed to:
str_ptr_arr = malloc(count * sizeof(char*)); //size of pointer
for (int i = 0; i < count; i++) {
str_ptr_arr[i] = malloc ((max_len + 1) * sizeof(char)); // +1 for '\0' terminate
}
rewind(fp); //rewind again;
Now, we have a problem, which is how to populate these cstrings (Python is so much easier!). This works, I'm not sure if it's the expert approach, but here we read into a
temporary buffer then use strcpy to move the contents of the buffer into our allocated array slots:
for (int i = 0; i < count; i++) {
char buff[max_len + 1]; //local temporary buffer that can store any line in file
fscanf(fp, "%s", buff); //read the first string to buffer
strcpy(str_ptr_arr[i], buff);
}
Note: this is a decent point at which to start excluding lines or removing various substrings from lines, as you can make strcpy conditional on the contents of the buffer, by using other cstring methods. I'm fairly new at this myself, (learning to write C functions for use in Python progams), but this seems to be the correct approach.
It might also be possible to go directly to a dynamically allocated array of floats for storing your numerical data without bothering with the cstring array; that could be done in the last loop above. You could split the strings at whitespace, exclude the alphabetical parts, and use the cstring function atof to convert to float datatype.
Edit: I should mention all these memory allocations must be manually freed when you are done with them, and this is the approach:
for(int i = 0; i < count; i++) { // free each allocated cstring space
free(str_ptr_arr[i]);
}
free(str_ptr_arr); // free the cstring pointer space
str_ptr_arr = NULL;
Given, for example:
#define STORAGE_INCREMENT 128
typedef struct
{
double x, y, z ;
} sXYZ ;
Then:
int atom_count = 0 ;
int atom_capacity = STORAGE_INCREMENT ;
sXYZ* atoms = malloc( atom_capacity * sizeof(*atoms) ) ;
// While valid triplet, discard symbol, get x,y,z
while( fscanf( fp, "%*s%lf%lf%lf", &atoms[atom_count].x,
&atoms[atom_count].y,
&atoms[atom_count].z ) == 3 )
{
// Increment count
atom_count++ ;
// If capacity exhausted, expand allocation
if( atom_count == atom_capacity )
{
atom_capacity += STORAGE_INCREMENT ;
sXYZ* bigger = realloc( atoms, atom_capacity * sizeof(*atoms) ) ;
if( bigger == NULL )
{
break ;
}
atoms = bigger ;
}
}
This allocates enough space for 128 atoms initially, and if the space is exhausted, it is expanded by a further 128 atoms - indefinitely. A smaller value can be used if the files typically have fewer atoms to be a little more memory efficient. This approach saves you having to first count the number of triplets in the file.
I found this piece of code at Reading a file character by character in C and it compiles and is what I wish to use. My problem that I cannot get the call to it working properly. The code is as follows:
char *readFile(char *fileName)
{
FILE *file = fopen(fileName, "r");
char *code;
size_t n = 0;
int c;
if (file == NULL)
return NULL; //could not open file
code = malloc(1500);
while ((c = fgetc(file)) != EOF)
{
code[n++] = (char) c;
}
code[n] = '\0';
return code;
}
I am not sure of how to call it. Currently I am using the following code to call it:
.....
char * rly1f[1500];
char * RLY1F; // This is the Input File Name
rly1f[0] = readFile(RLY1F);
if (rly1f[0] == NULL) {
printf ("NULL array); exit;
}
int n = 0;
while (n++ < 1000) {
printf ("%c", rly1f[n]);
}
.....
How do I call the readFile function such that I have an array (rly1f) which is not NULL? The file RLY1F exists and has data in it. I have successfully opened it previously using 'in line code' not a function.
Thanks
The error you're experiencing is that you forgot to pass a valid filename. So either the program crashes, or fopen tries to open a trashed name and returns NULL
char * RLY1F; // This is not initialized!
RLY1F = "my_file.txt"; // initialize it!
The next problem you'll have will be in your loop to print the characters.
You have defined an array of pointers char * rly1f[1500];
You read 1 file and store it in the first pointer of the array rly1f[0]
But when you display it you display the pointer values as characters which is not what you want. You should just do:
while (n < 1000) {
printf ("%c", rly1f[0][n]);
n++;
}
note: that would not crash but would print trash if the file read is shorter than 1000.
(BLUEPIXY suggested the post-incrementation fix for n BTW or first character is skipped)
So do it more simply since your string is nul-terminated, pass the array to puts:
puts(rly1f[0]);
EDIT: you have a problem when reading your file too. You malloc 1500 bytes, but you read the file fully. If the file is bigger than 1500 bytes, you get buffer overflow.
You have to compute the length of the file before allocating the memory. For instance like this (using stat would be a better alternative maybe):
char *readFile(char *fileName, unsigned int *size) {
...
fseek(file,0,SEEK_END); // set pos to end of file
*size = ftell(file); // get pos, i.e. size
rewind(file); // set pos to 0
code = malloc(*size+1); // allocate the proper size plus one
notice the extra parameter which allows you to return the size as well as the file data.
Note: on windows systems, text files use \r\n (CRLF) to delimit lines, so the allocated size will be higher than the number of characters read if you use text mode (\r\n are converted to \n so there are less chars in your buffer: you could consider a realloc once you know the exact size to shave off the unused allocated space).
I need to be able to make sure my array is correctly receiving values from the file card.raw through fread.
I am not confident about using arrays with pointers, so if anybody could help me with the theory here, it would be GREATLY appreciate it. Thanks in advance.
The code is supposed to take literally one block of size 512 bytes and stick it into the array. Then I am just using a debugger and printf to examine the arrays output.
/**
* recover.c
*
* Computer Science 50
* Problem Set 4
*
* Recovers JPEGs from a forensic image.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main(int argc, char* argv[])
{
//Size of EACH FAT JPEG in bytes
#define FILESIZE 512
unsigned char* buffer[FILESIZE];
///Step 1: Open jpeg
FILE* readfrom = fopen("card.raw", "rb");
if (readfrom == NULL)
{
printf("Could not open");
}
///Step 2: Find Beginning of JPEG. The first digits will be 255216255 Then 224 or 225
fread(&buffer, FILESIZE, 1, readfrom);
for(int x = 0; x < FILESIZE; x++)
{
printf("%d = %c\n", x, buffer[x]);
}
fclose(readfrom);
}
Use return values from input functions. fread() reports how many elements were read - code might not have read 512. Swap FILESIZE, 1 to detect the number of characters/bytes read.
// fread(&buffer, FILESIZE, 1, readfrom);
size_t count = fread(&buffer, 1, FILESIZE, readfrom);
Only print out up to the number of elements read. Recommend hexadecimal (and maybe decimal) output rather than character.
for(size_t x = 0; x < count; x++) {
// printf("%d = %c\n", x, buffer[x]);
printf("%3zu = %02X % 3u\n", x, buffer[x], buffer[x]);
}
If the fopen() failed, best to not continue with for() and fclose().
if (readfrom == NULL) {
printf("Could not open");
return -1;
}
The second parameter is size, in bytes, of each element to be read.
The third parameter is Number of elements each one with a size of the <second parameter> bytes.
So, swap your second and first parameters.
Replace unsigned char* buffer[FILESIZE]; with unsigned char buffer[FILESIZE];. For now, you have an array of unsigned char *, when you need unsigned char. Because buffer is already a pointer, you don't need to take its address. In fread call, replace &buffer with buffer.
It must go like this: fread(buffer, 1, FILESIZE, readfrom);
One more thing: add return with a specific error code after printf("Could not open");, because if file hasn't been open, you cannot read from it, can you? And add return 0; in the end of main.
And take your #define out of main.
Read more about fread here: http://www.cplusplus.com/reference/cstdio/fread/
I'm working in C and I'm modifying existing code.
I have a char array which is stored in a file as follows:
"\x01\x02\x03"
"\x04\x05\x06"
"\x07\x08\x09"
In the original source code this char array is included as follows:
const static char chs[] =
#include "file.h"
;
I'm modifying this code to load the file into a char array during runtime (to get the exact same result as with the above approach) instead of it to be included by the pre-processor. My first approach was to simply read the file into a char buffer, as follows:
FILE *fp;
const char *filename = "file.h";
fp = fopen (filename, "rb");
assert(fp != NULL);
fseek(fp, 0L, SEEK_END);
long int size = ftell(fp);
rewind(fp);
// read entire file into the buffer
char *buffer = (char*)malloc(sizeof(char) * size);
size_t nrOfBytesRead = fread(buffer, 1, size, fp);
However I've quickly discovered that this is not correct. The file already contains the exact code representation of the char array, I cannot simply read it into a char buffer and get the same result as the include approach.
What is the best way to get my char array which is stored in file, into a char array during runtime?
As you've seen, when you read the file using fread it reads it byte for byte. It doesn't get any of the syntactic processing that the compiler does on your source files. It doesn't know that strings live inside of quotes. It doesn't map escape sequences like \x01 into single bytes.
You have several different possibilities for fixing this:
Teach your program how to do that processing as it reads the file. This would be a fair amount of work.
Put just the bytes you want into the file.
Pick a different encoding for your file.
To say a little more about #2: If you don't want to change your file-reading code, what you can do is to create an (in this case) 9-byte file containing just the nine bytes you want. Since your nine bytes are not text, it'll end up being a "binary" file, which you won't be able to straightforwardly edit with an ordinary text editor, etc. (In fact, depending on the tools you have available to you, it might be challenging just to create this particular 9-byte file.)
So if you can't use #1 or #2, you might want to go with #3: pick a brand-new way to encode the data in the file, easier to parse than #1, but easier to prepare than #2. My first thought would be to have the file be hexadecimal. That is, the file would contain
010203040506070809
or
010203
040506
070809
Your file-reading code, instead of the single call to fread, would read two characters at a time and assemble them into bytes for your array. (I'd sketch this out for you, but the compilation I was waiting for has finished, and I ought to get back to my job.)
This should read the hex values from the file and save them to buffer.
fgets() reads each line from the file.
sscanf() reads each hex value from the line.
The format string for sscanf, "\\x%x%n", scans the backslash, an x, the hex value and stores the number of characters processed by the scan. The number of characters processed is used to advance through the line. This is needed if some lines have a different number of hex values.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char line[100] = {'\0'};
unsigned char *buffer = NULL;
unsigned char *temp = NULL;
unsigned int hex = 0;
int size = 0;
int offset = 0;
int used = 0;
int bufferused = 0;
int increment = 100;
int each = 0;
FILE *pf = NULL;
if ( ( pf = fopen ( "file.h", "r")) != NULL) {
while ( fgets ( line, sizeof ( line), pf)) {//get each line of the file
offset = 1;//to skip leading quote
//sscanf each hex value in the line
while ( ( sscanf ( line + offset, "\\x%x%n", &hex, &used)) == 1) {
offset += used;// to advance through the line
if ( bufferused >= size) {
temp = realloc ( buffer, size + increment);
if ( temp == NULL) {
//one way to handle the failure
printf ( "realloc failed\n");
free ( buffer);
exit (1);
}
buffer = temp;
size += increment;
}
buffer[bufferused] = hex;
bufferused++;
}
}
fclose ( pf);
}
for ( each = 0; each < bufferused; each++) {
printf ( "%x\n", buffer[each]);
}
free ( buffer);
return 0;
}
I'm getting some issues with reading the content of my array. I'm not sure if I'm storing it correctly as my result for every line is '1304056712'.
#include <stdio.h>
#include <stdlib.h>
#define INPUT "Input1.dat"
int main(int argc, char **argv) {
int data_index, char_index;
int file_data[1000];
FILE *file;
int line[5];
file = fopen(INPUT, "r");
if(file) {
data_index = 0;
while(fgets(line, sizeof line, file) != NULL) {
//printf("%s", line); ////// the line seems to be ok here
file_data[data_index++] = line;
}
fclose(file);
}
int j;
for(j = 0; j < data_index; j++) {
printf("%i\n", file_data[j]); // when i display data here, i get '1304056712'
}
return 0;
}
I think you need to say something like
file_data[data_index++] = atoi(line);
From your results I assume the file is a plain-text file.
You cannot simply read the line from file (a string, an array of characters) into an array of integers, this will not work. When using pointers (as you do by passing line to fgets()) to write data, there will be no conversion done. Instead, you should read the line into an array of chars and then convert it to integers using either sscanf(), atoi() or some other function of your choice.
fgets reads newline terminated strings. If you're reading binary data, you need fread. If you're reading text, you should declare line as an array of char big enough for the longest line in the file.
Because file_data is an array of char, file_data[data_index] is a single character. It is being assigned a pointer (the base address of int line[5] buffer). If reading binary data, file_data should be an array of integers. If reading strings, it should be an array of string, ie char pointers, like char * file_data[1000]
you also need to initialize data_index=0 outside the if (file) ... block, because the output loop needs it to be set even if the file failed to open. And when looping and storing input, the loop should test that it's not reached the size of the array being stored into.