Convert string to doubles in C - c

I'm about to implement a dynamic matrix structure (that stores double values) and I got some problems with reading from a file.
The idea is, that the program doesn't know the number of rows and columns in advance. It has to scan the first line in order to find the number of columns.
The problem with simply using fscanf() to scan doubles is, that (as far as I know) it can't differentiate between the newline and space characters, so it would read the whole file as one line.
To fix this I first fscanf() the line character-by-character with a function. It stores the values in a string, that represents exactly one line.
Then I use sscanf() to scan the string for double values and store them in a double array. After the conversion I free the string. This is done in the chararray_to_doublearray function.
Now after a bit of testing I suspect that the chararray_to_doublearray function is not working as intended.
/* Converts a character array to a double array and returns a pointer to it. Frees the space of the character array, as it's no longer needed. */
double *chararray_to_doublearray(char **chararray)
{
int i;
int elements = 0;
double *numbers=NULL;
double newnumber;
while (sscanf(*chararray, "%lf ", &newnumber) == 1) {
double* newarray = (double*) malloc(sizeof(double) * (elements+1));
for (i = 0; i < elements; ++i)
newarray[i] = numbers[i];
free(numbers);
numbers = newarray;
numbers[elements] = newnumber;
++elements;
}
free(*chararray);
return numbers;
}
And the main() function calling only the chararray_to_doublearray function:
main ()
{
int i;
double *numbers;
char string[50]="12.3 1.2 3.4 4 0.3";
numbers=chararray_to_doublearray(&string);
free(numbers)
return 0;
}
So to summarize: I couldn't find any good implementation of reading double values from the user (or from a file) until the end of line. This is my implementation.
Do you have any ideas, what might be wrong with this?
Regards,
naroslife

This is an XY problem. Do you really need to "fscanf() the line character-by-character"? Has this caused you to ask too much of your question in the wrong direction?
Consider this: %lf denotes a conversion of characters to the double that you choose... It stops immediately when there are no more suitable characters to convert... and a newline is not a suitable character to convert... Is there a light bulb shining in your head, yet?
In your case, the space that follows %lf in the format string causes the useful information (whether the white-space is a newline or not) to be discarded. STOP! You've gone too far, and the consequence is that you now need an intermediate character array conversion function, which is unnecessary bloat.
With this new-found realisation that removing the white-space from the format string will cause a post-fixed newline to be left onto the stream, consider using fgetc to handle the distinction between regular white-space and newlines.
e.g.
double f;
int x = scanf("%lf", &f);
int c;
do {
c = getchar();
} while (isspace(c) && c != '\n');
if (c != '\n') {
ungetc(c, stdin);
}
See above, how I was able to distinguish between newline and non-newline white-space?

There is nothing difficult about reading an unknown number of double values from a file or stdin and storing them in a simulated 2D array. (pointer-to-pointer-to-type) Since you have to assume the number of columns may also differ per-row, you need a similar way to allocate column storage, keep track of the number of values allocated/read, and a way to reallocate the column storage if/when the maximum number of columns are reached. This allows handling a jagged array as easily as an array with a fixed size of columns.
There is one subtle trick that greatly helps in managing jagged arrays. Since you do not know before hand how many column values may be present -- once read, you need a way to store the number of column elements present (for each row in the array). A simple and robust method is simply to store the number of column elements per-row as the first column value. Then after the data is collected, you have the information as part of the array that provides a key to iterating over all rows and columns in the array.
Included as part of this approach, I have created specialty functions xstrtod, xcalloc, xrealloc_sp (realloc of single-pointer array) and realloc_dp (realloc for double-pointer). These are nothing more than the standard functions with appropriate error-checking moved to the function so the myriad of validation checks don't cloud the main body of the code.
A quick implementation that reads values from stdin could be coded as follows:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
#include <math.h> /* for HUGE_VALF, HUGE_VALL */
#define ROWS 32
#define COLS 32
#define MAXC 256
double xstrtod (char *str, char **ep);
void *xcalloc (size_t n, size_t s);
void *xrealloc_sp (void *p, size_t sz, size_t *n);
void *xrealloc_dp (void **p, size_t *n);
int main (void) {
char line[MAXC] = {0}; /* line buffer for fgets */
char *p, *ep; /* pointers for strtod */
double **array = NULL; /* array of values */
size_t row = 0, col = 0, nrows = 0; /* indexes, number of rows */
size_t rmax = ROWS, cmax = COLS; /* row/col allocation size */
/* allocate ROWS number of pointers to array of double */
array = xcalloc (ROWS, sizeof *array);
/* read each line in file */
while (fgets(line, MAXC, stdin))
{
p = ep = line; /* initize pointer/end pointer */
col = 1; /* start col at 1, store ncols in 0 */
cmax = COLS; /* reset cmax for each row */
/* allocate COLS number of double for each row */
array[row] = xcalloc (COLS, sizeof **array);
/* convert each string of digits to number */
while (errno == 0)
{
array[row][col++] = xstrtod (p, &ep);
if (col == cmax) /* if cmax reached, realloc array[row] */
array[row] = xrealloc_sp (array[row], sizeof *array[row], &cmax);
/* skip delimiters/move pointer to next digit */
while (*ep && *ep != '-' && (*ep < '0' || *ep > '9')) ep++;
if (*ep)
p = ep;
else /* break if end of string */
break;
}
array[row++][0] = col; /* store ncols in array[row][0] */
/* realloc rows if needed */
if (row == rmax) array = xrealloc_dp ((void **)array, &rmax);
}
nrows = row; /* set nrows to final number of rows */
printf ("\n the simulated 2D array elements are:\n\n");
for (row = 0; row < nrows; row++) {
for (col = 1; col < (size_t)array[row][0]; col++)
printf (" %8.2lf", array[row][col]);
putchar ('\n');
}
putchar ('\n');
/* free all allocated memory */
for (row = 0; row < nrows; row++)
free (array[row]);
free (array);
return 0;
}
/** string to double with error checking.
* #include <math.h> for HUGE_VALF, HUGE_VALL
*/
double xstrtod (char *str, char **ep)
{
errno = 0;
double val = strtod (str, ep);
/* Check for various possible errors */
if ((errno == ERANGE && (val == HUGE_VAL || val == HUGE_VALL)) ||
(errno != 0 && val == 0)) {
perror ("strtod");
exit (EXIT_FAILURE);
}
if (*ep == str) {
fprintf (stderr, "No digits were found\n");
exit (EXIT_FAILURE);
}
return val;
}
/** xcalloc allocates memory using calloc and validates the return.
* xcalloc allocates memory and reports an error if the value is
* null, returning a memory address only if the value is nonzero
* freeing the caller of validating within the body of code.
*/
void *xcalloc (size_t n, size_t s)
{
register void *memptr = calloc (n, s);
if (memptr == 0)
{
fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__);
exit (EXIT_FAILURE);
}
return memptr;
}
/** reallocate array of type size 'sz', to 2 * 'n'.
* accepts any pointer p, with current allocation 'n',
* with the type size 'sz' and reallocates memory to
* 2 * 'n', updating the value of 'n' and returning a
* pointer to the newly allocated block of memory on
* success, exits otherwise. all new memory is
* initialized to '0' with memset.
*/
void *xrealloc_sp (void *p, size_t sz, size_t *n)
{
void *tmp = realloc (p, 2 * *n * sz);
#ifdef DEBUG
printf ("\n reallocating '%zu' to '%zu', size '%zu'\n", *n, *n * 2, sz);
#endif
if (!tmp) {
fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__);
exit (EXIT_FAILURE);
}
p = tmp;
memset (p + *n * sz, 0, *n * sz); /* zero new memory */
*n *= 2;
return p;
}
/** reallocate memory for array of pointers to 2 * 'n'.
* accepts any pointer 'p', with current allocation of,
* 'n' pointers and reallocates to 2 * 'n' pointers
* intializing the new pointers to NULL and returning
* a pointer to the newly allocated block of memory on
* success, exits otherwise.
*/
void *xrealloc_dp (void **p, size_t *n)
{
void *tmp = realloc (p, 2 * *n * sizeof tmp);
#ifdef DEBUG
printf ("\n reallocating %zu to %zu\n", *n, *n * 2);
#endif
if (!tmp) {
fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__);
exit (EXIT_FAILURE);
}
p = tmp;
memset (p + *n, 0, *n * sizeof tmp); /* set new pointers NULL */
*n *= 2;
return p;
}
Compile
gcc -Wall -Wextra -Ofast -o bin/fgets_strtod_dyn fgets_strtod_dyn.c
Input
$ cat dat/float_4col.txt
2078.62 5.69982 -0.17815 -0.04732
5234.95 8.40361 0.04028 0.10852
2143.66 5.35245 0.10747 -0.11584
7216.99 2.93732 -0.18327 -0.20545
1687.24 3.37211 0.14195 -0.14865
2065.23 34.0188 0.1828 0.21199
2664.57 2.91035 0.19513 0.35112
7815.15 9.48227 -0.11522 0.19523
5166.16 5.12382 -0.29997 -0.40592
6777.11 5.53529 -0.37287 -0.43299
4596.48 1.51918 -0.33986 0.09597
6720.56 15.4161 -0.00158 -0.0433
2652.65 5.51849 0.41896 -0.61039
Output
$ ./bin/fgets_strtod_dyn <dat/float_4col.txt
the simulated 2D array elements are:
2078.62 5.70 -0.18 -0.05
5234.95 8.40 0.04 0.11
2143.66 5.35 0.11 -0.12
7216.99 2.94 -0.18 -0.21
1687.24 3.37 0.14 -0.15
2065.23 34.02 0.18 0.21
2664.57 2.91 0.20 0.35
7815.15 9.48 -0.12 0.20
5166.16 5.12 -0.30 -0.41
6777.11 5.54 -0.37 -0.43
4596.48 1.52 -0.34 0.10
6720.56 15.42 -0.00 -0.04
2652.65 5.52 0.42 -0.61
Memory Check
In any code your write that dynamically allocates memory, it is imperative that you use a memory error checking program to insure you haven't written beyond/outside your allocated block of memory and to confirm that you have freed all the memory you have allocated. For Linux valgrind is the normal choice. There are so many subtle ways to misuse a block of memory that can cause real problems, there is no excuse not to do it. There are similar memory checkers for every platform. They are all simple to use. Just run your program through it.
$ valgrind ./bin/fgets_strtod_dyn <dat/float_4col.txt
==28022== Memcheck, a memory error detector
==28022== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==28022== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==28022== Command: ./bin/fgets_strtod_dyn
==28022==
the simulated 2D array elements are:
2078.62 5.70 -0.18 -0.05
5234.95 8.40 0.04 0.11
2143.66 5.35 0.11 -0.12
7216.99 2.94 -0.18 -0.21
1687.24 3.37 0.14 -0.15
2065.23 34.02 0.18 0.21
2664.57 2.91 0.20 0.35
7815.15 9.48 -0.12 0.20
5166.16 5.12 -0.30 -0.41
6777.11 5.54 -0.37 -0.43
4596.48 1.52 -0.34 0.10
6720.56 15.42 -0.00 -0.04
2652.65 5.52 0.42 -0.61
==28022==
==28022== HEAP SUMMARY:
==28022== in use at exit: 0 bytes in 0 blocks
==28022== total heap usage: 14 allocs, 14 frees, 3,584 bytes allocated
==28022==
==28022== All heap blocks were freed -- no leaks are possible
==28022==
==28022== For counts of detected and suppressed errors, rerun with: -v
==28022== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
There is nothing difficult about reading an unknown number of rows and unknown number of columns from a file in C, but you must pay particular attention to how you do it. While you can limit the array to a square (NxN) array, there is no reason every row can't have a different number of columns (a jagged-array).
Your basic approach is to allocate memory for an array or pointers to type double for some reasonable anticipated number of rows. ( #define ROWS 32 ) You will then read each line. For every line you read you then allocate a block of memory for an array of 'double' for some reasonably anticipated number of doubles. ( #define COLS 32 )
You then convert each string of digits encountered to an double value and store the number at array[row][col]. (we actually start storing values at col = 1 and save col = 0 to hold the final number of cols for that row) You keep track of the number you have added to the array and if your number of columns reaches the number you allocated, you then realloc the array to hold additional doubles.
You continue reading lines until you have read all the lines. If you reach your original limit on the number of rows, you simply realloc the array much like you did with cols.
You now have all your data stored and can do with it what you will. When you are done, do not forget to free all memory you have allocated. Let me know if you have questions.
Quick Brown Fox Separated File
There is one further bit of additional robustness that you can build into the code that will basically allow you to read any row of data no matter how much junk may be included in the file. It doesn't matter if the row-values are comma separated, semi-colon separated, space separated, or separated by the quick brown fox. With a little parsing help, you can prevent read failures by manually advancing to the beginning of the next number. A quick addition in context would be:
while (errno == 0)
{
/* skip any non-digit characters */
while (*p && ((*p != '-' && (*p < '0' || *p > '9')) ||
(*p == '-' && (*(p+1) < '0' || *(p+1) > '9')))) p++;
if (!*p) break;
array[row][col++] = xstrtod (p, &ep);
...
Skipping the non-digits will allow you to read almost any sane file with any type of delimiter without issue. Take for example, the same numbers used originally, but now formatted as follows in the data file:
$ cat dat/float_4colmess.txt
The, 2078.62 quick 5.69982 brown -0.17815 fox; -0.04732 jumps
5234.95 over 8.40361 the 0.04028 lazy 0.10852 dog
and the 2143.66 dish ran 5.35245 away 0.10747 with -0.11584
the spoon, 7216.99 2.93732 -0.18327 -0.20545
1687.24 3.37211 0.14195 -0.14865
2065.23 34.0188 0.1828 0.21199
2664.57 2.91035 0.19513 0.35112
7815.15 9.48227 -0.11522 0.19523
5166.16 5.12382 -0.29997 -0.40592
6777.11 5.53529 -0.37287 -0.43299
4596.48 1.51918 -0.33986 0.09597
6720.56 15.4161 -0.00158 -0.0433
2652.65 5.51849 0.41896 -0.61039
Even with this insane format, the code has no problems properly reading all numeric values into the array properly.

Related

C Program - reading integers from a file and decoding secret message

Hey :) I need some help with my code, which I think is mostly correct but I am having trouble figuring out where I am going wrong.
#include <stdio.h>
#include <stdlib.h>
int num_count(FILE* ptr){
int count = 0;
int numHolder = 0;
while((fscanf(ptr, "%d", &numHolder)) == 1){
count++;
}
return count;
}
void load_nums(FILE* ptr, int *codedPtr, int ncount){
int number = 0;
ncount = ncount - 1;
for(int i = 0; i <= ncount; i++){
fscanf(ptr, "%d", &number);
printf("%d", number);
*(codedPtr + i) = number;
}
return;
}
void decode(int *codedPtr, int ncount, char *decodedPtr){
char temp;
ncount = ncount - 1;
for(int i = 0; i <= ncount; i++){
temp = ((*(codedPtr + i) + *(codedPtr + (ncount - i))) + '0');
*decodedPtr = temp;
decodedPtr++;
}
return;
}
int main(int argc, char *argv[]){
int *codedPtr;
char *decodedPtr;
FILE *fp;
if (argc == 2){
fp = fopen(argv[1], "r+");
}
if(argc <= 1){
printf("Invalid command line: cmd infile outfile\n");
}
int numCount = num_count(fp);
printf("%d", *codedPtr);
codedPtr = (int*)calloc(numCount, sizeof(int));
decodedPtr = (char*)calloc(numCount, sizeof(char));
load_nums(fp, codedPtr, numCount);
decode(codedPtr, numCount, decodedPtr);
printf("\n%s\n\n", decodedPtr);
fclose(fp);
return(0);
}
I added some print functions to trouble shoot, and during the load_nums function the printf functions continuously prints 0's, it is not reading in the correct integer values from the file pointed to.
Could any of you help particularly with the load_nums function? Thank you all and let me know if you need any extra information. "-6 -76 53 -34 32 79 142 55 177 78" is what is in the file pointed to.
You are making things much more complicated than they need to be. You are dynamically allocating storage for both codedPtr and decodedPtr, there is no need to make two passes through the file (one to count integers, and one to read after allocation). Your decode is much more complex than necessary and there is a logic error. Adding '0' (it's not necessary in this case -- though normally it is to convert a decimal digit to its ASCII character value)
To address load_nums, change the return type to int * and allocate for codedPtr within load_nums using realloc as needed to increase the size of your allocated block of memory. Then return a pointer to the allocated block of memory holding your int values. Pass ncount as a pointer (e.g. int *ncount) so you can update the value at that address with the number of integers read so that the count is available back in the calling function (main() here).
Approaching allocation in this manner reduces your file I/O to a single-pass through the file (and file I/O is one of the most time consuming operations) Further, you completely eliminate the need for a num_count() function.
Putting those pieces together, you could do:
/* read integers from fp, dynamically allocating storage as needed,
* return pointer to allocated block holding integers and make ncount
* available through update pointer value.
*/
int *load_nums (FILE* fp, int *ncount)
{
int *codedPtr, avail = 2; /* declare pointer & no. to track allocated ints */
*ncount = 0; /* zero the value at ncount */
/* allocate avail no. of int to codedPtr - validate EVERY allocation */
if (!(codedPtr = malloc (avail * sizeof *codedPtr))) {
perror ("malloc-codedPtr");
return NULL;
}
while (fscanf (fp, "%d", &codedPtr[*ncount]) == 1) { /* read each int */
if (++(*ncount) == avail) { /* check if realloc needed (count == avail) */
/* always realloc to a temporary pointer */
void *tmp = realloc (codedPtr, 2 * avail * sizeof *codedPtr);
if (!tmp) { /* validate that realloc succeeds */
perror ("realloc-codedPtr");
return codedPtr; /* original codedPtr vals available on failure */
}
codedPtr = tmp; /* assign new block of mem to codedPtr */
avail *= 2; /* update avail with no. of int allocated */
}
}
return codedPtr; /* return pointer to allocated block of memory */
}
You would call the function in main() as, codedPtr = load_nums (fp, &numCount). You can wrap it in an if(...) statement to determine whether the allocation and read succeeded or failed:
int *codedPtr = NULL, numCount = 0;
...
if (!(codedPtr = load_nums (fp, &numCount))) /* read file/validate */
return 1;
(there is no need to pass codedPtr from main(). You can further validate by checking numCount > 0 -- that is left to you)
For your decode function, simply set up the for loop use two loop variables to iterate from the beginning and end towards the middle. This greatly simplifies things, e.g.
void decode (int *codedPtr, int ncount, char *decodedPtr)
{
/* loop from ends to middle adding values, + '0' NOT required */
for (int i = 0, j = ncount - i - 1; i < j; i++, j--)
decodedPtr[i] = codedPtr[i] + codedPtr[j];
}
(i starts at the first integer value and j at the last. Don't use *(codePtr + i) instead use codePtr[i] -- though equivalent, index notation is easier to read)
In main() you can alternatively open the file provided as the first argument to your program or read from stdin by default if no argument is provided (this is the way many Linux utilities work). Adding a simple ternary is all you need. Whether you are reading input or allocating memory (or using any function that is necessary for the continued correct operation of your code), you cannot use that function correctly unless you check the return to determine if the operation succeeded or failed. Lesson: validate, validate, validate....
Putting it altogether, you could do:
#include <stdio.h>
#include <stdlib.h>
/* read integers from fp, dynamically allocating storage as needed,
* return pointer to allocated block holding integers and make ncount
* available through update pointer value.
*/
int *load_nums (FILE* fp, int *ncount)
{
int *codedPtr, avail = 2; /* declare pointer & no. to track allocated ints */
*ncount = 0; /* zero the value at ncount */
/* allocate avail no. of int to codedPtr - validate EVERY allocation */
if (!(codedPtr = malloc (avail * sizeof *codedPtr))) {
perror ("malloc-codedPtr");
return NULL;
}
while (fscanf (fp, "%d", &codedPtr[*ncount]) == 1) { /* read each int */
if (++(*ncount) == avail) { /* check if realloc needed (count == avail) */
/* always realloc to a temporary pointer */
void *tmp = realloc (codedPtr, 2 * avail * sizeof *codedPtr);
if (!tmp) { /* validate that realloc succeeds */
perror ("realloc-codedPtr");
return codedPtr; /* original codedPtr vals available on failure */
}
codedPtr = tmp; /* assign new block of mem to codedPtr */
avail *= 2; /* update avail with no. of int allocated */
}
}
return codedPtr; /* return pointer to allocated block of memory */
}
void decode (int *codedPtr, int ncount, char *decodedPtr)
{
/* loop from ends to middle adding values, + '0' NOT required */
for (int i = 0, j = ncount - i - 1; i < j; i++, j--)
decodedPtr[i] = codedPtr[i] + codedPtr[j];
}
int main(int argc, char *argv[]) {
int *codedPtr = NULL, numCount = 0;
char *decodedPtr = NULL;
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
if (!(codedPtr = load_nums (fp, &numCount))) /* read file/validate */
return 1;
if (fp != stdin) /* close file if not stdin */
fclose (fp);
if (!(decodedPtr = malloc (numCount + 1))) { /* allocate/validate */
perror ("malloc-decodedPtr"); /* don't forget room for '\0' */
return 1;
}
decode (codedPtr, numCount, decodedPtr); /* decode the message */
decodedPtr[numCount] = 0; /* nul-terminate */
puts (decodedPtr); /* output decoded message */
free (codedPtr); /* don't forge to free what you allocate */
free (decodedPtr);
}
Example Use/Output
Testing your program, you find the decoded message is "Hello", e.g
$ echo "-6 -76 53 -34 32 79 142 55 177 78" | ./bin/codedptr
Hello
Memory Use/Error Check
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to ensure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ echo "-6 -76 53 -34 32 79 142 55 177 78" | valgrind ./bin/codedptr
==32184== Memcheck, a memory error detector
==32184== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==32184== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==32184== Command: ./bin/codedptr
==32184==
Hello
==32184==
==32184== HEAP SUMMARY:
==32184== in use at exit: 0 bytes in 0 blocks
==32184== total heap usage: 7 allocs, 7 frees, 5,251 bytes allocated
==32184==
==32184== All heap blocks were freed -- no leaks are possible
==32184==
==32184== For counts of detected and suppressed errors, rerun with: -v
==32184== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Look things over and let me know if you have further questions.

How do I read a matrix from a file?

I know this same question has been asked a hundred times before, but they either don't help me or they aren't answered.
I want to read a text file which has some integers in a format like this:
1;50
2;40
3;180
this file can go forever so I can't create an array with a fixed size. So far the summarized part of what I have done (full code isn't like this, I have checked if files aren't null, made file pointers, put them in different functions etc.) :
int **mymatrix;
mymatrix =(int **) malloc(sizeof(int*)*1);
fscanf(file, "%d", &mymatrix[0]);
fscanf(file, ";%d", &mymatrix[1]);
and to print that:
printf("%d", *mymatrix[0]);
printf(" %d", *mymatrix[0]);
I have looked some similar questions and learned the malloc line from them.
I have tried doing fscanf(file, "%d;%d", something) and replaced something with every possible combination of *, **, &, && and also tried [0], [1] but still can't read anything.
I don't need that print part on my code (also tried every possible combinations but no luck). I had placed breakpoints after scanf's but Visual Studio shows mymatrix as < unable to read memory >.
So, there should be a combination of scanf that I haven't tried. If anyone can help me on that part, I greatly appreciate it.
Like this:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
FILE *fp = fopen("matrix.txt", "r");
if(!fp){
perror("fopen");
return 1;
}
int d1, d2, rows = 0;
while(2 == fscanf(fp, "%d;%d", &d1, &d2))
++rows;
int **matrix = malloc(rows * sizeof(*matrix));
rewind(fp);
rows = 0;
while(2 == fscanf(fp, "%d;%d", &d1, &d2)){
matrix[rows] = malloc(2 * sizeof(**matrix));
matrix[rows][0] = d1;
matrix[rows++][1] = d2;
}
fclose(fp);
//print and free'd
for(int r = 0; r < rows; ++r){
printf("%d %d\n", matrix[r][0], matrix[r][1]);
free(matrix[r]);
}
free(matrix);
return 0;
}
realloc version.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
FILE *fp;
int **matrix = NULL;
int d1, d2, r, rows = 0;
fp = fopen("data.txt", "r");
if(!fp){
perror("fopen");
return 1;
}
while(2 == fscanf(fp, "%d;%d", &d1, &d2)){
matrix = realloc(matrix, (rows+1)*sizeof(*matrix));//In the case of large files increase the size that you want to extend. It must have control of the timing.
matrix[rows] = malloc(2 * sizeof(**matrix));
matrix[rows][0] = d1;
matrix[rows][1] = d2;
++rows;
}
fclose(fp);
//print and free'd
for(r = 0; r < rows; ++r){
printf("%d %d\n", matrix[r][0], matrix[r][1]);
free(matrix[r]);
}
free(matrix);
return 0;
}
First, int **mymatrix; is not a matrix/2D array and cannot represent one.
Said that, you should use a pointer to a 1D array/matrix:
// avoid magic numbers!
#define COLS 2
// Points to the matrix. Starts without matrix
int (*mymatrix)[COLS] = NULL;
Despite its type, it can point to a 2D array. As a general rule, a "pointer to an array of N dimensions" can be used to address an "array of N+1 dimensions.
// the amount to grow the array (min. 1, but that is inefficient)
#define GROW_LENGTH 10
// this holds the total number of rows in the array
size_t length = 0;
// row to store next entry
size_t row = 0;
// buffer for input data
int buffer[COLS];
// read data until failure
while ( scanf("%d;%d", &buffer[0], &buffer[1]) == 2 ) {
if ( row >= length ) {
// enlarge the array for another block
int (*p)[COLS] = realloc(mymatrix,
sizeof(*mymatrix) * (length + GROW_LENGTH));
if ( p == NULL ) {
// realloc failed
// release the matrix and terminate (can be changed to more inteligent behaviour)
free(mymatrix);
exit(1);
}
// update variables
mymatrix = p;
length += GROW_LENGTH;
}
// store the data into the matrix
mymatrix[row][0] = buffer[0];
mymatrix[row][1] = buffer[1];
// next position in buffer
row++;
}
if ( mymatrix == NULL ) {
// nothing has been read
}
// process the data.
// `row` contains the number of rows with data
Don't forget to release the array when done:
free(mymatrix);
The code above is a fragment. It requires some standard headers and a function, of course. Best is to wrap the reading part into its own function with a clean interface to the caller. It also reads from stdin; change to fscanf is simple.
Also the printing part is straight-forward, just loop over all rows. and print each column.
Note that this code will allocate at most GROW_LENGTH - 1 unused rows. Set to 1 to have no overhead at all, but that is less efficient, as realloc is called fore every row. The best balance depends on the application, OS, etc.
First, your arguments to fscanf don't match the format string. mymatrix[0] is an int *, so &mymatrix[0] is an int **. Compiling with -Wall -Wextra will warn you of this.
Also, you allocate space for a 1 element array of int *, but then you don't populate that pointer.
You need to allocate an array of 2 int to assign to the first element of mymatrix, then pass the address of each of those to fscanf:
int **mymatrix;
mymatrix = malloc(sizeof(int*)*1); // don't cast the return value of malloc
mymatrix[0] = malloc(sizeof(int)*2); // same here
fscanf(file, "%d", &mymatrix[0][0]);
fscanf(file, ";%d", &mymatrix[0][1]);
Then you print them like this:
printf("%d", mymatrix[0][0]);
printf(" %d", mymatrix[0][1]);
When reading each subsequent line, you'll need to realloc instead of malloc and keep track of how many lines you have and which line you're on.
In addition to all of the other fine answers, why not use a pointer to array of int 2 (or whatever the size of your elements are)? In your circumstance, this is an optimal approach. There is no need to use a pointer to pointer to int. That complicates allocation and freeing of the memory. A pointer to array gives you single allocation of blocks, single freeing of all allocated memory and the 2D indexing you desire.
If you are reading from your file and storing a collection of integer pairs, you need only use a pointer to array, e.g.
int (*arr)[2] = NULL;
That makes allocation with either malloc or calloc a single call to allocate storage an initial number of pairs, and makes freeing the memory a single call. For example, if you have a variable maxn of 64, then to allocate a block of memory to hold the first 64 pairs of integers read from the file, you need only:
arr = calloc (maxn, sizeof *arr);
There is no need for a separate call to allocate storage for every 2-integers, when your reach your initial limit of 64, you simply realloc your array and keep going. The following uses a constant MAXN to realloc for an additional 64 pairs each time the current index idx reaches the limit maxn (the new block of memory is also zeroed):
if (++idx == maxn) {
printf ("\n reallocating %zu to %zu\n", maxn, maxn + MAXN);
size_t szelem = sizeof *arr;
void *tmp = realloc (arr, (maxn + MAXN) * szelem);
if (!tmp) {
fprintf (stderr, "realloc() error: virtual memory exhausted.\n");
exit (EXIT_FAILURE);
}
arr = tmp;
memset (arr + maxn * szelem, 0, MAXN * szelem);
maxn += MAXN;
}
Putting all the pieces together and using a few simply error checking functions for convenience, you could do something similar to the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* constants for number of columns, buffer chars, and initial allocation */
enum { NCOL = 2, MAXC = 32, MAXN = 64 };
void *xcalloc (size_t nmemb, size_t sz);
void *xrealloc (void *ptr, size_t psz, size_t *nelem);
FILE *xfopen (const char *fn, const char *mode);
int main (int argc, char **argv) {
char buf[MAXC] = {0};
char *fmt = "%d;%d";
int (*arr)[NCOL] = NULL;
size_t i, idx = 0, maxn = MAXN;
FILE *fp = argc > 1 ? xfopen (argv[1], "r") : stdin;
/* alloc mem for array of MAXN elements */
arr = xcalloc (maxn, sizeof *arr);
while (fgets (buf, MAXC, fp)) { /* read each line of input */
int a, b; /* parse line for values */
if (sscanf (buf, fmt, &a, &b) != NCOL) continue;
arr[idx][0] = a, arr[idx][1] = b;
if (++idx == maxn) /* realloc as needed */
arr = xrealloc (arr, sizeof *arr, &maxn);
}
if (fp != stdin) fclose (fp); /* close if not stdin */
for (i = 0; i < idx; i++)
printf (" array[%3zu][0] : %4d [1] : %d\n",
i, arr[i][0], arr[i][1]);
free (arr); /* free allocated memory */
return 0;
}
/** xcalloc allocates memory using calloc and validates the return. */
void *xcalloc (size_t nmemb, size_t sz)
{ register void *memptr = calloc (nmemb, sz);
if (!memptr) {
fprintf (stderr, "xcalloc() error: virtual memory exhausted.\n");
exit (EXIT_FAILURE);
}
return memptr;
}
/** realloc 'ptr' to array of elements of 'psz' to 'nelem + MAXN' elements */
void *xrealloc (void *ptr, size_t psz, size_t *nelem)
{ void *tmp = realloc ((char *)ptr, (*nelem + MAXN) * psz);
if (!tmp) {
fprintf (stderr, "realloc() error: virtual memory exhausted.\n");
exit (EXIT_FAILURE);
}
memset (tmp + *nelem * psz, 0, MAXN * psz); /* zero new memory */
*nelem += MAXN;
return tmp;
}
/** fopen with error checking - short version */
FILE *xfopen (const char *fn, const char *mode)
{ FILE *fp = fopen (fn, mode);
if (!fp) {
fprintf (stderr, "xfopen() error: file open failed '%s'.\n", fn);
// return NULL; /* choose appropriate action */
exit (EXIT_FAILURE);
}
return fp;
}
Example Input
With an initial allocation for 64 pairs, reallocation is forces in order to read the entire file. (you can set the initial size at 1 and realloc on every iteration, but that is highly inefficient -- the initial size for MAXN must be at least 1, and should be set to some reasonably anticipated number of elements given your data)
$ cat dat/2d_data.txt
1;354
2;160
3;205
4;342
...
98;464
99;130
100;424
Example Use/Output
$ ./bin/array_ptr2array_realloc <dat/2d_data.txt
array[ 0][0] : 1 [1] : 354
array[ 1][0] : 2 [1] : 160
array[ 2][0] : 3 [1] : 205
array[ 3][0] : 4 [1] : 342
...
array[ 97][0] : 98 [1] : 464
array[ 98][0] : 99 [1] : 130
array[ 99][0] : 100 [1] : 424
Memory Use/Error Check
In any code your write that dynamically allocates memory, you have 2 responsibilites regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you haven't written beyond/outside your allocated block of memory, attempted to read or base a jump on an unintitialized value and finally to confirm that you have freed all the memory you have allocated. For Linux valgrind is the normal choice.
$ valgrind ./bin/array_ptr2array_realloc <dat/2d_data.txt
==2796== Memcheck, a memory error detector
==2796== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==2796== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==2796== Command: ./bin/array_ptr2array_realloc
==2796==
array[ 0][0] : 1 [1] : 354
array[ 1][0] : 2 [1] : 160
array[ 2][0] : 3 [1] : 205
array[ 3][0] : 4 [1] : 342
...
array[ 97][0] : 98 [1] : 464
array[ 98][0] : 99 [1] : 130
array[ 99][0] : 100 [1] : 424
==2796==
==2796== HEAP SUMMARY:
==2796== in use at exit: 0 bytes in 0 blocks
==2796== total heap usage: 2 allocs, 2 frees, 1,536 bytes allocated
==2796==
==2796== All heap blocks were freed -- no leaks are possible
==2796==
==2796== For counts of detected and suppressed errors, rerun with: -v
==2796== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)
Always confirm All heap blocks were freed -- no leaks are possible and equally important ERROR SUMMARY: 0 errors from 0 contexts.
Look over all the answers and let me know if you have any further questions. Using a pointer to array makes a whole lot of sense in a number of situations such as this. It simplifies allocation and freeing of memory and preserves your 2D indexing as well.
If mymatrix were defined as int mymatrix[3][2], you could read the first line doing:
fscanf(file, "%d;%d", &mymatrix[0][0], &mymatrix[0][1]);
The same code would work with mymatrix defined as int **mymatrix, if it would point to a dynamically initialized array of pointers to arrays of int as follows:
mymatrix=(int**)calloc(lines, sizeof(int*)); // intialize the array of array
for (inti=0; i<lines; i++)
mymatrix[i]=(int*)calloc(cols, sizeof(int)); //intialise each array
The number of lines and cols of the matrix could then be defined at runtinme.
You will have to malloc the memory to mymatrix[0].
mymatrix[0]= (int *) malloc ( sizeof (int) *2);
Also, in mymatrix malloc, 1 actually means the maximum number of rows you will have. So you can at max have 1 row as per that.

Reading 3 strings from a text file

I am having trouble reading 3 strings from one line, moving to the next one, and putting them in my struct correctly.
My text file looks like this:
- John Johnson Math
- Eric Smith Biology
- etc
I need to arrange students by class they have chosen. How should i read first string as name then blank, second as last name, and third by class and do that for every line, then store correctly in my struct? Here is what I have right now:
#include <stdio.h>
#include <stdlib.h>
#define MAX 30
typedef struct students {
char nameFirst[MAX];
char NameLast[MAX];
char choClass[MAX];
struct students *next;
} Students;
int main() {
FILE *in;
Students *first = NULL, *New = NULL, *last = NULL, *old = NULL, *current = NULL;
in = fopen("studenti.txt", "r");
if (in == NULL)
{
printf("Cannot open file!\n");
return 1;
}
while (i = fgetc(in) != (int)(EOF))
{
New = calloc(1, sizeof(Students));
if (first == NULL)
first = New;
else
last->next = New;
j = 0;
while (i != (int)(' '))
{
New->nameFirst[j++] = (char)i;
i = fgetc(in);
}
New->nameFirst[j] = '\0';
}
}
Continuing from the comment, why are you approaching this problem with a linked-list? You can use a linked list, but the overhead and code complexity is more than required. A straight forward solution is a simply dynamic array of type students. The benefits of an array or significant. Direct access to all student, simple sorting with a single call to qsort, simple additions, etc..
Don't get me wrong, if you assignment is to use a linked-list, by all means do, but you should really look at an dynamic array of type student, where you can realloc as needed to add as many students as you may like.
For example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { MAXC = 30, MAXS = 60, MAXLN = 128 };
typedef struct students {
char first[MAXC];
char last[MAXC];
char class[MAXC];
} students;
int main (int argc, char **argv) {
students *array = NULL;
size_t i, idx = 0, maxs = MAXS;
char buf[MAXLN] = "";
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
/* allocate/validate maxs students in array */
if (!(array = malloc (maxs * sizeof *array))) {
fprintf (stderr, "error: virtual memory exhausted.\n");
return 1;
}
while (fgets (buf, MAXLN, fp)) { /* read each line into buf */
/* separate in to struct members */
if (sscanf (buf, "- %s %s %s", array[idx].first,
array[idx].last, array[idx].class) != 3)
continue;
if (++idx == maxs) { /* check against current allocations */
void *tmp = realloc (array, (maxs + MAXS) * sizeof *array);
if (!tmp) { /* valdate realloc array succeeded */
fprintf (stderr, "error: realloc memory exhausted.\n");
break; /* or break and use existing data */
}
array = tmp; /* assign reallocated block to array */
maxs += MAXS; /* update current allocations size */
}
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
printf ("\nstudents:\n\n"); /* output formatted data */
for (i = 0; i < idx; i++) {
char tmp[2 * MAXC + 2] = "";
strcpy (tmp, array[i].last);
strcat (tmp, ", ");
strcat (tmp, array[i].first);
printf (" %-60s %s\n", tmp, array[i].class);
}
putchar ('\n');
free (array); /* free all allocated memory */
return 0;
}
(note: if your data file really doesn't begin each line with '- ', then just remove that from the sscanf format-string)
Example Input
$ cat dat/studentclass.txt
- John Johnson Math
- Eric Smith Biology
- etc.
Example Use/Output
$ ./bin/structstudents <dat/studentclass.txt
students:
Johnson, John Math
Smith, Eric Biology
Memory Error/Check
In any code your write that dynamically allocates memory, you have 2 responsibilites regarding any block of memory allocated: (1) always preserves a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you haven't written beyond/outside your allocated block of memory, attempted to read or base a jump on an unintitialized value and finally to confirm that you have freed all the memory you have allocated.
For Linux valgrind is the normal choice. e.g.
$ valgrind ./bin/structstudents <dat/studentclass.txt
==14062== Memcheck, a memory error detector
==14062== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==14062== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==14062== Command: ./bin/structstudents
==14062==
students:
Johnson, John Math
Smith, Eric Biology
==14062==
==14062== HEAP SUMMARY:
==14062== in use at exit: 0 bytes in 0 blocks
==14062== total heap usage: 1 allocs, 1 frees, 5,400 bytes allocated
==14062==
==14062== All heap blocks were freed -- no leaks are possible
==14062==
==14062== For counts of detected and suppressed errors, rerun with: -v
==14062== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)
Always confirm All heap blocks were freed -- no leaks are possible and equally important ERROR SUMMARY: 0 errors from 0 contexts.
Look it over an let me know if the array approach fits your needs and if you have any questions.
Sorting by class member
In order to sort the array of struct students by the class, the easiest way is to use the qsort function. It is the standard sorting function provided by the C library (include stdio.h). You can sort by any member of the students struct. You can even sort by class, and by name.
The only problem new programmers have with qsort is writing the compare function to pass to qsort in order to have it sort in the desired order. The compare function will receive a pointer to two elements in your array of struct student. The parameters passes are passed as void * (const void * actually). Just like any void pointer, you must cast it to the proper type before you can dereference it. (in this case students *) Therefore, you simply need a function that casts the void pointers to students * and passes the values to strcmp. Example:
int compare (const void *a, const void *b)
{
return strcmp (((students *)a)->class, ((students *)b)->class);
}
The only thing left is calling qsort (after fclose in the code):
qsort (array, idx, sizeof *array, compare);
Your output is then sorted by class.
If you then want to sort further by last name after sorting by class, instead of returning on the strcmp for class, test if the result is not equal to zero, and return that result. If the result of the strcmp on class is zero, then you simply return strcmp (((students *)a)->last, ((students *)b)->last); That simply sorts by class first, but if the class is the same, sorts further by last. For example:
int compare (const void *a, const void *b)
{
int r;
if ((r = strcmp (((students *)a)->class, ((students *)b)->class)))
return r;
return strcmp (((students *)a)->last, ((students *)b)->last);
}
Example Input
$ cat dat/studentclass.txt
- Wade Williams Biology
- John Johnson Math
- Eric Smith Biology
- etc.
Example Use/Output
$ ./bin/structstudents <dat/studentclass.txt
students:
Smith, Eric Biology
Williams, Wade Biology
Johnson, John Math
Take the time to learn qsort.

Reading numbers from file into an array

I'm trying to get the numbers from a File into the Array. I tried different approaches, and i came up with the following code:
int* readFileWithNumbers ()
{
FILE *file = fopen("number_list.txt", "r");
int*integers = malloc(sizeof(int) * 240);;
int i=0;
int num;
while(fscanf(file, "%d", &num) > 0) {
integers[i] = num;
i++;
}
fclose(file);
return integers;
}
My input file is in the format:
106
-18
248
-237
148
142
38
-189
59
-120
-219
-172
237
-257
-154
-267
-34
-292
239
-182
-243
-115
-26
-238
298
Can you please guide me, what I'm doing wrong here ?
Generally, you will want to pass a FILE * pointer, the array, a pointer to the index, and a pointer to the current allocation of memory max to your function. That way your function can read values from the file into the array, keep a count of the current index to compare against the current allocation size so you can realloc if the number of values exceed your current allocation. Finally, by virtual of using a pointer for both your index and your max allocation, the changes to either are immediately available back in your calling function (typically main() for these short examples.
Putting all those pieces together, you could do something similar to:
/* read array of unknown size int 'a' from 'fp' */
int *readarr (FILE *fp, int *a, size_t *idx, size_t *max)
{
int tmp;
if (!a) /* if a not allocated -- allocate/validate */
if (!(a = calloc (1, *max * sizeof *a))) {
fprintf (stderr, "readarr() virtual memory exhausted.\n");
exit (EXIT_FAILURE);
}
while (fscanf (fp, " %d", &tmp) == 1) { /* for each int in file */
if (*idx == *max) { /* check idx and max */
void *ap = realloc (a, 2 * *max * sizeof *a); /* realloc */
if (!ap) { /* validate realloc success */
fprintf (stderr, "realloc() error: memory exhausted.\n");
break; /* if failure, return with exising data */
}
a = ap; /* assign new mem block, zero new mem */
memset (ap + *max * sizeof *a, 0, *max * sizeof *a);
*max *= 2; /* update allocation size */
}
a[(*idx)++] = tmp; /* add int to array, update index */
}
return a; /* return array */
}
(note: the function will accept an allocated array, or NULL and allocate/reallocate as needed. However, the value for your array a cannot be a statically declared array due to the call to realloc that takes place. Further, you must assign the return from the function to your array in main(). If 'a' is NULL to begin with, or if realloc takes place, a new pointer address is returned.)
Zeroing the new memory after realloc is not required, but it can help prevent an inadvertent read from an uninitialized value if you later iterate over the array with an index greater than the last stored value index.
Also note the current reallocation scheme doubles the amount of memory each time it calls realloc. You can choose to add as little or as much as you need.
With that, a short example putting it all together could be:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXI 64
int *readarr ( FILE *fp, int *a, size_t *idx, size_t *max);
int main (int argc, char **argv) {
int *array = NULL; /* pointer to array */
size_t i = 0, n = 0, maxi = MAXI; /* index, initial elements */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* valildate file pointer */
fprintf (stderr, "error: file open failed. '%s'\n",
argc > 1 ? argv[1] : "stdin");
return 1;
}
array = readarr (fp, array, &n, &maxi); /* read values from file */
if (fp != stdin) fclose (fp); /* close file */
for (i = 0; i < n; i++) /* print array */
printf (" array[%3zu] : %d\n", i, array[i]);
free (array); /* free memory */
return 0;
}
/* read array of unknown size int 'a' from 'fp' */
int *readarr (FILE *fp, int *a, size_t *idx, size_t *max)
{
int tmp;
if (!a) /* if a not allocated -- allocate/validate */
if (!(a = calloc (1, *max * sizeof *a))) {
fprintf (stderr, "readarr() virtual memory exhausted.\n");
exit (EXIT_FAILURE);
}
while (fscanf (fp, " %d", &tmp) == 1) { /* for each int in file */
if (*idx == *max) { /* check idx and max */
void *ap = realloc (a, 2 * *max * sizeof *a); /* realloc */
if (!ap) { /* validate realloc success */
fprintf (stderr, "realloc() error: memory exhausted.\n");
break; /* if failure, return with exising data */
}
a = ap; /* assign new mem block, zero new mem */
memset (ap + *max * sizeof *a, 0, *max * sizeof *a);
*max *= 2; /* update allocation size */
}
a[(*idx)++] = tmp; /* add int to array, update index */
}
return a; /* return array */
}
Example Input 100 Int
$ cat dat/100int.txt
27086
29317
32736
...
16892
8270
6444
Example Use/Output
$ ./bin/fscanf_array_dyn dat/100int.txt
array[ 0] : 27086
array[ 1] : 29317
array[ 2] : 32736
array[ 3] : 3356
...
array[ 97] : 16892
array[ 98] : 8270
array[ 99] : 6444
Memory Error Check
In any code your write that dynamically allocates memory, you have 2 responsibilites regarding any block of memory allocated: (1) always preserves a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you haven't written beyond/outside your allocated block of memory, attempted to read or base a jump on an unintitialized value and finally to confirm that you have freed all the memory you have allocated.
For Linux valgrind is the normal choice. There are many subtle ways to misuse a new block of memory. Using a memory error checker allows you to identify any problems and validate proper use of of the memory you allocate rather than finding out a problem exists through a segfault. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/fscanf_array_dyn dat/100int.txt
==7273== Memcheck, a memory error detector
==7273== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==7273== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==7273== Command: ./bin/fscanf_array_dyn dat/100int.txt
==7273==
array[ 0] : 27086
array[ 1] : 29317
array[ 2] : 32736
...
array[ 97] : 16892
array[ 98] : 8270
array[ 99] : 6444
==7273==
==7273== HEAP SUMMARY:
==7273== in use at exit: 0 bytes in 0 blocks
==7273== total heap usage: 3 allocs, 3 frees, 1,336 bytes allocated
==7273==
==7273== All heap blocks were freed -- no leaks are possible
==7273==
==7273== For counts of detected and suppressed errors, rerun with: -v
==7273== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)
Always confirm All heap blocks were freed -- no leaks are possible and equally important ERROR SUMMARY: 0 errors from 0 contexts.
Look it all over and let me know if you have any further questions. Basic allocation and freeing of memory is the basis for much of C. It's better you take the time now to completely understand the code, then end up beating your head against your desk later... Good luck with your coding.

Using realloc on a 2D array c

I'm kinda new to C sorry if my questions is somewhat vague;
I need to use realloc on a 2D array without losing it's previous data, I have this function in my program to do it:
void modifyMatrix(int **iMat, int iRow, int iRow2, int iCol)
{
int i;
iMat = (int**)realloc(iMat, (iRow2)*sizeof(int*));
for(i=iRow; i<iRow2; i++)
{
iMat[i]=NULL;
}
for(i=0; i<iRow2; i++)
{
iMat[i]=(int*)realloc(iMat[i], (iCol)*sizeof(int));
}
}
Where iRow is the original size and iRow 2 & iCol are the new size and are all being captured elsewhere in the program.
Whenever I try to print the matrix I keep getting junk data or memory values on the rows and columns that are added, what am I doing wrong?
Let me know if you need the full code or any other questions to clarify, thanks in advance!
Edit:
Below you can see the code I use to create the Matrix
My bad, I think I should've added that the Matrix is already created elsewhere in the program, with this function I'm just trying to modify the dimensions, thanks for the quick response btw!, below you can find the function with which I'm creating the array
void createMatrix(int ***iMat, int iRow, int iCol)
{
int **iRow2 = (int**)calloc(iRow, sizeof(int*));
int i;
for (i=0; i<iRow; i++)
{
iRow2[i] = (int*)calloc(iCol, sizeof(int));
}
*iMat=iRow2;
}
Also, I can only use the array I've already created to do this, I can't create an temp one (which I know would be the easy way to do it)
In c the variables are passed by value, because of this the iMat inside the modifyMatrix() is not modifying the one in the caller function.
You need to pass the address of iMat instead
void modifyMatrix(int ***iMat, int iRow, int iRow2, int iCol)
{
int i;
int **safe;
safe = realloc(*iMat, iRow2 * sizeof(int *));
if (safe == NULL)
return;
*iMat = safe;
for (i = 0 ; i < iRow ; i++)
{
int *keep_old_pointer;
keep_old_pointer = realloc(safe[i], iCol * sizeof(int));
if (keep_old_pointer == NULL)
do_something_allocation_failed();
safe[i] = keep_old_pointer;
}
for (int i = iRow ; i < iRow2 ; ++i)
safe[i] = malloc(iCol * sizeof(int));
}
Also, don't assign NULL to every element and then try to realloc() because if realloc() makes sense in this situation then you are overwriting the pointers with NULL without freeing them.
And don't overwrite the realloc()ed pointer before checking if the allocation was succesfull, because if it fails you wont be able to free the previous pointer because you would have lost reference to it, causing a memory leak.
When you are passing an array of pointers to a function to realloc, you basically have 2 choices; (1) pass the address of the array to the function (i.e. &array) as the parameter, meaning your function definition will be reallocfoo (int ***array, size_t* size) or (2) assign the return of the function in the calling routine. (e.g. array = reallocfoo (array, &size);)
Since you have already been given answers for (1), let's look at how you would implement and use (2). Note: there is no need to make your function the type of the array, it is just returning a memory address, so making use of a generic void pointer is fine. For example:
void *xrealloc2 (void **memptr, size_t *n)
{
void *tmp = realloc (memptr, *n * 2 * sizeof tmp);
if (!tmp) {
fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__);
return NULL;
}
memptr = tmp;
memset (memptr + *n, 0, *n * sizeof tmp);
*n *= 2;
return memptr;
}
Also note since you are reallocating an array of pointers, there is no need to pass the type size (a pointer is a pointer is a pointer -- in all the cases we care about here). Putting this to work, since you are not passing the address of your array, you will need to assign the return to complete the reallocation. (much as you did in your code above) e.g.:
if (ridx == rmax) /* if realloc is needed */
ia = xrealloc2 ((void **)ia, &rmax);
Note: the current number of pointers (rmax) is passed as a pointer so its value can be updated to twice current in the reallocation function. (so when you run out next time, you can realloc based on the correct updated current number). Putting all the pieces together, you get a short example that just forces reallocation twice. Additionally, the original allocation is placed in a function as well to keep the main body of code tidy and the return checks for the allocation in the function. (you can decide how you handle memory exhaustion -- NULL return or exit, examples of both are shown in the two functions)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define RMAX 2
#define COLS 5
void *xcalloc (size_t n, size_t s);
void *xrealloc2 (void **memptr, size_t *n);
int main (void) {
int **ia = NULL;
size_t rmax = RMAX;
size_t rows = 0;
size_t ridx = 0, cidx = 0;
srand (2275311); /* arbitrary repeatable seed */
ia = xcalloc (RMAX, sizeof *ia);
/* intentionally force reallocation */
while (ridx < 3 * RMAX) {
ia[ridx] = xcalloc (COLS, sizeof **ia);
for (cidx = 0; cidx < COLS; cidx++)
ia[ridx][cidx] = rand () % 1000 + 1;
ridx++;
if (ridx == rmax)
ia = xrealloc2 ((void **)ia, &rmax);
}
rows = ridx;
printf ("\n the reallocated 2D array elements are:\n\n");
for (ridx = 0; ridx < rows; ridx++) {
for (cidx = 0; cidx < COLS; cidx++)
printf (" %4d", ia[ridx][cidx]);
putchar ('\n');
}
putchar ('\n');
for (ridx = 0; ridx < rows; ridx++)
free (ia[ridx]);
free (ia);
return 0;
}
/** xcalloc allocates memory using calloc and validates the return.
* xcalloc allocates memory and reports an error if the value is
* null, returning a memory address only if the value is nonzero
* freeing the caller of validating within the body of code.
*/
void *xcalloc (size_t n, size_t s)
{
register void *memptr = calloc (n, s);
if (memptr == 0)
{
fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__);
exit (EXIT_FAILURE);
}
return memptr;
}
/* realloc array of pointers ('memptr') to twice current
* number of pointer ('*nptrs'). Note: 'nptrs' is a pointer
* to the current number so that its updated value is preserved.
* no pointer size is required as it is known (simply the size
* of a pointer
*/
void *xrealloc2 (void **memptr, size_t *n)
{
void *tmp = realloc (memptr, *n * 2 * sizeof tmp);
#ifdef DEBUG
printf ("\n reallocating %zu to %zu\n", *n, *n * 2);
#endif
if (!tmp) {
fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__);
return NULL;
}
memptr = tmp;
memset (memptr + *n, 0, *n * sizeof tmp);
*n *= 2;
return memptr;
}
After you compile the code and run it, it will confirm that instead of just the maximum 2 rows (pointers) originally allocated, reallocation occurs twice increasing that number to 8 (e.g. 2->4->8) so all 6 rows of integers assigned are properly allocated:
the reallocated 2D array elements are:
155 573 760 410 956
553 271 624 625 934
259 291 811 161 185
756 211 16 6 449
124 869 353 210 317
310 181 897 866 831
If you have any questions, let me know. Don't forget, always run any code that allocates or reallocated through valgrind (or similar memory checker) to insure your memory use is correct and that your free all memory you allocate.
==29608== Memcheck, a memory error detector
==29608== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==29608== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==29608== Command: ./bin/realloc2d
==29608==
the reallocated 2D array elements are:
<snip>
==29608==
==29608== HEAP SUMMARY:
==29608== in use at exit: 0 bytes in 0 blocks
==29608== total heap usage: 9 allocs, 9 frees, 232 bytes allocated
==29608==
==29608== All heap blocks were freed -- no leaks are possible
==29608==
==29608== For counts of detected and suppressed errors, rerun with: -v
==29608== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
You can compile the code above with the -DDEBUG flag to have it print to stdout each time it reallocates and provide the current count of pointers allocated. Good luck.
On success, realloc frees the pointer you pass to it and returns a pointer to the newly allocated memory. You're getting "junk values" because dereferencing a pointer to freed memory is undefined behavior.
It's not pretty, but the way to fix this (as another answer pointed out) is to pass a triple pointer (int***). That way the function can modify the original value of the pointer. This is how you simulate reference semantics in C, which is a strictly "pass by value" language.
void modifyMatrix(int ***iMat, int iRow, int iRow2, int iCol)
{
int i;
int **newMatrix = realloc(*iMat, iRow2 * sizeof(int*));
if (newMatrix == NULL) {
/* handle realloc error here */
}
else {
*iMat = newMatrix; /* assign pointer to the new memory */
}
for(i=iRow; i<iRow2; i++)
{
(*iMat)[i]=NULL;
}
for(i = 0; i < iRow2; i++)
{
int* newRow = realloc((*iMat)[i], (iCol)*sizeof(int));
if (newRow == NULL) {
/* handle realloc error here */
}
else {
(*iMat)[i] = newRow;
}
}
}
You've also got to add some error checking. If realloc fails and returns a NULL pointer, you've just created a memory leak: you no longer have the previous value of the pointer.
Note that I removed all of your casts. It's bad practice to cast the return of malloc and friends in C.

Resources