I'm trying to copy contents of one file into another. Before I finished, I wanted to print the contents out on screen to see that things are working. But they didn't.
I included...
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
and my code is...
void decodeBin(char * filename){
//opens filename for reading and outfilename for writing
FILE * input = fopen(filename, "r");
char file_name[] = "";
strcpy(file_name, filename);
char out_file[] = "out";
strcat(out_file, file_name);
FILE * output = fopen(out_file, "w");
char ch;
if (input != NULL){
while((ch = fgetc(input)) != EOF)
printf("%c", ch);
}
fclose(input);
fclose(output);
}
I looked at the other stack overflow posts, which suggested to check if file pointer is not null, which I do. What's going wrong?
You're causing undefined behavior by writing outside the bounds of the file_name and out_file arrays. When you don't specify a size for the array, the size is determined from the string you use to initialize it. So it's equivalent to
char file_name[1] = "";
char out_file[4] = "out";
The extra byte is for the trailing null.
Since you didn't declare the arrays big enough for the strings you're copying into them, you get undefined behavior.
You need to declare the size of the arrays big enough to hold the largest possible filename. Or use malloc() to size it in terms of the parameters.
There's no need for the file_name variable, since it's just a copy of filename, and you can use that directly.
char *outfile = malloc(strlen(filename) + sizeof("out"));
sprintf(outfile, "out%s", filename);
Then at the end of the function, do
free(outfile);
Related
I try to read a file from this code. I am trying to load images and store them into my program as strings, so I can later create the identical image with fprintf to a new file. I am not allowed to use some file duplication; I need to load the files in as a string and write them to a new file later. What I am attempting is to have a char array, and since one char is one byte the array is as long as the file size, and each element of the char array corresponds to one byte of the diamond block texture, and I want to also be able to write this string from the code to a new file, and have another diamond block that I can open with an image viewer.
#include <stdio.h>
#include <stdlib.h>
char Contents[468];
int main(int argc, char *argv[]) {
char *WD = getenv("HOME");
char Path[strlen(WD)+strlen("/Desktop/diamond_block.png")+1];
sprintf(Path, "%s/Desktop/diamond_block.png", WD);
FILE *File = fopen(Path, "r");
fscanf(File, "%s", Contents);
printf(Contents);
}
The result is just four letters, âPNG, and it is supposed to be hundreds of characters meaning the file is NOT being fully read. I suspect it is somehow being terminated early by some terminating character, but how can I solve my problem?
This is a very basic answer to your question. With the code below you may understand what's your issue. This code need a good review to intercept all the errors the used functions may return. By the way ... enjoy it!
The code loads the whole file fname into the char array imgMem. It compute the file dimension on the variable n, allocates the memory for the array imgMem (malloc) and then loads the whole file into imgMem (fread).
Then the code writes the first 30 bytes of the file in two format:
the hex value of the byte
the char value if the byte has a console representation (otherwise prints a .)
Here the code:
#include <unistd.h>
#include <stdio.h>
#include <malloc.h>
int main(void)
{
const char * fname = "/home/sergio/Pictures/vpn.png";
FILE * fptr;
char * imgMem=NULL;
long n;
int i;
fptr=fopen(fname, "r");
//Determine the file dimension
fseek(fptr,0,SEEK_END); n=ftell(fptr);
//Set the file cursor to the beginning
fseek(fptr,0,SEEK_SET);
printf("The file is %lu byte long.\n\n",n);
//Allocate n bytes to load the file
imgMem = malloc((size_t)n);
//Load the file
fread(imgMem,(size_t)n,1,fptr);;
for(i=0; i<30; i++) {
printf("[%02X %c] ",
(unsigned char)imgMem[i],
(imgMem[i]>31 && imgMem[i]<127)?
imgMem[i]:'.'
);
if ((i+1)%8==0)
puts("");
}
puts("");
free(imgMem);
fclose(fptr);
return 0;
}
i'm trying to read a file and split this file into multiple buffers.
This is what i came up with:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define PKT_SIZE 2048;
#define PATH "directory of some kind"
int main() {
char filepath[200] = PATH;
FILE *packet;
int size = PKT_SIZE;
char *buffer[size];
int i=0;
//OPEN FILE
if((packet = fopen(filepath, "r")) == NULL){ //I'm trying with a txt file, then i'll change it to 'rb'
printf("Error Opening File\n");
return -1;
}
//READ FILE
while(*fgets((char *) *buffer[i], (int) strlen(buffer[i]), packet) != NULL) { //read the file and cycling insert the fgets into the buffer i
printf("Create %d buffer\n", i);
i++;
}
fclose(packet);
return 0;
}
Now, when i run this program, i get a SIGSEGV error, i managed to understand that this error is definetly:
*fgets((char *) *buffer[i], (int) strlen(buffer[i]), packet) != NULL
Do you have any suggestions?
*fgets((char *) *buffer[i], (int) strlen(buffer[i]), packet)
This line as several problems.
buffer[i] is just an un-initialized pointer pointing nowhere.
*buffer[i] is of type char you need to pass the char*.
strlen is not returning the size of the buffer. It is undefined behavior here because you called it over uninitialized pointer value.
Also dererencing whatever fgets is return is bad when the fgets returns NULL. It invokes undefined behavior.
There many solutions to this ranging from dynamic memory allocation to using
char buffer[size][MAXSIZE];. If you go about this you can get input this way:
#define MAXSIZE 100
...
char buffer[size][MAXSIZE];
while(fgets(buffer[i], sizeof(buffer[i]), packet)!=NULL){...
char* buffer[size] is an array of N char* pointers which are uninitialized. You must allocate memory to these before using them or your program will explode in a ball of fire.
The fix is to allocate:
for (size_t i = 0; i < size; ++i) {
buffer[i] = malloc(PKT_SIZE);
}
You're going to be responsible for that memory going forward, too, so don't forget to free later.
Allocating an arbitrary number of buffers is pretty wasteful. It's usually better to use some kind of simple linked-list type structure and append chunks as necessary. This avoids pointless over-allocation of memory.
I am doing a project of creating a bot that surfs the internet.
I have to code it in C and for now I'm focusing on the choice of the address where it will go (choosen from a list in a file). This works properly but when I display the addresses the bot has chosen, some are truncated to 24 characters and end with "!" which makes the code unusable with long addresses. Does anyone have any idea of where it might come?
The program :
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <math.h>
int main() {
FILE* file = fopen("test.txt", "r+");
char *line = NULL;
char *tab[1023];
int tailleTab = 0;
line = malloc(sizeof(*line));
if(line == NULL)
return(EXIT_FAILURE);
while((fgets(line, 1023, file)) != NULL ) {
if(line[0] != '#' && line[0] != '\n') {
tab[tailleTab] = line;
line = malloc(sizeof(*line));
tailleTab++;
}
}
srand(time(NULL));
int n = rand()%tailleTab;
printf("\n%d = %.32s\n", n, tab[n]);
printf("%s\n", tab[n]);
fclose(file);
}
The file from which the address is chosen:
www.google.com
www.wikipedia.org
www.dahunicorn.xyz
www.cloudimperiumgames.com
www.robertspaceindustries.com
www.candybox2.net
www.42.com
www.1337.com
The main problem is this:
line = malloc(sizeof(*line));
This only allocates a single character to line. The expression *line is a char which means you allocate sizeof(char) bytes, and sizeof(char) is defined to always be 1.
That means your call to fgets will write out of bounds of your allocated memory and you will have undefined behavior.
There's no reason to actually allocate line dynamically. Instead create it as an array, and then use strdup when saving it in the tab array. Either that or allocate more memory (1023 is a good number, since that's amount you pass to fgets).
As already explained in another answer, with this code:
line = malloc(sizeof(*line));
you are allocating with malloc a single char on the heap, since the expression *line is equivalent to a char (as line is declared as char *).
I would simplify your code using named constants instead of magic numbers like 1023 that are spread through code (and make it harder to maintain), in addition to just reserving space for the temporary line buffer on the stack instead of dynamically allocating it on the heap, e.g.:
/* Instead of: line = malloc(sizeof(*line)); */
#define LINE_MAX_SIZE 1024
char line[LINE_MAX_SIZE];
Also consider doing:
#define TAB_MAX_ITEMS /* 1023 or whatever */
char* tab[TAB_MAX_ITEMS];
In the while loop consider using LINE_MAX_SIZE instead of the magic number 1023:
while ((fgets(line, LINE_MAX_SIZE, file)) != NULL ) {
You may also want to add a check to the index in the tab array, to avoid buffer overruns:
if (tailleTab >= TAB_MAX_ITEMS) {
/* Index out of range */
...
}
/* tailleTab is a valid index.
* Deep-copy the line read in the temporary buffer
* and save a pointer to the copy into the tab array.
*/
tab[tailleTab] = strdup(line);
In production code you should also loop through the pointers stored in the tab array, and call free on the them to release the memory allocated on the heap.
I need to read some data from text file and store it in 2D-array.
This code works good:
#include <string.h>
#include <stdio.h>
int main() {
FILE *f = fopen("Read.txt", "r");
char buff[100][100];
char str[100];
int i = 0;
while(fgets(str, 100, f)) {
strcpy(buff[i], str);
i++;
}
return 0;
}
But why doesn't it work when I try to change buff definition in line 5 to:
char (*buff)[100];
I expected this definition to work too.
The error I get:
Run-Time Check Failure #3 - The variable 'buff' is being used without being defined
char (*buff)[100];
Here buff is a pointer to an array of 100 characters. So first you should make the pointer point to valid memory location before storing some value in it.
Presuming you want to go for dynamic memory allocation then you can have
char *buff[100];
Now in the fgets() loop allocate memory to each pointer individually like
buff[i] = malloc(100);
Note here buff is an array of 100 char pointers.
Switching to C from Java, and I'm having some troubles grasping memory management
Say I have a function *check_malloc that behaves as such:
// Checks if malloc() succeeds.
void *check_malloc(size_t amount){
void *tpt;
/* Allocates a memory block in amount bytes. */
tpt = malloc( amount );
/* Checks if it was successful. */
if ( tpt == NULL ){
fprintf(stderr, "No memory of %lu bytes\n", amount);
exit(1);
}
return tpt;
}
I also have the following variables to work with:
FILE *f = fopen("abc.txt", "r"); // Pointer to a file with "mynameisbob" on the first line and
// "123456789" on the second line
char *pname; // Pointer to a string for storing the name
}
My goal is to use *check_malloc to dynamically allocate memory so that the String pointed to by *pname is just the correct size for storing "mynamisbob", which is the only thing on the first line of the text file.
Here is my (failed) attempt:
int main(int argc, char *argv[]){
FILE *f = fopen("abc.txt", "r"); // A file with "mynameisbob" on the first line and
// "123456789" on the second line
char *pname; // Pointer to a string for storing the name
char currentline[150]; // Char array for storing current line of file
while(!feof(f)){
fgets(currentline,100,f);
pname = ¤tline;
}
But I know this probably isn't the way to go about this, because I need to use my nice check_malloc* function.
Additionally, in my actual text file there is a "<" symbol before the name on the first line.But I just want the *pname to point to a String saying "mynameisbob" without the "<" symbol. This isn't that important now, it just is reinforcement to me that I know I can't just set the pointer to point straight to currentline.
Can anyone help me fix my thinking on this one? Thanks a lot.
In C you need to copy chars, not the "strings" (which are just pointers). Check out strcpy() and strlen(). Use strlen() to determine how long the line actually is which fgets has read, then use your malloc() to allocate exactly that (plus 1 for the 0). Then copy the chars over with strcpy().
There are several problems in your code, see my comments in this example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Checks if malloc() succeeds.
void *check_malloc (size_t amount) {
void *tpt;
/* Allocates a memory block in amount bytes. */
tpt = malloc( amount );
/* Checks if it was successful. */
if (tpt == NULL) {
fprintf (stderr, "No memory of %lu bytes\n", amount);
exit (EXIT_FAILURE);
}
return tpt;
}
// To avoid subtle errors I have defined buffer size here
#define BUFFER_SIZE 150
// I have used the (void) version of main () here, while not strictly neccessary, you where not using argc and argv anyway, so the can be left out in this case
int main (void) {
// It might be a good idea to make the filename a char[] as well, but I leave that as an exercise to the reader.
FILE *f = fopen("abc.txt", "r"); // A file with "mynameisbob" on the first line and
// "123456789" on the second line
// You have to check whether the file was *actually openend*
if (f == NULL) {
fprintf (stderr, "Could not open file abc.txt\n"); // '"...%s\n", filename);' might better.
exit (EXIT_FAILURE);
}
char *pname; // Pointer to a string for storing the name
char currentline[BUFFER_SIZE]; // Char array for storing current line of file
while(!feof (f)) {
char *res = fgets (currentline, BUFFER_SIZE, f);
// fgets returns NULL when EOF was encountered before the next '\n'
if (res) {
size_t read = strlen (res);
// The line might have been empty
if (read) {
// Better use "sizeof *varname", while char is always 1 byte it is a good practice
pname = check_malloc ((read + 1) * sizeof *pname); // + 1 because we have to provide an extra char für '\0'
strncpy (pname, currentline, read); // You have to use strcpy or strncpy to copy the contents of the string rather than just assigning the pointer
// What was allocated must be freed again
free (pname);
}
}
}
fclose(f); // Always close everything you open!
return EXIT_SUCCESS;
}
Actually you really don't have to use pname in this simple case, because currentline already contains the line, but since you're trying to learn about memory management this should give you a general idea of how things work.
In your code you had this line:
pname = ¤tline;
There are two problems here:
As already mentioned in my code assigning currentline to pname only copies the pointer not the contents.
The correct assignment would be pname = currentline (without the address operator &), because currentline is also a pointer under the hood (it behaves like char *currentline even though it's statically allocated).