C - fprintf() & printf() deleting array element memory - c

I fairly new to C Programming, but fprintf() & printf() is behaving strangely and I'm so confused on why--I need some help understanding and diagnosing this issue.
fprintf() Deleting Element of Array
First off, I'm passing in a populated malloc allocated four element char** array into a simple function that will write to a file, everything in the array appears normal and all four elements contain the correct data. The function call in main() looks like this. My array in question is header.
Note: I had to cast this normal (char** array) as a constant in this function parameter, due to the function header parameter. Our professor gave us the header file and we cannot change anything in them.
pgmWrite((const char**) header, (const int**) matrix,
rowPixels, colPixels, outFile);
Next, stopping debugger just before it executes the fprintf() & printf() functions, screenshot showing the array is still populated with my 4 elements.
pgmWrite() - Showing array is still fine
Observe the 4th element of the array after execution of fprintf().
After fprintf() executes, element 3 memory is wiped out.
When run, printf() executes the printing of the array exactly what is shown in the debugger, ending at the 3rd element. Often printing nothing in that spot or in rare cases garbage characters. The behavior of printf() is exactly the same as how fprintf() is working as well.
I'm at a loss here guys, please help me understand what I'm doing wrong. I can only provide these two screenshots, based on me being a new member. I'll try to provide as much information as possible. Thank you. Here is a simplified version of my program. Keep in mind, the professor gave us the function declarations and told us we cannot change them. So, I have to work with what I have here. Also, since this is fileIO, you need to find a *.pgm file to test this.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define rowsInHeader 4
#define maxSizeHeadRow 200
int ** pgmRead( char **header, int *numRows, int *numCols, FILE *in ){
// INITIALIZING
char *headArr[rowsInHeader][maxSizeHeadRow];
char buffer[100];
int r = 0;
fpos_t pos;
// CREATE: Header
while (r < 4){
// IF: Row in pgm file header lists the dimensions of matrix
if (r == 2){
// CURSOR: Saving pointer location in file (see notes in header for method reference)
fgetpos(in, &pos);
// ASSIGN: Dereference column and row pointers from file
fscanf(in, "%d %d", numCols, numRows);
// CURSOR: Moving back to saved pointer location (see notes in header for method reference)
fsetpos(in, &pos);
}
// ASSIGN: Copying header row into array
fgets(buffer, maxSizeHeadRow, in);
strcpy((char*)headArr[r], buffer);
// POINTER: Reference pointer to headArr[]
header[r] = (char*)headArr[r];
// TRAVERSE: To next row in file
r++;
}
// NOTE: Placeholder for return type
return 0;
}
int pgmWrite( const char **header, const int **pixels, int numRows, int numCols, FILE *out ){
// INITIALIZING
int i = 0;
// WRITE: Header
for (i = 0; i < rowsInHeader; i++){
fprintf(out, "%s", header[i]);
printf("%s", header[i]);
}
return 0;
}
int main(int argc, char *argv[]){
char **header = (char**)malloc(rowsInHeader * sizeof(char));
FILE *inFile = fopen("smallFile.pgm", "r");
FILE *outFile = fopen("TestPicture.ascii.pgm", "w");;
int rowPixels = 0;
int colPixels = 0;
int **matrix = NULL;
// READ & WRITE
matrix = pgmRead(header, &rowPixels, &colPixels, inFile);
pgmWrite((const char**)header, (const int**)matrix, rowPixels, colPixels, outFile);
// FINALIZING
fclose(inFile);
free(header);
return 0;
}

You are not allocating your array correctly. This line:
char **header = (char**)malloc(rowsInHeader * sizeof(char));
makes header point to an uninitialized region of memory , size 4 bytes.
Then inside your PGM function you write:
header[r] = (char*)headArr[r];
The code header[r] means to access the r'th pointer stored in the space pointed to by headArr. But since that space is only 4 bytes big, you're actually writing off into the wild blue yonder.
Also, (char *)headArr[r] is a mistake. If you did not use the cast, your compiler would have warned you about this mistake. You should avoid using casts in your code, especially using them to make warnings go away. You're saying to the compiler "Ssh, I know what I'm doing" when in fact you don't know what you are doing.
The entire approach with headArr is flawed from the start: even if you had actually written the right code to implement what you were trying, you'd be returning pointers into space which is deallocated when the function returns.
Basically the whole pgmRead function is a complete mess and it'd be easier to start from scratch. But this time, think carefully about when and where you are allocating memory, and what the types are of your expressions, and don't use casts. Let the pgmRead function do all the allocation.
(Unfortunately, based on your description it looks like you will have to use your casts to call the pgmWrite function since that has a mistake in its signature. const int ** should be const int * const *, and similarly for const char **. I'd recommend to actually change pgmWrite's signature accordingly, get your program working, and then once everything is good, then go back to the broken version that you are forced to use.)
Reading C FAQ - arrays and pointers might be useful too.

Related

How to fix segfault caused by a realloc going out of bounds?

Hello and TIA for your help. As I am new to to posting questions, I welcome any feedback on how this quesiton has been asked. I have researched much in SO without finding what I thought I was looking for.
I'm still working on it, and I'm not really good at C.
My purpose is extracting data from certain specific tags from a given XML and writing it to file. My issue arises because as I try to fill up the data struct I created for this purpose, at a certain point the realloc() function gives me a pointer to an address that's out of bounds.
If you look at this example
#include <stdio.h>
int main() {
char **arrayString = NULL;
char *testString;
testString = malloc(sizeof("1234567890123456789012345678901234567890123456789"));
strcpy(testString, "1234567890123456789012345678901234567890123456789");
int numElem = 0;
while (numElem < 50) {
numElem++;
arrayString = realloc(arrayString, numElem * sizeof(char**));
arrayString[numElem-1] = malloc(strlen(testString)+1);
strcpy(arrayString[numElem-1], testString);
}
printf("done\n");
return 0;
}
it does a similar, but simplified thing to my code. Basically tries to fill up the char** with c strings but it goes to segfault. (Yes I understand I am using strcpy and not its safer alternatives, but as far as I understand it copies until the '\0', which is automatically included when you write a string between "", and that's all I need)
I'll explain more in dephth below.
In this code i make use of the libxml2, but you don't need to know it to help me.
I have a custom struct declared this way:
struct List {
char key[24][15];
char **value[15];
int size[15];
};
struct List *list; //i've tried to make this static after reading that it could make a difference but to no avail
Which is filled up with the necessary key values. list->size[] is initialized with zeros, to keep track of how many values i've inserted in value.
value is delcared this way because for each key, i need an array of char* to store each and every value associated with it. (I thought this through, but it could be a wrong approach and am welcome to suggestions - but that's not the purpose of the question)
I loop through the xml file, and for each node I do a strcmp between the name of the node and each of my keys. When there is a match, the index of that key is used as an index in the value matrix. I then try to extend the allocated memory for the c string matrix and then afterwards for the single char*.
The "broken" code, follows, where
read is the index of the key abovementioned.
reader is the xmlNode
string contained the name of the xmlNode but is then freed so consider it as if its a new char*
list is the above declared struct
if (xmlTextReaderNodeType(reader) == 3 && read >= 0)
{
/* pull out the node value */
xmlChar *value;
value = xmlTextReaderValue(reader);
if (value != NULL) {
free(string);
string=strdup(value);
/*increment array size */
list->size[read]++;
/* allocate char** */ list->value[read]=realloc(list->value[read],list->size[read] * sizeof(char**));
if (list->value[read] == NULL)
return 16;
/*allocate string (char*) memory */
list->value[read][list->size[read]-1] = realloc(list->value[read][list->size[read]-1], sizeof(char*)*sizeof(string));
if (list->value[read][list->size[read]-1] == NULL)
return 16;
/*write string in list */
strcpy(list->value[read][list->size[read]-1], string);
}
/*free memory*/
xmlFree(value);
}
xmlFree(name);
free(string);
I'd expect this to allocate the char**, and then the char*, but after a few iteration of this code (which is a function wrapped in a while loop) i get a segfault.
Analyzing this with gdb (not an expert with it, just learned it on the fly) I noticed that indeed the code seems to work as expected for 15 iteration. At the 16th iteration, the list->value[read][list->size[read]-1] after the size is incremented, list->value[read][list->size[read]-1] points to a 0x51, marked as address out of bounds. The realloc only brings it to a 0x3730006c6d782e31, still marked as out of bounds. I would expect it to point at the last allocated value.
Here is an image of that: https://imgur.com/a/FAHoidp
How can I properly allocate the needed memory without going out of bounds?
Your code has quite a few problems:
You are not including all the appropriate headers. How did you get this to compile? If you are using malloc and realloc, you need to #include <stdlib.h>. If you are using strlen and strcpy, you need to #include <string.h>.
Not really a mistake, but unless you are applying sizeof to a type itself you don't have to use enclosing brackets.
Stop using sizeof str to get the length of a string. The correct and safe approach is strlen(str)+1. If you apply sizeof to a pointer someday you will run into trouble.
Don't use sizeof(type) as argument to malloc, calloc or realloc. Instead, use sizeof *ptr. This will avoid your incorrect numElem * sizeof(char**) and instead replace it with numElem * sizeof *arrayString, which correctly translates to numElem * sizeof(char*). This time, though, you were saved by the pure coincidence that sizeof(char**) == sizeof(char*), at least on GCC.
If you are dynamically allocating memory, you must also deallocate it manually when you no longer need it. Use free for this purpose: free(testString);, free(arrayString);.
Not really a mistake, but if you want to cycle through elements, use a for loop, not a while loop. This way your intention is known by every reader.
This code compiles fine on GCC:
#include <stdio.h> //NULL, printf
#include <stdlib.h> //malloc, realloc, free
#include <string.h> //strlen, strcpy
int main()
{
char** arrayString = NULL;
char* testString;
testString = malloc(strlen("1234567890123456789012345678901234567890123456789") + 1);
strcpy(testString, "1234567890123456789012345678901234567890123456789");
for (int numElem = 1; numElem < 50; numElem++)
{
arrayString = realloc(arrayString, numElem * sizeof *arrayString);
arrayString[numElem - 1] = malloc(strlen(testString) + 1);
strcpy(arrayString[numElem - 1], testString);
}
free(arrayString);
free(testString);
printf("done\n");
return 0;
}

Stack smashing detected during fread on binary file in C

UPDATE IN BOTTOM====
So a while ago I made the following function, which I successfully used to get the grey values from images (w x h dimension) that were converted to .bin-files. It just gives an array of all pixel values.
It was, however, not as a function like this but put in the main() immediately.
// read the BIN-file as grayscale image
void decodeBIN(const char* filename, short image[], int w, int h){
int i = 0;
unsigned char buffer[16]; // no specific size attributed
FILE *ptr;
ptr = fopen(filename, "rb");
if (!ptr){
printf("\nUnable to open file!\n"); // error
}
while (!feof(ptr)){
fread(buffer,2,1,ptr); // read w bytes to buffer
image[i] = buffer[1];
//printf("%u ", image[i]); // DEBUG
i++;
}
fclose(ptr);
printf("\nBinary image read (npixels: %i).\n", i-1); // DEBUG
}
I decided to expand the code, so I rewrote it to the previous function and put it in a separate file for functions and also made a header file. The extra file for functions and the header file work 100% so that's not the issue. Now, this code does not work anymore and I get a stack smashing error. Some variables called after this function have also jumped to another value, so I figured the problem was with the buffer (I didn't know about the correct size for the buffer, but it worked...). After some experimentation and testing, I came up with the following function. I replaced the buffer with a char array named image2 to simply try and test it:
void decodeBIN(const char* filename, short image[], int w, int h){
int i = 0, res;
char image2[];
FILE *ptr;
ptr = fopen(filename, "rb"); //"MySnap_20180327-2239-010.bin"
if (!ptr){
printf("\nUnable to open file!\n"); // error
}
res = fread(image2,1,w*h,ptr) // need to read w*h pixels
while (i < w*h){ // DEBUG
printf("%i ", (int)image2[i]); // DEBUG
i++;
}
printf("\nRead %u bytes\n", res); // DEBUG
fclose(ptr);
printf("Binary image read (npixels: %i).\n", i); // DEBUG
}
I'm a bit lost in how it used to work and all of a sudden when I move the code from main() to a function it stops working, so any help is welcome!
Thanks in advance.
Disclaimer: I'm aiming to write this with the help of as few libraries as possible
===== UPDATE:
After the answer of #alainmerigot I got this code, which helped with getting the correct values:
void decodeBIN(const char* filename, unsigned char image[], int w, int h){
int i = 0, res;
FILE *ptr;
res = fread(image,sizeof(char),w*h,ptr) // need to read w*h pixels
fclose(ptr);
}
The segmentation fault and jumped variables are still in place though, so here a more upper-level oversight of what I'm doing:
char filenamePathed["[path of file]/file.bin"];
short img1[npixels]; // npixels = w*h
printf("i_file: %i\n", i_file); // correct value
decodeBIN(filenamePathed, img_curr, w, h); // decode bin
printf("i_file: %i\n", i_file); // value jumped
while (i < npixels){
img1[i] = (short)img_curr[i];
i++;
}
Perhaps it is good to know that I'm doing this iteratively for multiple files (time series)? I also need it to end up in a (short) format (or integer, but eventually needs to be memory-efficient and pixels have a range of 0-255 so int is a bit abundant imo).
The problem with your second function is that you write in array image2 while no space has been reserved for it. Declaring char image2[]; only says that an array exists and that the address of this array can be found in var image2, but no space is associated with it, hence the problem.
You can associate space with this array by several means.
Using permanent storage in the heap
image2 = malloc(x*y); // but do not forget to free(image2) at the end of the function
Using temporary storage in the stack (space is automatically freed when leaving the function).
image2 = alloca(x*y); // slightly faster than malloc and do not require to free() the image
But the best is to use a array with parametrized size (since C99). Your array should be declared as
char image2[w*h]; // will use the value of w and h to define array size
If you want to do other things than printing the image values in your function, you should store the image in permanent memory and have a mean to know the address of the array in your program. This is probably what you intended and is the reason why you have short image[] in your parameter list.
The solution is just simply to use image instead of image2 in fread().
But, the declaration of image should be coherent and image should be an array of char not short.
Beware also of declarations. In your first function, the image is an array of unsigned char and in the second an array of char. While the storage size is identical and fread() will store the same values, they are not equivalent. If used in an arithmetic context, image[i] will be interpreted differently and the results will likely be different. In general, images are unsigned.
Apparently, the problem was with the allocation of image, although I'm not sure why it was wrong.
I used to allocate it with unsigned char image[npixels]; and the solution to the error appeared to be unsigned char image[npixels*7];
Somehow it works, but if anyone has an explanation, please do so :)

Passing pointer/array to main() from a function

I’m learning functions/pointers, and having a bit of an issue. What I need to write is a C program with main() and two other functions.
Requirements:
read_funct() must allocate enough memory using malloc() to store the data.
Function prototype for read_funct must be:
int read_funct(int *data_num, double **data_vals, char *filename)
How it’s meant to work:
main() calls the first function: read_funct()
read_num() reads binary data from a file. Two values have to be extracted: the no. of values (first 4 bytes), then the values themselves (8 bytes each, so contained in the next 8*no. of values). These correspond to data_num and data_vals. They have to be printed, the program then returns to main().
main() performs operations to edit the data from the first file.
main() calls the second function: write_funct(), which writes the edited data into a new file.
Where I am:
The first function reads data_num correctly, and reads/prints data_vals. This is all working properly. However, I’m trying to print these in main() to verify that I’m performing operations on the correct data, but I can’t get it working.
Note: I’m not trying to get it working with write_funct() at the moment, just taking it step-by-step.
Here’s my current code for main():
int read_funct(int *data_num, double **data_vals, char *filename);
int main()
{
int data_num;
double **data_vals;
//Reads file using read_funct()
read_funct(&data_num, data_vals, filename);
//Check: print data_num
printf("\nCheck No. of Values: %d\n", data_num);
//Check: print data_vals
for(int i = 0; i<data_num; i++)
{
printf("%0.3lf\t", data_vals[i]);
}
return(0);
}
Here’s read_funct()
int read_funct (int *data_num, double **data_vals, char *filename)
{
FILE * fp = fopen(filename, "rb"); //Opening file
//There's code here to check valid file open
//There's code here to determine size and check valid length
//Proceed with reading data_num if file is large enough
char buffer_n[4];
fread(buffer_n, 4, 1, fp);
int res = buffer_n[0]|(buffer_n[1] << 8)|(buffer_n[2] << 16)|(buffer_n[3] << 24); //Convert endian
data_num = &res; //Passes results back to data_num
printf("Number of Data Values: %d \n", *data_num); //Printing results
//Proceeds with calculating data_vals
data_vals = malloc(8*res); //Allocating memory
fread(data_vals, 8, res, fp);
//Prints data_vals
for(int i=0; i<res; i++)
{
printf("%0.3f\t", data_vals[i]);
}
printf("\nEnd of File Read.\n\n");
fclose(fp);
free(data_vals); //Free allocated memory
return(0);
}
Desired output:
Basically, I want it to print out the values from inside read_file() and then print a check in main(), so the output will be something like:
No. of values: 3 //From printf in read_file()
2 4 6
Check No. of values: 3 //From printf in main()
2 4 6
Where I think I'm going wrong:
Fairly sure that the main issue is that I've messed up my pointers and how I've initialised things in main(). I've been trying to fix this by myself, but I think I need some more experienced help to figure this out.
I know that every malloc() call must have a subsequent free(), but I'm worried that by doing so the way that I have, maybe I've made it so that I can't retrieve it in main(). Does it instead need to have an intermediate buffer to which memory is allocated instead?
Help to get this code working would be very greatly appreciated. Thank you!
Apart from freeing the data too soon, you have another problem here:
double **data_vals;
read_funct(&data_num, data_vals, filename);
If you want data_vals to be filled (written to, modified) by a function, you must pass its address, exactly as you do with data_num.
Here is another, slightly different, explanation. You see, you declare data_vals but you don't assign a value to it - it contains garbage. So it is a non-sense to pass data_vals to any function, or use it in any expression. It has a sense instead, to assign something to it, either via direct assignment or passing its address to a function, for the function to fill the variable.
Then, your usage of data_vals depicts a vector, or an array. So you really need to declare an array with [], or may be a pointer (pointers and arrays are quite related/interchangeable in C). The logic of your main() function requires a pointer, not a pointer to pointer. Hence, this is appropriate:
double *data_vals;
The function which writes to your pointer variable, instead, needs the address of the variable to write to; in other words: a pointer to a pointer. This is why your function has this (correct) signature:
read_funct(..., double **data_vals, ...)
To understand easily, let see the other (simpler) thing you wrote correctly:
int data_num;
read_funct(&data_num, ...); // declaration: read_funct(int *data_num, ...)
You declare data_num as integer in main(); you declare read_funct() with a formal parameter of pointer to integer, then you call read_funct() passing the address of your variable data_num. Perfect. Now, do the same with the other variable, data_vals. You declare it as pointer to double, pass its address to read_funct() using the notation &data_vals, and your function read_funct() declares that parameter as a pointer to pointer to double (and writes to it using *data_vals = .... You can see the parallelism between the two variables, right?
May be I've been too pedantic, but your question was really clear and well formed, so I tried to do the same.
Yes, you are free-ing the buffer too soon. After you have freed it, there is not guarantee as to what it contains. You can free it at the end, in main.

Why will this not print?

Before you feel the need to mark this as a duplicate post, please don't. I have read all the threads on pointers, arrays, and functions I could find but almost all of them are far too advanced to be of any help to me.
I'm not getting an error, however my code will not print my array. It seems the issue here is using scanf. I don't think the values entered are actually being put into the array in main(). I've tried using pointers, but then I get the error "Thread 1: EXC_BAD_ACCESS (code=1, address=0x0)" whenever I try to use scanf to collect user inputted values to put into the array.
What I am working on is limited to declaring my array in the main() function, but all the operations are to be performed in promptData() function. Any help would be great, I'm at my wits end trying to figure this out on my own.
#import <stdio.h>
void promptData(double data[], int numElem);
int main(int argc, const char * argv[])
{
int size, i;
double array[size];
promptData(array, size);
for (i = 0; i < size; i++)
printf("%.2lf\n", array[i]);
return 0;
}
void promptData(double data[], int numElem)
{
int i;
printf("Enter integer values for size of array.\n");
scanf("%i", &numElem);
for (i = 0; i < numElem; i++)
{
printf("Enter array values.\n");
scanf("%lf", &data[i]);
}
}
Your program has undefined behaviour because variable size was not initialized and has indeterminate value.
You should at first in main ask the user to enter the size of the array then define the array itself and only after that fill it with values.
For example
int main(int argc, const char * argv[])
{
int size = 0;
printf( "Enter a positive integer value for the size of the array: ");
scanf( "%i", &size);
if ( size == 0 ) exit( 1 );
double array[size];
promptData(array, size);
//...
Also in C there is no such a directive as
#import <stdio.h>
Use instead
#include <stdio.h>
At least in ANSI C 89 and C 90, you can't give a variable as the size of an array. The size of array should be known at compile time. You should be doing something like double array[size];.
Even in C99, where you can have variable sized arrays; the variables should contain proper index values at the time you declare the array. In that case, you should read the number from stdin and then declare the array.
Also in C, all parameters are passed by value. This means every function takes a copy of the parameters in the function. If you want to modify a variable's value, you should pass a pointer to it, and then modify the pointer's dereferenced value, something like:
void change(int *x)
{
*x = 7;
}
void first(void)
{
int x = 5;
change(&x);
printf("%d\n", x);
}
Adding on to the other, correct, answer by Zenith, if you want a dynamically allocated array (like you want to be able to change its size based on user input), then your only option is to use one of the memory allocation functions like malloc().
Once you actually have the size in your main function, declare your array like this:
int *myArray = malloc(sizeof(int) * size));//note that malloc will return a NULL if it fails
//you should always check
if(myArray != null) {
//do stuff with myArray like you were. You can just use myArray[] as long as you
//make SURE that you don't go beyond 'size'
}
free(myArray);
//VERY important that every malloc() has a free() with it
Note: untested, but the idea is there.
Further, to answer your other question.
If you find yourself in a situation where you need to call a function and use things INSIDE that function to change stuff where you called it, you have only two choices in C.
You can either return the value and assign it to a variable in the calling function like this:
int result = myFunction(someVariable, anotherVariable);
//do stuff with result
Or, use pointers.
I'm not explaining pointers here, that's usually several lectures worth of information, and is one of the more difficult concepts to grasp for introductory programmers. All I can tell you is you need to learn them, but this format is not the right way to go about doing that.
You're passing size to promptData as a copy.
Thus changes to numElem inside promptData will not affect the size variable in your main. Hence size remains uninitialized, i.e. has an undefined value and therefore should not be used as a size for an array.
If you need to initialize an array with a size that's only known at run-time, you need to allocate memory for the array dynamically using malloc, for example:
double* array = malloc(size * sizeof(double));

C: create String existing out of ints and chars

Since I'm very new to C programming, I have a probably very simple problem.
I got a struct looking like this
typedef struct Vector{
int a;
int b;
int c;
}Vector;
Now I want to write an array of Vectors in a file. To achieve that, I thought to create following method scheme
String createVectorString(Vector vec){
// (1)
}
String createVectorArrayString(Vector arr[]){
int i;
String arrayString;
for(i=0; i<sizeof(arr); i++){
//append createVectorString(arr[i]) to arrayString (2)
}
}
void writeInFile(Vector arr[]){
FILE *file;
file = fopen("sorted_vectors.txt", "a+");
fprintf(file, "%s", createVectorArrayString(arr);
fclose(file);
}
int main(void){
// create here my array of Vectors (this has already been made and is not part of the question)
// then call writeInFile
return 0;
}
My main problems are at (1), which involves also (2) (since I have no clue how to work with Strings in C, eclipse is saying "Type "String" unknown", although I included <string.h>)
So I read at some point that transforming an int to a String is possible with the method itoa().
As I understood it, I can simply do following
char buf[33];
int a = 5;
itoa(a, buf, 10)
However, I cannot bring that to work, let alone that I can't figure out how to "paste" chars or ints into a String.
In my point (1), I would like to create a String of the Form (a,b,c), where as a, b and c are the "fields" of my struct Vector.
In point (2), I would like to create a single String of the Form (a1,b1,c1)\n(a2,b2,c2)\n...(an,bn,cn), whereby n is the amount of Vectors in the array.
Is there a quick solution? Do I confuse the concept of Strings from Java with them of C?
Yes, you do confuse the concept of strings in Java and C.
The C strings are rather inconvenient to work with. They require dynamic memory allocation, and what is worse, corresponding deallocation (which is possible but tedious). In your case, it might be best to remove strings completely, and implement whatever you need without strings.
To write a vector directly to file:
Vector vec;
FILE* file = ...;
fprintf(file, "%d %d %\n", vec.a, vec.b, vec.c);
To write an array of vectors, just do the above in a loop.
A string, in C, is just a null-terminated array of characters. It is generally declared as a char *, though if you have a fixed maximum length, and can allocate it on the stack or inline in a structure, it might be declared as char str[LENGTH].
One of the easiest ways to build a string out of a mix of characters and numbers is to use snprintf(). This is like printf(), but instead of printing to standard output, will print into a string (an array of char). Note that you need to allocate and pass in the buffer yourself; so you will either need to know the maximum length beforehand, or find out by trying to call snprintf(), finding out how many characters it would print, allocating an array of that size, and calling snprintf() again to actually print the result.
So if you have a vector of three integers, and want to build a string out of it, you could write:
char *createVectorString(Vector vec){
int count = snprintf(NULL, 0, "(%d,%d,%d)", vec.a, vec.b, vec.c);
if (count < 0)
return NULL;
char *result = malloc(count * sizeof(char));
if (result == NULL)
return NULL;
count = snprintf(result, count, "(%d,%d,%d)", vec.a, vec.b, vec.c);
if (count < 0)
return NULL;
return result;
}
Note that because you called malloc() to allocate this buffer, you will need to call free() once you are done with it, to avoid a memory leak.
Note that snprintf() only returns the length that you need as of C99. Some compilers (like MSVC), don't support C99 yet, so they return -1 instead of the length that the string would be. In those cases, there may be another function that you can call to determine the size of buffer you need (in MSVC, it's _vscprintf), or you may need to just guess at a size, and if that doesn't work, allocate a buffer twice that size and try again, until it succeeds.
In short: yes, you are confusing Java Strings with C, where you do not have standard string type. What is a string is in reality a sequence of chars terminated with a char with value 0 (or '\0', if you want to be purist).
The quickest solution is to not generate strings (and manually allocate all the memory), but rather to use fprintf with FILE*. Instead of functions to create strings, write functions to write various things into supplied FILE*, for example int writeVector(FILE* output, Vector v). It will be easier for the beginning. I don't think all the gory details of manual memory management required for constructing such strings are good start.
(Note the return type of int in proposed prototype; this is for error codes.)
Additionally, as one of the commenters noted, you misunderstand sizeof. sizeof(arr) would return size of all the elements of the array combined, in bytes (well, technically in chars, but it's a distinction you don't need to worry about right now). To get number of elements in an array, you'd need to use sizeof(arr)/sizeof(arr[0]). But I'm not sure it would work with your function argument, which is technically a pointer, despite the fancy syntax. Applying sizeof to pointer will return size of the pointer itself, not the data it points to.
Which is why in C you would usually provide size of an array in an extra function argument, like:
String createVectorArrayString(Vector arr[], size_t n)
or more in line with what I wrote above:
int writeVectorArray(FILE *output, Vector arr[], size_t n)
{
int retcode = 0;
size_t i;
for (i = 0; i < n; ++i) {
if ( (retcode = writeVector(output, arr[i])) != 0)
return retcode;
}
}
Yes, you are confusing Java Strings with C.
you can't pass arrays in C, only pointers to the first element.
sizeof (arr) where arr is a function argument is the size of the pointer.
You can't return a block scope String, only a pointer to a string. But pointers to local automatic variables go out of scope when the function returns.
I'd write a loop more along
#define N 42
/* Typedef for Vector assumed somewhere.*/
Vector arr[N];
/* Fill arr[]. */
for (i = 0; i < N; ++i) {
fprintf (file, "arr[%d] = { a=%d, b=%d, c=%d }\n", i, arr[i].a, arr[i].b, arr[i].c);
}

Resources