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

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.

Related

Breadth first search code in C, possible stack overflow

I wrote a code for breadth first search in C using a compressed sparse row data structure. The code seems to work well for one graph but returns an error for another graph file. It works well for this file but throws an error for this file Being new to C programming, I can't find the cause of the problem and will appreciate any help
I tried checking the condition for the while loop. The condition for the loop is true when the code hangs up and returns an error. I am running this code on CodeBlocks 16.01 with the mingw compiler.
#include <stdio.h>
#include <stdlib.h>
// Declaring a struct type to hold
int main(){
int n, m, counter, current, x, src, dst;
n=0, m=0, counter = 0, current =0, src = 0, dst = 0;
FILE *fp; //create a pointer to the file directory
fp = fopen("filename.graph","r"); //set the directory pointer to the path of the text file containing graph data
if ((fp == NULL)){ perror("Error, no such file exists \n"); exit(1);}
//If file not found, print error message and exit the program
else
{
fscanf(fp,"%d %d", &n,&m); //read first line of text file to get number of vertices and edges in graph
struct CSRgraph //Create CSR data structure
{
int heads[m]; //Stores heads of edges
int offsets[n+1]; //Stores information on the number of edges leaving each node
};
struct CSRgraph g; //Create an instance of the CSR graph data structure
g.offsets[0] = 0; //Set the initial offset value to 0
g.offsets[n] = m; //Set the offset value of 'phantom' node to the number of edges in graph
for(x=0;x<m;x++) //iterate over all lines containing edge information in text file
//Read file and create CSR data structure from information in text file
{
fscanf(fp,"%d %d",&src,&dst); //read source and head information from file
g.heads[x] = dst; //assign head information to the next available slot in data structure
if (src < n+1) //Check that node is valid
{
if (src == current) //check that current edge originates from same source as previous edge
{
counter++; //increment counter for the number of edges that originate from current source
}
else //Current edge does not originate from previous source. New source node encountered
{
g.offsets[src] = counter + g.offsets[src -1]; //Update offset value for previous source
counter = 1; //restart edge origin counter
current = src ; //set current to current source
}
}
}
fclose(fp); //Close file after use
int Discovered[n],Queue[n+1],Explored[n], *front_ptr,*end_ptr,*exp_ptr;
front_ptr = Queue; //Initialize the front pointer to the Queue array
end_ptr = Queue; //Initialize the end pointer to the Queue array
exp_ptr = Explored; //Initialize the explored pointer to the Explored array
for (x=0;x<n;x++)
{
Discovered[x] = 0; //An array to track discovered nodes. Not necessarily explored, but nodes that have showed up previously
}
// Advance the pointers in the direction you want
*end_ptr = 0; //setting the first element in the queue as the node 0
end_ptr++; //advancing the end pointer to the next available array spot
Discovered[0] = 1;
while (front_ptr != end_ptr)
{ //Queue is empty if front pointer is the same as end pointer
int p,curr;
curr = *front_ptr; //grab the front of the queue and set it as current node
front_ptr++; //equivalent to removing from element and pushing the next node in line to the front
*exp_ptr = curr; //set current node to explored
exp_ptr++; //advance the explored pointer one step
for (p = g.offsets[curr]; p < g.offsets[curr+1]; p++)
//iterate over all neighbors of current node
{
if (Discovered[g.heads[p]] == 0)
//if node is not already discovered, set it to discovered, add it to queue and advanced the end pointer of queue one step
{
Discovered[g.heads[p]] = 1;
*end_ptr = g.heads[p];
end_ptr++;
}
}
}
}
return 0;
}
Your use of int heads[m]; as a VLA of int with m = 108744 (along with the other 4 VLAs you allocate of 2950 integers) is likely causing a StackOverflow... (this will be compiler, OS and memory-model dependent). To fix the problem, change CSRgraph so that members heads and offsets are pointers and then dynamically allocate storage based on the numbers read from the first line of the file, e.g.
typedef struct { /* typdef for convenience */
int *heads,
*offsets;
} CSRgraph_t;
int main (int argc, char **argv) {
CSRgraph_t g; /* declare instance of struct */
...
/* allocate/validate g.heads & g.offsets */
if (!(g.heads = malloc (m * sizeof *g.heads))) {
perror ("malloc-g.heads");
return 1;
}
/* calloc used to zero g.offsets */
if (!(g.offsets = calloc ((n + 1), sizeof *g.offsets))) {
perror ("malloc-g.offsets");
return 1;
}
g.offsets[0] = 0;
g.offsets[n] = m;
...
(note: calloc is used on offsets to initialize it to all zero as you later compare p < g.offsets[curr+1])
Putting it altogether, you could do:
#include <stdio.h>
#include <stdlib.h>
typedef struct { /* typdef for convenience */
int *heads,
*offsets;
} CSRgraph_t;
int main (int argc, char **argv) {
CSRgraph_t g; /* declare instance of struct */
int n, m, counter, current;
n = m = counter = current = 0;
/* 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 (fscanf (fp, "%d %d", &n, &m) != 2) { /* validate EVERY read */
fputs ("error: invalid format n, m.\n", stderr);
return 1;
}
/* allocate/validate g.heads & g.offsets */
if (!(g.heads = malloc (m * sizeof *g.heads))) {
perror ("malloc-g.heads");
return 1;
}
/* calloc used to zero g.offsets */
if (!(g.offsets = calloc ((n + 1), sizeof *g.offsets))) {
perror ("malloc-g.offsets");
return 1;
}
g.offsets[0] = 0;
g.offsets[n] = m;
for (int x = 0; x < m; x++) {
int src; /* src is only needed within scope of loop */
if (fscanf (fp, "%d %d", &src, &g.heads[x]) != 2) {
fprintf (stderr, "error: invalid format - line %d.\n", x);
}
if (src < n+1) {
if (src == current)
counter++;
}
else {
g.offsets[src] = counter + g.offsets[src -1];
counter = 1; /* restart edge origin counter */
current = src; /* set current to current source */
}
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
int Discovered[n], Queue[n+1], Explored[n],
*front_ptr, *end_ptr, *exp_ptr;
front_ptr = Queue; /* front pointer to the Queue array */
end_ptr = Queue; /* end pointer to the Queue array */
exp_ptr = Explored; /* explored pointer to the Explored array */
for (int x = 0; x < n; x++)
Discovered[x] = 0;
/* Advance the pointers in the direction you want */
*end_ptr = 0;
end_ptr++;
Discovered[0] = 1;
while (front_ptr != end_ptr) {
int curr = *front_ptr;
front_ptr++;
*exp_ptr = curr;
exp_ptr++;
for (int p = g.offsets[curr]; p < g.offsets[curr+1]; p++) {
if (Discovered[g.heads[p]] == 0) {
Discovered[g.heads[p]] = 1;
*end_ptr = g.heads[p];
end_ptr++;
}
}
}
free (g.heads);
free (g.offsets);
return 0;
}
(note: avoid hardcoding filenames, e.g. fopen("filename.graph","r"), main() takes arguments, use them to pass the filename as the first argument to your program [and you can read from stdin by default if no argument is provided])
Memory Use/Error Check
$ valgrind ./bin/readgraphsfile ~/tmp/graphfile/large.graph
==17345== Memcheck, a memory error detector
==17345== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==17345== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==17345== Command: ./bin/readgraphsfile ~/tmp/graphfile/large.graph
==17345==
==17345==
==17345== HEAP SUMMARY:
==17345== in use at exit: 0 bytes in 0 blocks
==17345== total heap usage: 3 allocs, 3 frees, 447,332 bytes allocated
==17345==
==17345== All heap blocks were freed -- no leaks are possible
==17345==
==17345== For counts of detected and suppressed errors, rerun with: -v
==17345== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
It works fine with your large.graph file.

Reassigning elements (pointers in particular) in a struct

I want to take a struct, "trash" it, and reassign the values of its elements. I wrote the following example code, and it seems to work. But I am wondering if anyone sees anything wrong with it. I am mainly worried about the "name" and "ip" pointers. They came out looking right, but did I just get lucky?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct stuff_s{
int n;
char *name;
int dsize;
int *ip;
} stuff;
void output_stuff(stuff *s){
int n;
printf("%d\n", s->n);
printf("%s\n", s->name);
printf("%d\n", s->dsize);
for (n=0; n<s->dsize; n++) {
printf("%d ",s->ip[n]);
}
printf("\n");
}
void reassign(stuff *s) {
stuff snew;
int n;
snew.n = 2;
snew.name = calloc(32, sizeof(char));
strcpy(snew.name, "Snoopy");
snew.dsize = 12;
snew.ip = calloc(snew.dsize, sizeof(int));
for (n=0; n<snew.dsize; n++) { snew.ip[n] = n; }
free(s->name);
free(s->ip);
memcpy(s, &snew, sizeof(stuff));
}
int main() {
stuff d;
int n;
d.n = 1;
d.dsize = 10;
d.ip = calloc(d.dsize, sizeof(int));
for (n=0; n<d.dsize; n++) {
d.ip[n] = n;
}
d.name = calloc(32, sizeof(char));
strcpy(d.name,"Charlie Brown");
output_stuff(&d);
printf("\n");
reassign(&d);
output_stuff(&d);
free(d.ip);
free(d.name);
}
Well, here's what valgrind says:
1
--2097-- REDIR: 0x4ebf9c0 (strlen) redirected to 0x4c2e0e0 (strlen)
Charlie Brown
10
0 1 2 3 4 5 6 7 8 9
--2097-- REDIR: 0x4eb9d10 (free) redirected to 0x4c2bd80 (free)
--2097-- REDIR: 0x4ec8630 (memcpy##GLIBC_2.14) redirected to 0x4a25720 (_vgnU_ifunc_wrapper)
--2097-- REDIR: 0x4ed1620 (__memcpy_sse2_unaligned) redirected to 0x4c2f6b0 (memcpy##GLIBC_2.14)
2
Snoopy
12
0 1 2 3 4 5 6 7 8 9 10 11
==2097==
==2097== HEAP SUMMARY:
==2097== in use at exit: 0 bytes in 0 blocks
==2097== total heap usage: 4 allocs, 4 frees, 152 bytes allocated
==2097==
==2097== All heap blocks were freed -- no leaks are possible
==2097==
==2097== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
==2097== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
So there are no memory errors.
Some stylistic points
You don't need to use sizeof(char) - it's defined to be 1
dsize should be unsigned, and should really be a size_t, which is bigger than an int
As SoronellHaetir points out, you don't need to use another struct - you can modify the passed-in one
did I just get lucky?
Well, you got lucky, but not for the reasons you may be thinking...
Your handling of the stuct allocation and reassignment was correct, but incomplete. You should validate all memory allocations to insure you do not invoke Undefined Behavior by attempting to access memory that does not belong to you in the event of an allocation failure.
For example, when you allocate d.ip -- check the return to insure calloc succeeded, e.g.
if (!(d.ip = calloc (d.dsize, sizeof *d.ip))) {
perror ("calloc d.ip failed");
exit (EXIT_FAILURE);
}
You should do that for every allocation.
Type void for reassign is insufficient. It provides no meaningful way to determine whether the allocations in the function succeeded or not. Any time you are allocating memory, opening a file, taking input, etc.. make sure you declare your function with a type that can provide a meaningful return to indicate success or failure. A pointer returning a valid address or NULL works, as does an integer type returning a value that can indicate success/failure.
Don't use magic numbers in your code. If you need a constant for instance for the size of the name member, then #define one or use an enum. For example if you want the size of name to be 32 bytes, then define a namesize constant, e.g.
#define NMSZ 32
Your reassign function continues with magic numbers and magic strings in making assignments to .n, .dsize, and .dname. (granted, I understand that is was likely for a quick test). Make reassign useful by passing the values of n, name and dsize as function parameters.
You don't need to memcpy (s, &snew, sizeof (stuff));. All you need to do is assign *s = snew;. Now you may be a bit lucky here since you limited the pointer members of your struct to single pointers. Since the value contained is the address of the start of each memory block, an assignment is all that is required. However, if you use a pointer to pointer to type as a member (e.g. a double-pointer) an assignment (or a memcpy) is no longer sufficient, and a deep copy will be required.
note: unless you need name to be modifiable (e.g. you need to change individual characters), then a string literal can be used and eliminate the need to dynamically allocate altogether.
It may also be wise to change your choice of int n; to int i; as the counter to eliminate confusion between n and s.n, etc..
Putting those pieces together, you could make reassign a bit more robust as follows:
stuff *reassign (stuff *s, int n, const char *name, int dsize) {
stuff snew;
int i;
snew.n = n; /* validate all memory allocations */
if (!(snew.name = calloc (NMSZ, sizeof *snew.name))) {
perror ("calloc snew.name");
return NULL;
}
strcpy (snew.name, name);
snew.dsize = dsize; /* ditto */
if (!(snew.ip = calloc (snew.dsize, sizeof *snew.ip))) {
perror ("calloc snew.ip");
return NULL;
}
for (i = 0; i < snew.dsize; i++)
snew.ip[i] = i + 5;
free (s->name);
free (s->ip);
*s = snew; /* you can simply assign snew */
return s;
}
While you are free to assign each member of your struct after declaration, beginning with C99, use of named-initializers make a simple and readable way to initialize non-dynamic members at the time of declaration, e.g.
stuff d = { .n = 1, .dsize = 10 };
Finally, as noted in the comments, there is no need to call printf ("\n"); to output a single character. That is what putchar ('\n'); is for. Granted, a decent compiler will make the optimization for you, but that isn't an excuse for not using the correct tool for the job to begin with.
Putting all the pieces together, you could make your code a bit more robust and protect against Undefined Behavior by adding validations and making use of the meaningful return from reassign as follows:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NMSZ 32
typedef struct stuff_s {
int n,
dsize,
*ip;
char *name;
} stuff;
void output_stuff (stuff *s){
int n;
printf ("%d\n%s\n%d\n", s->n, s->name, s->dsize);
for (n = 0; n < s->dsize; n++)
printf ("%d ",s->ip[n]);
putchar ('\n');
}
stuff *reassign (stuff *s, int n, const char *name, int dsize) {
stuff snew;
int i;
snew.n = n; /* validate all memory allocations */
if (!(snew.name = calloc (NMSZ, sizeof *snew.name))) {
perror ("calloc snew.name");
return NULL;
}
strcpy (snew.name, name);
snew.dsize = dsize; /* ditto */
if (!(snew.ip = calloc (snew.dsize, sizeof *snew.ip))) {
perror ("calloc snew.ip");
return NULL;
}
for (i = 0; i < snew.dsize; i++)
snew.ip[i] = i + 5;
free (s->name);
free (s->ip);
*s = snew; /* you can simply assign snew */
return s;
}
int main() {
stuff d = { .n = 1, .dsize = 10 };
int i;
if (!(d.ip = calloc (d.dsize, sizeof *d.ip))) {
perror ("calloc d.ip failed");
exit (EXIT_FAILURE);
}
for (i = 0; i < d.dsize; i++)
d.ip[i] = i;
if (!(d.name = calloc (NMSZ, sizeof *d.name))) {
perror ("calloc d.name failed");
exit (EXIT_FAILURE);
}
strcpy (d.name, "Charlie Brown");
output_stuff (&d);
putchar ('\n');
if (reassign (&d, 2, "Linus", 12)) {
output_stuff (&d);
free (d.ip);
free (d.name);
}
return 0;
}
Example Use/Output
$ ./bin/structcpy
1
Charlie Brown
10
0 1 2 3 4 5 6 7 8 9
2
Linus
12
5 6 7 8 9 10 11 12 13 14 15 16
Look thins over an let me know if you have any 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 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