fprintf printing a bunch of NULLs at the beginning - c

typedef struct record
{
float field1;
char *name;
} record;
void printRecordsTo(record **s, char *fileName, int size)
{
initializePrinter(fileName);
int i = 0;
while (i < size)
{
printRecordToFile(s[i]);
i++;
}
closePrinter();
}
static int delete = 0; // TODO: Remove
void printRecordToFile(record *r)
{
if (!file)
{
puts("Printer not initialized");
exit(1);
}
printf("%d %s", delete ++, toString(r)); // prints all correctly to stdout
fprintf(file, "%s", toString(r)); // includes many NULLs
}
char *toString(record *s)
{
float field1 = s->field1;
int len = 4;
char *field1Str = malloc(len + 1);
snprintf(field1Str, len + 1, "%f", field1);
char *name = s->name;
char *buf = malloc((1024) * sizeof(char));
snprintf(buf, 1023, "%s%s%s%s%s\n", "(", name, ", ", field1Str, ")");
return buf;
}
I can't figure out why many NULLs are being printed by the fprintf for large files (of size ~1000 records). The function works fine for the small files (of size ~20 records) I used. I tested it against normal printf which prints the string representations of records correctly.

Drop toString() function from source, it's redundant.
Use below statements instead in printRecordToFile()
printf ("%d (%s, %f)", delete++, r->name, r->field1);
fprintf (file, "(%s, %f)", r->name, r->field1);
Use meaningful names for structure attributes/members.
If you're still seeing garbage values, then perhaps you need to sit with a debugger to find out where structure data is being corrupted. With the info at hand we can only guess.
Use Valgrind to trace memory error & leaks. It's a pretty nifty tool for C programmers.

Related

Variable changed after function gets called again in C

I created a struct and a function that returns that struct.
Afterwards I'm calling that function twice, each time assigned to a different variable.
The problem is that the first variable changes after the second run.
What am I missing here?
code:
struct text_and_len {
char* text;
int len;
};
struct text_and_len get_text_and_length(){
int len;
scanf("%d ", &len);
char text[len];
fgets(text, len+1, stdin);
return (struct text_and_len) {text, len};
}
void get_input_and_check_is_within(){
struct text_and_len b = get_text_and_length();
printf("%s \n", b.text);
struct text_and_len a = get_text_and_length();
printf("%s \n", a.text);
printf("%s \n", b.text);
this will first print the b.text, but then will print the a.text twice.
These lines used in get_text_and_length()():
char text[len];
fgets(text, len+1, stdin);//over writes buffer by at least 1, 2 if wanting a C string. Will cause undefined behavior.(UB)
will potentially allow user to enter input that would over write the buffer.
The code as is also includes variables that reach end of life before they are needed else where, resulting in predictable, but unwanted behavior.
Also the member in the struct char* text; requires memory be allocated before being written to. Thus will also require freeing.
Below is your code refactored to address these, with some other modifications to the prototypes and calling methods that simplify the writing of the code...
struct text_and_len {
char* text;
int len;
};
void get_text_and_length(struct text_and_len *b){
printf("Enter max length of input string\n");
scanf("%d ", &(b->len));
//b->text[b->len];//VLA, but has already been declared as char *
b->text = malloc(b->len + 2);//room for NULL terminator AND newline
memset(b->text, 0, b->len+2);//zero variable to all NULL
//fgets(text, len+1, stdin);//text has no memory
//and as is would have over-written
//buffer - UB
printf("Enter string no longer than max length\n");
fgets(b->text, b->len+2, stdin);//note len+2 provides room
//for len char + NULL + newline
}
void get_input_and_check_is_within(struct text_and_len *b){
get_text_and_length(b);
printf("max length: %d \n", b->len);
printf("text entered:%s \n", b->text);
}
int main(void)
{
struct text_and_len a = {0};
get_input_and_check_is_within(&a);
free(a.text);//allocated in get_text_and_length()
return 0;
}

Accessing values from user-defined functions

I've got a (I think) pretty easy question that I need help with. I'm working on learning pointers with called user-defined functions in C.
I've got two functions, my main() and another which pulls certain data from a file, read_file(). Read_file() pulls data from a specified file - an integer, (coeff_num) and a series of values (coeff_values) - and prints out the data. Then main() is meant to reprint this data as a check, to ensure that it's being called correctly in order to perform further calculations.
My problem is this: everything is printing out fine in the read_file() function. While checking in main(), data_num is printing out fine, but data_values isn't.
The code (with some irrelevant bits edited out, mainly error checking stuff) is as follows:
int read_file(int *data_num, double **data_values, char *filename);
int main()
{
int data_num;
double **data_values;
char *filename[] = {/*FILES*/};
read_fule(&data_num, data_values, *filename);
printf("Check Number:\n%u\n", data_num);
printf("Check Values:\n);
for(int i = 0; i<data_num; i++)
{
printf("%u\t", data_values[i]);
}
return(0);
}
and:
int read_file(int *data_num, double **data_values, char *filename)
{
FILE * fp = fopen(filename, "rb"); //Opening file
/* Error checking code here - see if file opens, find length
return if not long enough, etc */
//Find number of values
char buffer_n[4];
fread(buffer_n, 4, 1, fp);
int result = buffer_n[0]|(buffer_n[1] << 8)|(buffer_n[2] << 16)|(buffer_n[3] << 24); //Change endian
*data_num = result;
/* Instructed to allocate memory */
data_values = malloc(8*result); //Allocating memory
//Reads data values
fread(data_values, 8, result, fp);
//Prints results as float
printf("Number of data values: %d \n", result);
for(int i=0; i<result; i++)
{
printf("%0.3f\t", data_values[i]);
}
fclose(fp);
return 1;
}
I'm fairly certain that this is an issue with my pointers. For the program, I have to use malloc() when reading data_values, and read_file has to have the prototype of: int read_file(int *data_num, double **data_values, char *filename). Can someone give me some guidance about where I've messed up?
Cheers for any help, it'd be greatly appreciated.
I set result = 30 as you told me, changed a few places, and I think now it works fine.
I think you don't need double** pointer, what you need is double* pointer.
And you need cast the void* to double*:
data_values = (double*)malloc(8*result); //Allocating memory
This code works fine:
//data_values should be defined as double*
int read_file(int *data_num, double *data_values, char *filename)
{
FILE * fp = fopen(filename, "rb"); //Opening file
/* Error checking code here - see if file opens, find length
return if not long enough, etc */
//Find number of values
char buffer_n[4];
size_t i;//added
fread(buffer_n, 4, 1, fp);
//int result = buffer_n[0]|(buffer_n[1] << 8)|(buffer_n[2] << 16)|(buffer_n[3] << 24); //Change endian
int result = 30;
*data_num = result;
/* Instructed to allocate memory */
data_values = (double*)malloc(8*result); //Allocating memory
//Reads data values
fread(data_values, 8, result, fp);
//Prints results as float
printf("Number of data values: %d \n", result);
for(int i=0; i<result; i++)
{
printf("%0.3f\t", data_values[i]);
}
fclose(fp);
return 1;
}
Edit:
If you want to use double**, you can try this solution:
/* Instructed to allocate memory */
data_values[0] = (double*)malloc(8 * result); //Allocating memory
//Reads data values
fread(data_values[0], 8, result, fp);
//Prints results as float
printf("Number of data values: %d \n", result);
for(int i=0; i<result; i++)
{
printf("%0.3f\t", data_values[0][i]);
}
But you have to notice that this is not a form, this is still used as an array, so you may change it later according to your situation.

Dynamic formatted string from another function

I have a function A with a body like so
char* A (const char* arg) {
char ret[8192];
B(ret);
return strdup(ret);
}
Function B looks like this (some pseudo code on iteration logic for brevity)
void B(char* ret) {
char retString[8192];
while(ITERATIONS_LEFT) {
snprintf(returnString, 8192, "\n Format %s\n\n", IT_VALUE);
snprintf(returnString, 8192, "\n Val %s\n\n", IT_VALUE_2);
}
strcpy(ret, returnString);
}
So essentially I have a function A that gives another function B a string buffer for B to enter formatted data into. Now this works fine as long as the total data returned from the iterations does not exceed 8196 (just a guess at a 'sufficiently large' value) but I think it would be better if I could do this dynamically and not have to worry about the case where my buffer fills. How would I achieve this in a fairly efficient manner, with the constraints that function A must still call function B, and that B's signature can be changed but A's cannot?
In addition to your allocation problem, you overwrite the same string here:
snprintf(returnString, 8192, "\n Format %s\n\n", IT_VALUE);
snprintf(returnString, 8192, "\n Val %s\n\n", IT_VALUE_2);
You could solve this with a kind of "appender" that re-allocates memory as it is needed by determining the required length by passing a size of 0 to snprintf as Joachim Pileborg suggested:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
struct append_t {
char *str; /* string */
size_t len; /* length of string */
size_t size; /* allocated size */
};
void append(struct append_t *app, const char *fmt, ...)
{
va_list arg;
size_t len;
va_start(arg, fmt);
len = vsnprintf(NULL, 0, fmt, arg);
va_end(arg);
while (app->len + len + 1 >= app->size) {
app->size = app->size ? app->size * 2 : 0x100;
app->str = realloc(app->str, app->size);
// Check and handle error
}
va_start(arg, fmt);
len = vsnprintf(app->str + app->len, app->size - app->len, fmt, arg);
va_end(arg);
app->len += len;
}
int main(int argc, char **argv)
{
struct append_t app = {NULL};
for (int i = 1; i < argc; i++) {
if (i > 1) append(&app, ", ");
append(&app, "'%s'", argv[i]);
}
if (app.str) puts(app.str);
free(app.str);
return 0;
}
Things to note:
The code uses the fact that realloc(NULL, size) behaves like malloc(size). The appender must be initialised to all zero.
vsnprintf is a variant of snprintf that takes a va_list instead of variadic arguments. The v...printf functions allow you to write your own printf-like functions. You can't pass variadic arguments to other functions, you have to create a va_list with the va_... macros from the <stdarg.h> header.
Most compilers can detect mismatches between printing formats and arguments for the standard printf functions. If you wat to benefit from these checks for your function, you could use the appropriate GCC attributes ((format(printf, 2, 3)) or the SAL annotation _Printf_format_string_.
In your example, A would create the appender and pass it to B and then return its .str. You could also return an appender from B and return its .strfrom A.
I suggest the following versions of A and B.
char* A (const char* arg) {
int size = 8192;
char *ret = malloc(size);
B(ret, size);
return ret;
}
void B(char* ret, int size) {
int pos = 0, required;
while(ITERATIONS_LEFT) {
required = snprintf(NULL, 0, "\n Format %s\n\n", IT_VALUE);
if (pos + required >= size) {
size *= 2;
ret = realloc(ret, size);
}
pos += sprintf(ret + pos, "\n Format %s\n\n", IT_VALUE);
required = snprintf(NULL, 0, "\n Val %s\n\n", IT_VALUE_2);
if (pos + required >= size) {
size *= 2;
ret = realloc(ret, size);
}
pos += sprintf(ret + pos, "\n Val %s\n\n", IT_VALUE_2);
}
}
Note that:
buffer size is doubled if it isn't enough. That works well in most cases.
copying is minimized (no strdup or strcpy)
you may want to make a new function with the repeated code in the while loop
In your version of B buffer is overwritten each time you call snprintf. Here the writing position (pos) is updated to append (null terminating char overwritten)
snprintf with NULL argument will return the required buffer size without printing anything anywhere
You may want to check that ret is not NULL after calling realloc
If ret is not NULL it's certain that the buffer is large enough. Thus simple sprintf is used to actually print.
Remember to free the buffer!
I haven't tested the code myself

free() caused segmentation fault

In this program, there is a segmentation fault. The program can print out "loop end" successfully and segmentation fault appeared after "loop end", which means there is not error in read_name function. But I could not figure out any error in my free_memory function. Could anyone help me figure out? Thank you.
input file:
9
Clinton, Hillary R.
Bonds, Bobby S.
Bonds, Barry L.
Clinton, William I.
Clinton, Chelsea T.
Bush, Laura M.
Bush, George W.
Bush, Jenna F.
Bush, Barbara G.
program:
#include <stdio.h>
#include <malloc.h>
#include<string.h>
void alloc(char ***surname, char ***first, char **mid_init, int num);
void read_names(FILE *inp, char **surname, char **first, char *mid_init, int num );
void free_memory(char **surname, char **first, char *mid_init, int num);
int main(int argc, char *argv[])
{
int num = 0;
char **surname, **first, *mid_init;
FILE *inp = fopen(argv[1], "r");
FILE *outp = fopen(argv[2], "w");
char array[79];
fscanf(inp, "%d", &num);
printf("%d\n", num);
fgets(array, 79, inp);
alloc(&surname, &first, &mid_init, num);
read_names(inp, surname, first, mid_init, num);
free_memory(surname, first, mid_init, num);
fclose(inp);
fclose(outp);
return 0;
}
void alloc(char ***surname, char ***first, char **mid_init, int num)
{
int i;
*surname = (char**)malloc(num * sizeof(char*));
*first = (char**)malloc(num * sizeof(char*));
*mid_init = (char*)malloc(num * sizeof(char));
for(i=0; i<num; i++)
{
(*surname)[i] = (char*)malloc(15*sizeof(char));
(*first)[i] = (char*)malloc(10*sizeof(char));
}
}
void read_names(FILE *inp, char **surname, char **first, char *mid_init, int num )
{
char *token, array[79];
char delim[6] = ", .\n";
int i=0;
fgets(array, 79, inp);
printf("loop begins\n");
for(i=0; i<num; i++)
{
fgets(array, 79, inp);
printf("%s", array);
token = strtok(array, delim);
strcpy( (surname[i]), token);
printf("%s ", (surname[i]));
token = strtok(NULL, delim);
strcpy( (first[i]), token);
printf("%s ", (first[i]));
token = strtok(NULL, delim);
*mid_init = token[0];
printf("%s\n", mid_init);
printf("\n\n");
}
printf("\nloop ends\n");
}
void free_memory(char **surname, char **first, char *mid_init, int num)
{
int i;
for(i=0;i<num;i++)
{
free((surname)[i]);
free((first)[i]);
}
free(surname);
free(first);
free((mid_init));
}
First off, you're limiting yourself to 14-character first names and 9-character last names, so that would be the first thing I'd check, that your names aren't longer than this.
If they are, you'll probably corrupt the memory arena when copying them.
One way to check this is to simply print the length of token every time you set it, such as:
token = strtok(array, delim);
printf ("DEBUG: token length is %d\n", strlen (token));
Keep in mind that corruption does not necessarily have a visible immediately or even ever. In this case, what's most likely happened is that you've overwritten a vital piece of inline control information in the memory arena, such as a memory block size or a pointer to another memory block.
However, there's no code actively checking for that when you write to memory so it's probably only found when you next try to do a memory allocation or de-allocation call.
Your next call like this after the corruption is your free calls and that's almost certainly where it's being found, because the arena is corrupt.
Bottom line, writing beyond the end of allocated memory is undefined behaviour. That means you shouldn't do it.
If it turns out your names aren't too long (as you state in a comment), you need to then ask yourself why you have a superfluous fgets(array, 79, inp); in your code. I understand why it's needed in main so as to move to the next line after inputting the line count with a call to fscanf. And that one does its job well.
However, you have another one at the start of read_names which effectively throws away the first name in your list. That's going to cause problems because, while your code thinks there are X names in the file, you've thrown away the first one meaning that there are only X - 1 remaining. You can tell this because, when you begin to print out the names, the first one from the file appears to be missing.
If you remove the fgets at the start of read_names, you should find it's okay.
As an aside, there's a couple of other changes I'd make to the code. First you really should check all those malloc calls in case one of them fails. That's the general rule for all functions that can fail when you rely later on them not having failed.
Second, I'm not really a big fan of ever multiplying by sizeof(char) - this is guaranteed by the standard to always be 1, so multiplying by it clogs up the code and makes it less readable.
Try replacing
token = strtok(NULL, delim);
*mid_init = token[0];
printf("%s\n", mid_init);
with
token = strtok(NULL, delim);
mid_init[i] = token[0];
printf("%c\n", mid_init[i]);
When mid_init memory chunk is filled with garbages without any null in it, 'printf("%s\n", mid_init);' might read beyond the data segment causing segmentation fault.
But #paxdiablo's answer has a much better chance to be the case here.
#Bruce, segmentation fault doesn't always appear at the exact spot it happened.
I don't know why you are getting a segmentation fault, but if I was writing this, I would try and make it a bit simpler (I don't think you are doing yourself any favors) - it makes no sense to pass around something like char ***surname.
This is only my personal opinion, but I would do something like this:
#include <stdio.h>
#include <malloc.h>
typedef struct {
char **data;
unsigned int count;
unsigned int actualSize;
} StringArray;
void StringArray_init(StringArray *array)
{
array->count = 0;
array->actualSize = 0;
}
void StringArray_add(StringArray *array, char* value)
{
if (array->actualSize == 0)
{
array->data = (char**)malloc(sizeof(char*)* 4);
array->actualSize = 4;
}
else
{
if (array->count >= array->actualSize)
{
array->actualSize *= 2;
array->data = (char**)realloc(array->data,sizeof(char*) * array->actualSize);
}
}
array->data[array->count] = value;
array->count++;
}
char* StringArray_get(StringArray *array, unsigned int position)
{
if (position < array->count)
return array->data[position];
else
return 0;
}
void StringArray_clear(StringArray *array)
{
if (array->count >0) free(array->data);
array->count = 0;
array->actualSize = 0;
}
int main ()
{
StringArray surname;
StringArray_init(&surname);
StringArray_add(&surname, "Smith");
StringArray_add(&surname, "Jones");
for(int i=0;i<surname.count;i++)
{
printf("%s\n", StringArray_get(&surname,i));
}
StringArray_clear(&surname);
}
What the above code is doing is allocating memory when you add a value, but instead of allocating space for one item, it adds enough for four. If you get to the point where you add a fifth, it will then double the space to 8 items. This method should help with memory fragmentation. I'm also using a structure, which just makes it a bit easier to pass this array around.
I could also do something like this if I wanted to allocate memory for the strings (just include the string.h header):
int main ()
{
StringArray surname;
StringArray_init(&surname);
char *name = (char*)malloc(sizeof(char) * 6);
strcpy(name,"Smith");
StringArray_add(&surname, name);
name = (char*)malloc(sizeof(char) * 6);
strcpy(name,"Jones");
StringArray_add(&surname, name);
for(int i=0;i<surname.count;i++)
{
printf("%s\n", StringArray_get(&surname,i));
}
// Free memory
for(int i=0;i<surname.count;i++)
{
char *name = StringArray_get(&surname,i);
if (name != NULL) free(name);
}
StringArray_clear(&surname);
}
The size of each name is 6 because there are 5 characters and an extra one for 0, which is the string terminator.
Sorry if this doesn't directly answer your question, but hope it helps.
Bruce,
In your data file, you need a blank line between the number and list of names because of the first fgets() at the beginning of read_names() consumes the second line.
Because the program skipped the second line, it could read only 8 names and the last line read was a blank line, which caused strtok to return a null and the next strcpy tried to read from address 0, which is, of course, a segmentation fault.
And in my machine, the fault happened before printing "loop ends".
You need to check the return values of function calls (strtok in this case) for possible errors. Otherwise you will be wasting a lot of time debugging like this.

2D Array Malloc

Below is a part of a longer code where malloc'ing for a 2D array is done. Could anyone tell if this is correct? If I introduce static values, the code works fine. Else, seg faults...
enum { LEN = 1024*8 };
char **tab = NULL;
int cur_LEN = LEN;
int count_lineMax = 0;
tab = malloc(count_lineMax * sizeof(*tab));
memset(tab, 0, count_lineMax * sizeof(*tab));
if(tab == NULL && count_lineMax) {
printf("Mem_check\n");
exit(1);
}
for(k=0;k<count_lineMax;k++) {
tab[k] = malloc(cur_LEN*sizeof(*tab[k]));
memset(tab[k], 0, cur_LEN*sizeof(*tab[k]));
if(tab[k] == NULL) {
printf("Mem_check*\n");
exit(1);
}
}
for(l=0;l<count_lineMax;l++) {
free(tab[l]);
}
free(tab);
int count_lineMax = 0;
tab = malloc(count_lineMax * sizeof(*tab));
What is this? You are gonna malloc 0 bytes?
There are at least two ways to build the table while reading lines. One uses the property of realloc() that if its first argument is a null pointer, it will behave like malloc() and allocate the requested space (so the code can be self-starting, using realloc() alone). That code might look like:
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { LEN = 1024*8 };
static void error(const char *fmt, ...);
static char *xstrdup(const char *str);
int main(void)
{
char line[LEN];
char **tab = NULL;
int tabsize = 0;
int lineno = 0;
while (fgets(line, sizeof(line), stdin) != 0)
{
if (lineno >= tabsize)
{
size_t newsize = (tabsize + 2) * 2;
char **newtab = realloc(tab, newsize * sizeof(*newtab));
if (newtab == 0)
error("Failed to allocate %zu bytes of memory\n", newsize * sizeof(*newtab));
tab = newtab;
tabsize = newsize;
}
tab[lineno++] = xstrdup(line);
}
/* Process the lines */
for (int i = 0; i < lineno; i++)
printf("%d: %s", i+1, tab[i]);
/* Release the lines */
for (int i = 0; i < lineno; i++)
free(tab[i]);
free(tab);
return(0);
}
static void error(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
exit(1);
}
static char *xstrdup(const char *str)
{
size_t len = strlen(str) + 1;
char *copy = malloc(len);
if (copy == 0)
error("Failed to allocate %zu bytes of memory\n", len);
memmove(copy, str, len);
return(copy);
}
The alternative uses malloc() explicitly when the table is empty, and is most simply coded as:
int main(void)
{
char line[LEN];
int tabsize = 4;
int lineno = 0;
char **tab = malloc(tabsize * sizeof(*tab));
if (tab == 0)
error("Failed to allocate %zu bytes of memory\n", tabsize * sizeof(*tab));
...
Everything else can remain untouched.
Note that it can be convenient to have functions xmalloc() and xrealloc() which are guaranteed never to return a null pointer because they report an error instead:
static void *xmalloc(size_t nbytes)
{
void *space = malloc(nbytes);
if (space == 0)
error("Failed to allocate %zu bytes of memory\n", nbytes);
return(space);
}
static void *xrealloc(void *buffer, size_t nbytes)
{
void *space = realloc(buffer, nbytes);
if (space == 0)
error("Failed to reallocate %zu bytes of memory\n", nbytes);
return(space);
}
In the long term (big programs), this cuts down on the total number of times you write 'out of memory' error messages. On the other hand, if you must recover from memory allocation failures (save the user's work, etc), then this is not an appropriate strategy.
The code above creates a ragged array; different entries in tab have different lengths. If you want homogeneous lengths (as in the original code), then you have to replace or modify the xstrdup() function to allocate the maximum length.
You might have noticed that the code in xstrdup() used memmove() instead strcpy(). That's because strlen() already measured how long the string is, so there's no need for the copy code to test each byte to see whether it needs copying. I used memmove() because it can never go wrong, even if the strings overlap, even though in this context it is clear that the strings can never overlap and so memcpy() - which is not guaranteed to work correctly if the strings overlap - could have been used since the strings cannot overlap.
The strategy of allocating (oldsize + 2) * 2 new entries means that the memory reallocation code is exercised often enough during testing, without unduly impacting performance in production. See The Practice of Programming by Kernighan and Pike for a discussion of why this is a good idea.
I almost always use a set of functions similar to the error() function because it dramatically simplifies error reporting. The functions I normally use are part of a package that records and reports the program name (from argv[0]) as well, and that has a fairly wide range of alternative behaviours.

Resources