Why is a simple declaration of a character array crashing my code? - c

I have been playing around with file writing functions to study their properties in more detail, along with some other things as well (however what I was doing is ultimately irrelevant), and while I was doing that I encountered a segmentation fault. But not just the everyday type of segfault (dereferencing to unallocated space or something), the segfault is somehow caused by the declaration of a character array. In the code char name[10]. The declaration of char name[10] results in segmentation fault, and I do not understand why. Commenting this declaration removes the issue. What is going on here?
The code I wrote is given below:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main(int argc, char *argv[]){
//char name[10];
//strcpy(name, "George");
//printf("%s\n", name);
//if(argc == 2){
//char *myname = "George";
FILE *file = fopen("Readmystuff" , "rt");//fopen(argv[1],"rt");
if(file == NULL)
printf("Could not open file: %s\n", strerror(errno));
char *str, *cr;
int maxsize = 200;
cr = fgets(str, maxsize, file);
int fcl = fclose(file);
printf("\n");
int strl = strlen(str);
if(fcl == 0)
printf("File closed succesfully\ncr: %c\nstr: %s\nTotal string size - 1 (for null): %i\n", *cr, str, strl);
else
printf("File did not close");
//}
//else
//printf("There must be one argument, argv[1] = the filename, for the code to work\n");
return 0;
}

char *str, *cr;
/* ... */
cr = fgets(str, maxsize, file);
Your str pointer is not initialized, its value is indeterminate. You are writing to an invalid object. Either define an array with a sufficient size or use malloc to allocate one.

Related

Error using fprintf and fscanf

I have an archive results.csv and I need to read the first line of this archive and print it out on output.txt. Somehow it's printing random characters after everything and I couldn't figure out what is wrong.
Command: a.c results.csv
First line:
date,home_team,away_team,home_score,away_score,tournament,city,country,neutral
output.txt: date,home_team,away_team,home_score,away_score,tournament,city,country,neutral,(!£,(!£,(!£,(!£,(!£,#,£,(!£,(!£
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
typedef struct
{
char *line1;
char *line1a;
char *line1b;
char *team1;
char *team2;
char *reason;
char *city;
char *country;
char *neutral_field;
}data;
void open_input(char *argv[], FILE **input)
{
if((*input=fopen(argv[1], "r")) == NULL)
{
printf("%s not found\n", argv[1]);
exit(1);
}
}
void open_output(char *string, FILE **output)
{
if((*output=fopen(string, "w")) == NULL)
{
printf("%s not found\n", string);
exit(1);
}
}
void alloc_data(data *d, int size)
{
d->line1 = (char*)malloc(4*sizeof(char));
d->team1 = (char*)malloc(9*sizeof(char));
d->team2 = (char*)malloc(9*sizeof(char));
d->line1a = (char*)malloc(10*sizeof(char));
d->line1b = (char*)malloc(10*sizeof(char));
d->reason = (char*)malloc(10*sizeof(char));
d->city = (char*)malloc(4*sizeof(char));
d->country = (char*)malloc(7*sizeof(char));
d->neutral_field = (char*)malloc(7*sizeof(char));
}
void store(data *d, FILE *input, FILE **output)
{
fscanf(input, "%s,%s,%s,%s,%s,%s,%s,%s,%s", d[0].line1, d[0].team1, d[0].team2, d[0].line1a, d[0].line1b, d[0].reason, d[0].city, d[0].country, d[0].neutral_field );
fprintf(*output, "%s,%s,%s,%s,%s,%s,%s,%s,%s\n", d[0].line1, d[0].team1, d[0].team2, d[0].line1a, d[0].line1b, d[0].reason, d[0].city, d[0].country, d[0].neutral_field );
}
int main(int argc, char *argv[])
{
FILE *input;
FILE *output;
char *string = "output.txt";
int size = 1000;
open_input(argv, &input);
open_output(string, &output);
data *d;
d = (data*)malloc(size*sizeof(data));
alloc_data(d, size);
store(d, input, &output);
free(d);
return 0;
}
fscanf(input, "%s,%s,%s,%s,%s,%s,%s,%s,%s", d[0].line1, d[0].team1,...
The above code tries to read the whole line in to d[0].line1 which causes buffer overflow. team1 and the rest will contain uninitialized data.
You have to change fscanf as follows:
fscanf(input, "%3[^ ,\n\t],%9[^ ,\n\t],...
Where 3 is 4 - 1, and 4 is the size of d[0].line1
Alternatively you can use strtok
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void store(FILE *input, FILE *output)
{
char buf[500];
while(fgets(buf, sizeof(buf), input))
{
//strip end-of-line from `buf`
if(strlen(buf))
if(buf[strlen(buf) - 1] == '\n')
buf[strlen(buf) - 1] = 0;
//tokenize with strtok
char *token = strtok(buf, ",");
while(token)
{
fprintf(output, "%s", token);
token = strtok(NULL, ",");
}
fprintf(output, "\n");
}
}
int main(int argc, char *argv[])
{
FILE *input = fopen("input.txt", "r");
FILE *output = fopen("output.txt", "w");
store(input, output);
return 0;
}
With above code you don't need an additional structure.
If you do use a structure for data, you have to be more careful. It seems you are trying to create an array of 1000 data, but the following only creates one oversized pointer, not an array of data
int size = 1000;
data *d;
d = (data*)malloc(size*sizeof(data));
alloc_data(d, size);
Additionally, for each malloc there should be a corresponding free.
Your buffers aren't big enough to hold the terminating NUL byte. scanf stores that NUL byte (overrunning the buffer), but then the object that really owns that byte may overwrite it, so when printf looks for the NUL it doesn't find it until much later in memory.
The buffer overruns are a bigger problem than what you've seen, who knows what objects those NUL bytes you didn't make space for are smashing? And what happens when you read a data file with slightly different header spelling? Suddenly your hard-coded allocations sizes will be even more wrong than they are already.

C program to reverse content of a file and write that to another file

I'm having issues with an assignment where I have to take the contents of one file into a buffer, reverse those contents, and write them to another file. This program NEEDS to utilize two functions that look like this:
int read_file( char* filename, char **buffer );
int write_file( char* filename, char *buffer, int size);
so far my files look like this:
file_utils.h
#ifndef UTILS_H
#define UTILS_H
int read_file(char* filename, char **buffer);
int write_file(char* filename, char *buffer, int size);
#endif
file_utils.c
#include "file_utils.h"
#include <stdlib.h>
#include <stdio.h>
#include <font1.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
int read_file(char* filename, char **buffer) {
FILE* file1;
file1 = fopen(filename, "r");
//gets the size of the file
struct stat st;
stat(filename, &st);
int size = st.st_size;
buffer = malloc(size);
read(file1, &buffer, 1);
return size;
}
int write_file(char* filename, char*buffer, int size) {
FILE* file2;
file2 = fopen(filename, 'w');
for (int k = size - 1; k >= 0; k--) {
char* x = &buffer + k;
fprintf(file2, "%s", x);
}
printf(filename, '\O');
return 1;
}
reverse.c
#include "file_utils.h"
#include <stdlib.h>
#include <stdio.h>
#include <font1.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
char* buffer;
char* filename1;
char* filename2;
int filesize;
filename1 = argv[1];
filename2 = argv[2];
filesize = read_file(filename1, &buffer);
write_file(filename2, buffer, filesize);
return 0;
}
and that's all there is. I run it using "clang file_utils.c reverse.c" and I get warnings for file_utils.c like
incompatible integer to pointer conversion passing 'int" to parameter of type 'const char *' (for the line file1 = fopen(filename, 'r')
incompatible pointer to integer conversion passing 'FILE *' (aka 'struct_IO_FILE*') to parameter of type 'int' (for the line read(file1, &buffer, 1);)
the same warning as the first one but for the line file2 = fopen(filename, 'w');
and incompatible pointer types initializing 'char *' with an expression of type 'char **'; dereferences with * (for the line char* x = &buffer + k;)
on top of all this when I continue on to run the executable as such
./a.out file1 file2
where file 1 has text that should be reversed into file 2, I get a segmentation fault.
Any insight into things I can fix will be much appreciated.
Just off the top of my head, without testing, I see these bugs:
buffer = malloc(size); should be *buffer = malloc(size);
... because buffer is a pointer to pointer to char, you need to
dereference it once.
read(file1, &buffer, 1); should be fread(*buffer, 1, size, file1);
... because you opened file1 with fopen, so it's FILE *. read is
Unix I/O, not stream I/O, and doesn't use FILE *.
file2 = fopen(filename, 'w'); should be file2 = fopen(filename, "w");
The second argument should be a "string" (pointer to char or array of
char). 'w' is a single char.
char* x = &buffer + k; should be char *x = buffer + k;
buffer is a pointer to char, so you want to use it directly, not
take its address. Also note the style of putting * next to the
variable instead of the type. This is a good habit, because these
do not mean the same thing:
char *a, *b, *c; /* three pointers */
char* a, b, c; /* one pointer, two chars */
fprintf(file2, "%s", x); should be fprintf(file2, "%c", *x);
The first form treats x as the beginning of a string and will output
everything from that point onward until it hits a NUL terminator. You
want to output only one char, so use the %c specifier, and
dereference x to get a char.
A better way would be fwrite(x, 1, 1, file2);
printf(filename, '\O'); is not needed and doesn't do what you think.
It looks like you intended to write a NUL at the end. That would be
'\0' (zero), not '\O' (letter O). In any case, it's not needed or
wanted. NUL is used to terminate a string in C, not a file. Your output
file will be one character longer than it should be if you do this.
The most important issue with your code is here
char* x = &buffer + k;
fprintf(file2, "%s", x);
perhaps you mean
char *x = buffer + k;
fprintf(file2, "%c", *x);
You also, are mixing IO functions. For a FILE * object you should use fread() instead of read(), there should be an incompatible arguments warning from the compiler.
If there are no warnings (BTW char *x = &buffer + k should trigger another warning), then you should probably enable them explicitly so that your compiler can help you figure out other problems.
Also, check that file1 is not NULL after fopen(), check that fread() did read the requested amount, in general check for every possible error which you can easily infer from the return value of the implied function, if you don't know the meaning of such value then READ THE DOCUMENTATION before using such function.
And finally all together:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
int read_file(char* filename, char **buffer) {
FILE* file1;
file1 = fopen(filename, "r");
//gets the size of the file
struct stat st;
stat(filename, &st);
int size = st.st_size;
*buffer = malloc(size);
fread(*buffer, size, 1, file1);
fclose(file1);
return size;
}
void write_file(char* filename, char*buffer, int size) {
FILE* file2 = fopen(filename, "w"); int k;
for (k = size - 1; k >= 0; k--) {
fwrite(buffer + k, 1, 1, file2);
}
fclose(file2);
}
int main(int argc, char *argv[]) {
char* buffer;
char* filename1;
char* filename2;
int filesize;
filename1 = "input.txt";
filename2 = "reverse.txt";
filesize = read_file(filename1, &buffer);
write_file(filename2, buffer, filesize);
free(buffer);
return 0;
}
with a live demo. Please add checks for all return values, like malloc() does not return NULL.

Using fgets to read through file in C

I am trying to read through the file given then tokenize it. The only problem im having is fgets.The file open recieves no errors. I have seen this elsewhere on the site however no matter how i set this up including setting fileLine to a set amount like (char fileline [200]) i get a segmentation fault. Thanks in advance for any help.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char *argv[]){
char *fileName = "0";
char *tokenize, *savePtr;
struct Record *database= malloc(sizeof(database[0]));
int recordNum =0;
char *fileLine = malloc(sizeof(char *));//have replaced with fileline[200] still didnt work
FILE *fd = open(fileName,O_RDWR);
if(fd< 0){
perror("ERROR OPENING FILE");
}
while(fgets(fileLine,200,fd) !=NULL){
printf("%s\n", fileLine);
tokenize = strtok_r(fileLine,",",&savePtr);
while(tokenize != NULL){
//TOKENIZING into a struct
}
}
Why use open() with FILE? Use fopen() instead.
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *fileName = "test.txt";
char *tokenize, *savePtr;
char fileLine[200] = {0}; // init this to be NULL terminated
FILE *fd = fopen(fileName, "r");
if (fd == 0) { // error check, equal to 0 as iharob said, not less than 0
perror("ERROR OPENING FILE");
return -1;
}
while (fgets(fileLine, 200, fd) != NULL) {
printf("%s\n", fileLine);
tokenize = strtok_r(fileLine, ",", &savePtr);
while (tokenize != NULL) {
tokenize = strtok_r(NULL, ",", &savePtr); // do not forget to pass NULL
//TOKENIZING into a struct
}
}
return 0;
}
As Weather Vane said, fd < 0 would work if you used open(). However, with fopen(), you should check to see if the pointer is NULL, ecquivalently fd == 0.
A comparison between this functions that open a file can be found in:
open and fopen function
C fopen vs open
The way I have it in mind is that fopen() is of higher level.
This line
char *fileLine = malloc(sizeof(char *));
allocates memory for a char * type, 4 or 8 bytes (depending on the platform).
So when you do
fgets(fileLine,200,fd)
it expects there to be 200 bytes of memory available.
Try this:
char *fileLine = malloc(200);
if (fileLine == NULL) { ... } // check for error
which will allocate the memory required.
You are using open() instead of fopen().
You can't be sure that the file did open correctly because fopen() does not return an integer, but a pointer to a FILE * object, on failure it returns NULL, so the right codition is
FILE *file;
file = fopen(filename, "r");
if (file == NULL)
{
perror("fopen()");
return -1;
}
In your code, you still go and use fgets() even when the fopen() fails, you should abort the program in that case.
Also, malloc() takes the number of bytes as the size parameter, so if you want fgets() to be limited to read just count bytes, then malloc() should be
char *buffer;
size_t count;
count = 200; /* or a value obtained someway */
buffer = malloc(count);
if (buffer == NULL)
{
fclose(file);
perror("malloc()");
return -1;
}
All the problems in your code would be pointed out by the compiler if you enable compilation warnings.

Function mallocs a pointer and reads data into it, but caller can not access it

I have a specific problem: I have an issue when I try to use my own function to load file on memory.
load_file_on_memory() receives a filename and a pointer. It just opens the file, allocates memory dynamically for file content and fills it, and passes the pointer to the caller using destiny as an argument.
But I have a problem: Inside load_file_on_memory() function, I have success on malloc space for content. I can put data on pointer and get it, too.
When I try to use the pointer outside function, the caller just gets trash. I will post my code (shortly) here.
I can't understand why this happen. I am using Windows 7 with Tiny C Compiler. I don't know if that environment can cause errors.
Here's my source
#include <stdio.h>
#include <stdlib.h>
int load_file_on_buffer(char filename[], void *buffer_destiny){
FILE *file_loaded;
unsigned int file_size;
file_loaded = fopen(filename, "rb");
if(file_loaded == NULL)
return -1;
fseek(file_loaded, 0, SEEK_END);
file_size = ftell(file_loaded);
fseek(file_loaded, 0, SEEK_SET);
buffer_destiny = (void *) malloc(file_size);
fread((char *) buffer_destiny, file_size, 1, file_loaded);
printf("BEGIN DEBUG FILE\n");
printf("%s", buffer_destiny);
printf("\n\nEND DEBUG FILE\n");
fclose(file_loaded);
return 0;
}
int main(int argc, char *argv[]){
char *buffered_input_file;
///First, load input file
if(load_file_on_buffer("test.txt", (void *)buffered_input_file) != 0)
return -1;
printf("Input file loaded successfully\n");
printf("This function must print file content: \n\n");
printf("%s", buffered_input_file);
}
You are passing a parameter void* buffer_destiny. Once the function is entered, this is just a normal variable. Which you overwrite using a malloc () call. This has no effect on the calling function. Instead declare the function as
int load_file_on_buffer(char filename[], void **pbuffer_destiny)
call it as
void* buffered_input_file;
load_file_on_buffer("test.txt", &buffered_input_file)
and in the function write
void* buffer_destiny = malloc (...);
*pbuffer_destiny = buffer_destiny;
The pointer buffer_destiny is a local variable in the function load_file_on_buffer. Changing buffer_destiny has no effect on the pointer buffer_input_file in main. One way to fix the problem is to return the pointer to main.
Another problem is that you're using "%s" to print the files content. In order for that to work, you need to properly NUL terminate the buffer. In other words, the buffer needs to be one byte bigger than the file size and a NUL terminator '\0' needs to be placed in that extra byte.
#include <stdio.h>
#include <stdlib.h>
char *load_file_on_buffer( const char *filename )
{
FILE *file_loaded;
unsigned int file_size;
file_loaded = fopen(filename, "rb");
if(file_loaded == NULL)
return NULL;
fseek(file_loaded, 0, SEEK_END);
file_size = ftell(file_loaded);
fseek(file_loaded, 0, SEEK_SET);
char *buffer_destiny = malloc(file_size + 1);
fread( buffer_destiny, file_size, 1, file_loaded );
buffer_destiny[file_size] = '\0';
printf("BEGIN DEBUG FILE\n");
printf("%s", buffer_destiny);
printf("\n\nEND DEBUG FILE\n");
fclose(file_loaded);
return buffer_destiny;
}
int main(int argc, char *argv[])
{
char *buffered_input_file;
///First, load input file
if( (buffered_input_file = load_file_on_buffer("test.txt")) == NULL )
return -1;
printf("Input file loaded successfully\n");
printf("This function must print file content: \n\n");
printf("%s", buffered_input_file);
}
If you still want to pass the buffered_input_file as a parameter then this will work for you, I commented the code at some parts I believe clarification is required.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int load_file_on_buffer(char filename[], void **buffer_destiny)
{
FILE *file_loaded;
unsigned int file_size;
if (buffer_destiny == NULL)
return -1;
*buffer_destiny = NULL; /* to check in the calling function */
file_loaded = fopen(filename, "r"); /* rb is no longer needed in new code */
if(file_loaded == NULL)
return -1;
fseek(file_loaded, 0, SEEK_END);
file_size = ftell(file_loaded);
fseek(file_loaded, 0, SEEK_SET);
*buffer_destiny = malloc(1 + file_size); /* +1 for the null terminator */
if (*buffer_destiny == NULL)
{
fclose(file_loaded);
return -1;
}
/* add a null terminator so the string is acceptable by printf */
memset(*buffer_destiny + file_size, '\0', 1);
/* you got this wrong
*
* fread((char *) buffer_destiny, file_size, 1, file_loaded);
*
* the correct way is
*
* fread(void *ptr, size_t size, size_t count, FILE *fp);
*
* where size is the size of each element and count is the number of elements.
*/
if (fread(*buffer_destiny, 1, file_size, file_loaded) != file_size)
{
free(*buffer_destiny);
*buffer_destiny = NULL;
fclose(file_loaded);
return -1;
}
printf("BEGIN DEBUG FILE\n");
printf("%s", (char *)*buffer_destiny);
printf("END DEBUG FILE\n");
fclose(file_loaded);
return 0;
}
int main(int argc, char *argv[])
{
char *buffered_input_file;
if (load_file_on_buffer("data.dat", (void **)&buffered_input_file) != 0)
return -1;
printf("Input file loaded successfully\n");
printf("This function must print file content: \n\n");
printf("%s", buffered_input_file);
free(buffered_input_file);
return 0;
}
buffered_input_file is NULL initially in main() and passed to load_file_on_buffer() by value. buffer_destiny initially got NULL from main() but inside function after memory allocation it should behave normally as you mentioned. However buffer_destiny is a local variable not a pointer for passed variable, hence at the end of function it loses its information and buffered_input_file in main() is still NULL.

Read From File and Store Strings into a Multidimensional Array of Strings in C

I really need to know how to fix this.
I have a file that is read and I store the strings from the file into an array that is passed as an argument, but I can't figure out how to make it work.
When I do print the content of the array it says null.
So how do I pass a multi-dimensional array of strings to readfiles() and make it save the strings in the array passed as parameter, each string in one position?
Thanks for the help.
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <stdio.h>
#include <strings.h>
#define max_chars_string 10000
#define n_strings 100
int main(int argc, char **argv)
{
char *filename;
char strings_hashes[n_strings][max_chars_string];
char * pointer_string = &strings_hashes[0][0];
int n_lines;
int i = 0;
filename = (char*)malloc(strlen(argv[1])*sizeof(char));
if(argc !=3){
fprintf(stderr, "Usage : %s [text_file] [cores]",argv[0]);
exit(0);
}
strcpy(filename,argv[1]);
read_lines(filename,pointer_string);
for(i = 0; i<n_lines;i++){
printf("%s \n",strings_hashes[i][max_chars_string]);
}
return 0;
}
void read_lines(char * filename, char *pointer){
FILE *fp;
char str[max_chars_string];
int i =0;
if((fp = fopen(filename, "r"))==NULL) {
printf("Cannot open file.\n");
exit(1);
}
while(!feof(fp)) {
while(fgets(str, sizeof str, fp)) {
strcpy(pointer, str);
printf("%s", str);
pointer++;
i++;
}
}
fclose(fp);
}
Change
void read_lines(char * filename, char *pointer){
to
void read_lines(char * filename, char (*pointer)[max_chars_string]){
(pointer's type needs to be "pointer to array of max_chars_string chars". When using pointers to access multidimensional arrays, the pointer type needs to know the all the dimensions except for the outermost one, so that it knows how far to skip along when incremented.)
Change
strcpy(pointer, str);
to
strcpy(*pointer, str);
Now call it as
read_lines(filename,strings_hashes);
(This is equivalent to the following, which may be clearer:)
read_lines(filename,&string_hashes[0]);
Finally, you want to print a string not an individual character, so use
printf("%s \n",strings_hashes[i]);

Resources