C programming to increase the size of a string - c

So I wrote this code but it gives me the same answer everytime. I am increasing the memory allocated to the pointer in steps of 4 and then print the value.
#include <stdio.h>
int main(void) {
int n=0;
char *name = "hello";
scanf("%d",&n);
for(int i =0; i<n;i++){
name += sizeof(int);
printf("%d \n", (sizeof(&name)));
}
return 0;
}
can someone help me? I don't know whats wrong here. I don't need a different code, I just want to understand what's wrong with this.

Try the following, error checking was left out for clarity:
#include <stdio.h>
int main(void)
{
int n=0;
char *name = null;
scanf("%d",&n);
for(int i=0; i<n;i++)
{
char *buffer = null;
//allocate/reallocate the buffer. increases by 4 bytes every iteration
buffer = (char*) realloc(name, (i+1)*4);
name = buffer;
printf("%d \n", (sizeof(&name)));
}
//release the memory used by the buffer
free(name);
return 0;
}

Here are some explanations of what is happening.
#include <stdio.h>
int main(void) {
int n=0;
// this does not actually allocate any memory. It sets the POINTER name to point (like an arrow) to a read-only block that contains "hello"
char *name = "hello";
// string literals generally come in fixed read-only memory
scanf("%d",&n);
for(int i =0; i<n;i++){
// this causes the pointer memory address to be incremented by sizeof(int) (typically 4)
// after the first increment if it will point to a string "o" (incremented by 4 characters)
// after the second increment it will point to some undefined memory behind "hello" in your virtual address space and will have undefined behaviour when accessed
name += sizeof(int);
// sizeof(&name) will give you the size of a char **. Pointer to a character pointer.
// Wich is the same size as all pointers.
// = sizeof(void *) = 8 for 64-bit systems, 4 for 32-bit systems
printf("%d \n", (sizeof(&name)));
}
return 0;
}
This is the way to do it:
#include <stdio.h>
int main(void) {
int n=0;
// allocate 10 bytes of memory and assign that memory address to name
char *name = malloc(10);
// the size of that memory needs to be kept in a separate variable
size_t name_length = 10;
// copy the desired contents into that memory
memcpy(name, "hello", sizeof("hello"));
scanf("%d",&n);
for(int i =0; i<n;i++){
// reallocate the memory into something with sizeof(int) more bytes
void * tmp = realloc(name, name_length += sizeof(int));
// this can fail
if (tmp) {
name = tmp;
} else {
perror("realloc");
exit(-1);
}
printf("%d \n", name_length);
}
return 0;
}

You have not allocated any memory for the pointer at all in the code you provide. You will have to deal with dynamic memory if you want to change the size of the allocated chunk. You will have to initially use malloc and then use realloc to allocate more memory on each step.

Let's step through your code one by one:
char *name = "hello";
this create an array of chars 'h','e','l','l','o',0 and assignes the memory address of the first character to name
for(int i =0; i<n;i++){
name += sizeof(int);
printf("%d \n", (sizeof(&name)));
}
here you add to the name pointer the size of int, which increments this pointer by 4 each pass.
Since this is a char pointer, the pointer is incremented by 4 bytes - since sizeof(int) == 4
You cannot increase the size of your hello char array, since it is not a dynamic array.
If you wish to be able to resize the string, you should malloc and copy the chars to the bigger array.

Related

How do I modify a char** in another function

This is what I expect my string array s to be after the program is run: {"#0", "#1", "2"}.
This is what I am getting: {"#2", "#2", "2"}.
How do I modify this code so that I can get {"#0", "#1", "#2"} in the main after the function is executed?
What am I doing wrong? Please help.
#include <stdio.h>
void func(char **s){
for(int i=0; i<3; i++){
char buf[10];
snprintf(buf, 10, "#%d",i);
s[i]=buf;
}
}
int main()
{
char *s[3];
func(s);
for(int i=0; i<3; i++){
printf("%s", s[i]);
}
return 0;
}
First, you have every element in your array pointing to the same character array.
Second, they are all pointing to a local character array. This leads to undefined behavior.
Local variables in functions get allocated on the stack. When the function call is over, that memory may be overwritten with some other value.
Given two pointers p and q, the statement:
p = q;
doesn't copy the contents of the memory pointed to by q to the contents of the memory pointed to by p. It copies the pointer values, such that both p and q now point to the same memory, and any change to the memory via p is reflected when q is used.
That being said, the statement:
char buf[10];
declares buf to be an array of 10 chars. It has a lifetime corresponding to the execution of its block of definition. Once the function returns, it's destroyed and s is now indeterminate. Indeterminate pointers lead to undefined behaviour.
Possible Solutions:
standard strcpy
POSIX's strdup (which will be included in C23)
Note that the strdup() function returns a pointer to a new string which is
a duplicate of the provided string. Memory for the new string is obtained with malloc, and must be freed by the calling process with free.
#Chris’s answer tells you what is wrong.
To fix it, you have options. The simplest is to make the argument array have strings (char arrays) that are big enough for your uses:
#define MAX_STR_LEN (9+1) // Every string’s capacity is 9+1 characters
void func(size_t n, char array_of_string[][MAX_STR_LEN])
{
for (size_t i=0; i<n; i++)
{
snprintf(array_of_string[i], MAX_STR_LEN, "#%d", (int)i); // use the extant string
}
}
int main(void)
{
char array_of_string[3][MAX_STR_LEN] = {{0}}; // Array of 3 strings
func(3, array_of_string);
...
return 0;
}
If you want to play with dynamic char * strings, life gets only a little more complicated:
void func(size_t n, char *array_of_string[])
{
for (size_t i=0; i<n; i++)
{
free(array_of_string[i]); // free any pre-existing string
array_of_string[i] = calloc( 10, 1 ); // allocate our new string
if (!array_of_string[i]) fooey(); // always check for failure
snprintf(array_of_string[i], 10, "#%d", (int)i); // use the new string
}
}
int main(void)
{
char *array_of_string[3] = {NULL}; // Array of 3 dynamic strings, all initially NULL
func(3, array_of_string);
...
for (size_t i=0; i<3; i++) // Don’t forget to clean up after yourself
free(array_of_string[i]);
return 0;
}
Ultimately the trick is to manage the size of your strings, remembering that a string is itself just an array of char. You must ensure that there is enough room in your character array to store all the characters you wish. (Good job on using snprintf()!
Also remember that in C any argument of the form array[] is the same as *array. So our functions could have been written:
void func(size_t n, char (*array_of_string)[MAX_STR_LEN])
or
void func(size_t n, char **array_of_string)
respectively. The first is an uglier (harder to read) syntax. The second is nicer, methinks, but YRMV.
Finally, if you are using C99 (or later) you can tell the compiler that those arguments are, actually, arrays:
void func(size_t n, char array_of_string[n][MAX_STR_LEN])
or
void func(size_t n, char *array_of_string[n])
MSVC does not support that syntax, though, and probably never will, alas.
{ // start of a new scope
char buf[10]; // a variable with automatic storage duration
// ...
} // end of scope - all automatic variables end their life
In your code, you make pointers point at buf which has seized to exist (3 times) at the } in the for loop. Dereferencing (reading from the memory those pointers point at) those pointers afterwards makes your program have undefined behavior (anything could happen).
What you can do is to allocate and release memory dynamically using malloc and free.
When sending in a pointer to the first element in an array of elements to a function like you do, it's also customary to provide the length of the array (the number of elements in the array) to the function.
It could look like this:
#include <stdio.h>
#include <stdlib.h>
// A macro to calculate the number of elements in an array
// sizeof (x) - the number of bytes the whole array occupies
// sizeof *(x) - the size of the first element in the array
// (all elements have equal size)
// The result of the division is the number of elements in the array.
#define SIZE(x) (sizeof (x) / sizeof *(x))
void func(char *s[], size_t len) {
for (size_t i = 0; i < len; i++) {
// calculate the required length for this string
size_t req = snprintf(NULL, 0, "#%zu", i) + 1; // +1 for '\0'
// and allocate memory for it
s[i] = malloc(req);
if(s[i] == NULL) exit(1); // failed to allocate memory
snprintf(s[i], req, "#%zu", i);
} // dynamically allocated memory is _not_ released at the end of the scope
}
int main() {
char *s[3];
func(s, SIZE(s));
for (size_t i = 0; i < SIZE(s); i++) {
puts(s[i]);
free(s[i]); // free what you've malloc'ed when you are done with it
}
}
Note that with the use of the macro there is only one hardcoded 3 in the program. Even that could be made into a named constant (#define CHAR_PTRS (3) or enum { CHAR_PTRS = 3 };) to further the ease of reading and maintaining the code.
A non-idiomatic version only accepting a pointer to an array of a fixed (at compile time) size could look like like below. In this example you couldn't accidentally provide a pointer to an array with only 2 char* (which would cause the function to write out of bounds). Instead, it'd result in a compilation error.
#include <stdio.h>
#include <stdlib.h>
// Here `s` is a pointer to an array of 3 char*
void func(char *(*s)[3]) {
for (int i = 0; i < 3; i++) {
(*s)[i] = malloc(10);
if((*s)[i] == NULL) exit(1);
snprintf((*s)[i], 10, "#%d", i);
}
}
int main() {
char *s[3];
func(&s); // &s is a char*(*)[3]
for (int i = 0; i < 3; i++) {
printf("%s\n", s[i]);
free(s[i]);
}
}
#include <stdio.h>
#include <string.h>
void func(char **s){
for(int i=0; i<3; i++){
s[i]=malloc(sizeof(char) * 100);
char buf[10];
snprintf(buf, 10, "#%d",i);
strcpy(s[i], buf);
}
}
int main()
{
char *s[3];
func(s);
for(int i=0; i<3; i++){
printf("%s", s[i]);
}
return 0;
}
This fixed my problem. My understanding is that I assigned memory and then copied the contents of buf to s to the now-present memory.

how do I assign individual string to an element in one array of pointer?

I am new to C and still trying to figure out pointer.
So here is a task I am stuck in: I would like to assign 10 fruit names to a pointer of array and print them out one by one. Below is my code;
#include <stdio.h>
#include <string.h>
int main(){
char *arr_of_ptrs[10];
char buffer[20];
int i;
for (i=0;i<10;i++){
printf("Please type in a fruit name:");
fgets(buffer,20,stdin);
arr_of_ptrs[i]= *buffer;
}
int j;
for (j=0;j<10;j++){
printf("%s",*(arr_of_ptrs+j));
}
}
However after execution this, it only shows me the last result for all 10 responses. I tried to consult similar questions others asked but no luck.
My understanding is that
1) pointer of array has been allocated memory with [10] so malloc() is not needed.
2) buffer stores the pointer to each individual answer therefore I dereference it and assign it to the arr_of_ptrs[i]
I am unsure if arr_of_ptrs[i] gets me a pointer or a value. I thought it is definitely a pointer but I deference it with * the code and assign it to *buffer, program would get stuck.
If someone could point out my problem that would be great.
Thanks in advance
Three erros, 1. You must allocate memory for elements of elements of arr_of_ptrs, now you only allocate the memory for elements of arr_of_ptrs on stack memory. 2. arr_of_ptrs[i]= *buffer; means all of the arr_of_ptrs elements are pointed to same memory address, which is the "buffer" pointer. So all the elements of arr_of_ptrs will be same to the last stdin input string. 3. subsequent fgets() call has potential problem, one of the explaination could be here
A quick fix could be,
#include <stdio.h>
#include <string.h>
int main(){
const int ARR_SIZE = 10, BUFFER_SIZE = 20;
char arr_of_ptrs[ARR_SIZE][BUFFER_SIZE];
char *pos;
int i, c;
for (i = 0; i < ARR_SIZE; ++i) {
printf ("Please type in a fruit name: ");
if (fgets (arr_of_ptrs[i], BUFFER_SIZE, stdin) == NULL) return -1;
if ((pos = strchr(arr_of_ptrs[i], '\n')))
*pos = 0;
else
while ((c = getchar()) != '\n' && c != EOF) {}
}
for (i = 0; i < ARR_SIZE; ++i)
printf("%s\n", arr_of_ptrs[i]);
return 0;
}
The misunderstanding is probably that "Dereferencing" an array of characters, unlike dereferencing a pointer to a primitive data type, does not create a copy of that array. Arrays cannot be copied using assignment operator =; There a separate functions for copying arrays (especially for 0-terminated arrays of char aka c-strings, and for allocating memory needed for the copy):
Compare a pointer to a primitive data type like int:
int x = 10;
int *ptr_x = &x;
int copy_of_x = *ptr_x; // dereferences a pointer to x, yielding the integer value 10
However:
char x[20] = "some text"; // array of characters, not a single character!
char *ptr_x = &x[0]; // pointer to the first element of x
char copy_of_first_char_of_x = *ptr_x; // copies the 's', not the entire string
Use:
char x[20] = "some text";
char *ptr_x = &x[0];
char *copy_of_x = malloc(strlen(ptr_x)+1); // allocate memory large enough to store the copy
strcpy(copy_of_x,ptr_x); // copy the string.
printf("%s",copy_of_x);
Output:
some text

HEAP CORRUPTION DETECTED memory leak in C

I got and error which says
Debug assertation failed and heat corruption detected
like everything is working good in my program but I get that error. Where is the memory leak here? I have to free that memory in the main because my functions need to return pointers.
My code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int *dynamic_reader(unsigned int n) {
/*making new array and checking if allocation succeeded*/
int *mem;
mem = malloc(n * sizeof(int));
if (!mem) {
printf("Memory allocation failed\n");
exit(-1);
}
/*letting the user to input the values for the array*/
int i = 0;
while (i < n) {
scanf("\n%d", &mem[i]);
i++;
}
/*printing the array just to make sure everything is good*/
for (int j = 0; j < n; j++) {
printf("%d ", mem[j]);
}
return mem;
}
int *insert_into_array(int *arr, unsigned int num, int newval) {
/*making new bigger array*/
int *newarr = realloc(arr, (num + 1) * sizeof(int));
/*adding the integer to this new array */
newarr[num] = newval;
printf("\n");
/*printing to make sure everything is correct*/
for (int j = 0; j < num + 1; j++) {
printf("%d ", newarr[j]);
}
return newarr;
}
int main(void) {
/*In dynamic_reader function I need to make an array which size is given as a parameter*/
/*In this case I choosed 3*/
int *arr = dynamic_reader(3);
int num = 3;
/*In insert_into_array function I need to add one integer to this array I made in dynamic_reader*/
/*The parameters are the array, the number of elements in the array already done and the integer I want to add*/
int *c = insert_into_array(arr, num, 9);
/*I free the memory here because I need to return the pointers of these arrays in the function so it cant be done there*/
free(arr);
free(c);
}
You are double freeing your memory. Check the documentation for realloc. Realloc will either 1) expand the passed buffer or 2) will allocate a new buffer, copy the data, and free the original buffer. When you do:
free(arr);
free(c);
You are double freeing a value that was either once already freed by realloc or already freed by the first free(arr)
Additionally, you should check if realloc fails (returns NULL) and if so, handle the case appropriately.
First you malloc an array, which you return to your main function as arr. Then in another function, you realloc where arr is an argument to the realloc, but some other pointer stores the results. Depending on what happened in realloc, you've either got arr and newarr pointing to the same location, or newarr pointing to a valid location and arr pointing to an invalid location that has been freed. Either way, freeing both of them at the end is a problem.
No need to free(arr), that is taken care of when you realloc() it. The pointer returned by realloc() will either point to memory which includes the original memory, or free the old memory after copying its content to a new, larger chunk of memory.

Partition a 1D char* into 2D char**

There are a lot of questions about converting a 2D array into a 1D array, but I am attempting just the opposite. I'm trying to partition a string into substrings of constant length and house them in a 2D array. Each row of this 2D matrix should contain a substring of the initial string, and, if each row were to be read in succession and concatenated, the initial string should be reproduced.
I nearly have it working, but for some reason I am losing the first substring (partitions[0] -- length 8*blockSize) of the initial string (bin):
int main (void){
char* bin = "00011101010000100001111101001101000010110000111100000010000111110100111100010011010011100011110000011010";
int blockSize = 2; // block size in bytes
int numBlocks = strlen(bin)/(8*blockSize); // number of block to analyze
char** partitions = (char**)malloc((numBlocks+1)*sizeof(char)); // break text into block
for(int i = 0; i<numBlocks;++i){
partitions[i] = (char*)malloc((8*blockSize+1)*sizeof(char));
memcpy(partitions[i],&bin[8*i*blockSize],8*blockSize);
partitions[i][8*blockSize] = '\0';
printf("Printing partitions[%d]: %s\n", i, partitions[i]);
}
for(int j=0; j<numBlocks;++j)
printf("Printing partitions[%d]: %s\n", j,partitions[j]);
return 0;
}
The output is as follows:
Printing partitions[0]: 0001110101000010
Printing partitions[1]: 0001111101001101
Printing partitions[2]: 0000101100001111
Printing partitions[3]: 0000001000011111
Printing partitions[4]: 0100111100010011
Printing partitions[5]: 0100111000111100
Printing partitions[0]: Hj
Printing partitions[1]: 0001111101001101
Printing partitions[2]: 0000101100001111
Printing partitions[3]: 0000001000011111
Printing partitions[4]: 0100111100010011
Printing partitions[5]: 0100111000111100
The construction of partitions in the first for loop is successful. After construction at read out, the string at partitions[0] contains garbage values. Can anyone offer some insight?
int numBlocks = strlen(bin)/(8*blockSize); // number of block to analyze
char** partitions = (char**)malloc((numBlocks+1)*sizeof(char)); // break text into block
for(int i = 0; i<numBlocks;++i){
partitions[i] = (char*)malloc((8*blockSize+1)*sizeof(char));
memcpy(partitions[i],&bin[8*i*blockSize],8*blockSize);
partitions[i][8*blockSize] = '\0';
printf("Printing partitions[%d]: %s\n", i, partitions[i]);
}
This all looks suspicious to me; it's far too complex for the task, making it a prime suspect for errors.
For reasons explained in answers to this question, void * pointers which are returned by malloc and other functions shouldn't be casted.
There's no need to multiply by 1 (sizeof (char) is always 1 in C). In fact, in your first call to malloc you should be multiplying by sizeof (char *) (or better yet, sizeof *partitions, as in the example below), since that's the size of the type of element that partitions points at.
malloc might return NULL, resulting in undefined behaviour when you attempt to assign into the location it points at.
Anything else (i.e. everything that isn't NULL) that malloc, calloc or realloc returns will need to be freed when no longer in use, or else tools such as valgrind (a leak detection program, useful for people who habitually forget to free allocated objects and thus cause memory leaks) will report false positives and lose part of their usefulness.
numBlocks, i, or anything else that's for counting elements of an array, should be declared as a size_t to follow standard convention (e.g. check the strlen manual, synopsis section to see how strlen is declared, noting the type of the return value is size_t). Negative values caused by overflows here will obviously cause the program to misbehave.
I gather you've yet to think about any excess beyond the last group of 8 characters... This shouldn't be difficult to incorporate.
I suggest using a single allocation, such as:
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BLOCK_SIZE 8
int main(void) {
char const *bin = "00011101010000100001111101001101000010110000111100000010000111110100111100010011010011100011110000011010";
size_t bin_length = strlen(bin),
block_count = (bin_length / BLOCK_SIZE)
+ (bin_length % BLOCK_SIZE > 0); // excess as per point 6 above
char (*block)[BLOCK_SIZE + 1] = malloc(block_count * sizeof *block);
if (!block) { exit(EXIT_FAILURE); }
for (size_t x = 0; x < block_count; x++) {
snprintf(block[x], BLOCK_SIZE + 1, "%s", bin + x * BLOCK_SIZE);
printf("Printing partitions[%zu]: %s\n", x, block[x]);
}
for (size_t x = 0; x < block_count; x++) {
printf("Printing partitions[%zu]: %s\n", x, block[x]);
}
free(block);
exit(0);
}
Their are a few problems with your code.
You are allocating **partitions incorrectly.
Instead of:
char** partitions = (char**)malloc((numBlocks+1)*sizeof(char)); /* dont need +1, as numblocks is enough space. */
You need to allocate space for char* pointers, not char characters.
instead, this needs to be:
char** partitions = malloc((numBlocks+1)*sizeof(char*));
Also read Why not to cast result of malloc(), as it is not needed in C.
malloc() needs to be checked everytime, as it can return NULL when unsuccessful.
Once finished with the space allocated, it is always good to free() memory previously requested by malloc(). It is important to do this at some point in the program.
Here is some code which shows this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BLOCKSIZE 2
#define BLOCK_MULTIPLIER 8
int main(void) {
const char *bin = "00011101010000100001111101001101000010110000111100000010000111110100111100010011010011100011110000011010";
const size_t blocksize = BLOCKSIZE;
const size_t multiplier = BLOCK_MULTIPLIER;
const size_t numblocks = strlen(bin)/(multiplier * blocksize);
const size_t numbytes = multiplier * blocksize;
char **partitions = malloc(numblocks * sizeof(*partitions));
if (partitions == NULL) {
printf("Cannot allocate %zu spaces\n", numblocks);
exit(EXIT_FAILURE);
}
for (size_t i = 0; i < numblocks; i++) {
partitions[i] = malloc(numbytes+1);
if (partitions[i] == NULL) {
printf("Cannot allocate %zu bytes for pointer\n", numbytes+1);
exit(EXIT_FAILURE);
}
memcpy(partitions[i], &bin[numbytes * i], numbytes);
partitions[i][numbytes] = '\0';
printf("Printing partitions[%zu]: %s\n", i, partitions[i]);
}
printf("\n");
for(size_t j = 0; j < numblocks; j++) {
printf("Printing partitions[%zu]: %s\n", j,partitions[j]);
free(partitions[j]);
partitions[j] = NULL;
}
free(partitions);
partitions = NULL;
return 0;
}
Which outputs non-garbage values:
Printing partitions[0]: 0001110101000010
Printing partitions[1]: 0001111101001101
Printing partitions[2]: 0000101100001111
Printing partitions[3]: 0000001000011111
Printing partitions[4]: 0100111100010011
Printing partitions[5]: 0100111000111100
Printing partitions[0]: 0001110101000010
Printing partitions[1]: 0001111101001101
Printing partitions[2]: 0000101100001111
Printing partitions[3]: 0000001000011111
Printing partitions[4]: 0100111100010011
Printing partitions[5]: 0100111000111100

program crashes while using realloc

I am given a text file of unknown size and i have to read it till the end, calculate the number of words, letters and some other stuff. To do this i try to read the entire file and save all the words in an array. I am told to use dynamic memory allocation since i don't know the size of the text file beforehand.
Before i get into the algorithm for calculating the words and letters i am trying to make the dynamic memory allocation work. This is my code:
int main(int argc, char *argv[]) {
FILE *fp; // file pointer
//defining a dynamic string array
char **array = malloc(10 * sizeof(char *)); //10 rows for now, will be dynamically changed later
int i,size = 10, current = 0; // current points to the position of the next slot to be filled
for(i=0; i<10; i++){
array[i] = malloc(20); //the max word size will be 20 characters (char size = 1 byte)
}
fillArray(fp, array, current, size);
return 0;
}
I define an array of strings, a variable showing its size, and a variable pointing to the slot where the next element will be added.
The functions are as follows:
int fillArray(FILE *fp, char **p, int ptr, int size){
puts("What's the name of the file (and format) to be accessed?\n (It has to be in the same directory as the program)");
char str[20];
gets(str); //getting the answer
fp = fopen((const char *)str, "r"); //opening file
int x=0, i=0, j;
while(x!=EOF){ // looping till we reach the end of the file
printf("current size: %d , next slot: %d\n", size, ptr);
if(ptr>=size){
printf("increasing size\n");
addSpace(p, &size);
}
x = fscanf(fp, "%19s", p[i]);
puts(p[i]);
i++;
ptr++;
}
}
void addSpace(char **p, int *size){ //remember to pass &size
//each time this is called, 10 more rows are added to the array
p = realloc(p,*size + 10);
int i;
for(i=*size; i<(*size)+10; i++){
p[i] = malloc(20);
}
*size += 10;
}
void freeSpace(char **p, int ptr){
//each time this is called, the rows are reduced so that they exactly fit the content
p = realloc(p, ptr); //remember that ptr points to the position of the last occupied slot + 1
}
At the beginning, the rows of the array are 10. Each time the words of the text don't fit the array, the function addSpace is called adding 10 more rows. The program runs succesfully 3 times (reaching 30 rows) and then crashes.
After using printf's to find out where the program crashes (because i am not used to the debugger yet), it seems that it crashes while trying to add 10 more rows (to 40). I can't figure out the problem or how to fix it. Any help is appreciated.
C is pass by value. The pointer p is passed to addSpace(p, &size);, and a copy of that pointer is created in the function. Once the copy is changed: p = realloc(p,*size + 10); the original stays the same.
After the realloc call, the original pointer is not valid anymore. Using it causes undefined behavior, a crash in your case.
Return the new value and assign it to the original pointer:
p = addSpace( p , &size );
Classic!
You are also passing in a double pointer which is reallocd, the address has changed between the caller and callee.
Also there's a realloc issue.
p = realloc(p,*size + 10);
If realloc fails, the original pointer to block of memory is clobbered.
The proper way to do this:
char **tmp_ptr = realloc(p, *size + 10);
if (tmp_ptr == NULL){
perror("Out of memory");
}else{
p = tmp_ptr;
}
return p;
You can do it another way, either return back the address of the new block or use triple pointers.
void addSpace(char ***p, int *size){ //remember to pass &size
//each time this is called, 10 more rows are added to the array
char **tmp_ptr = realloc(*p, *size + 10);
if (tmp_ptr == NULL){
perror("Out of memory");
}else{
*p = tmp_ptr;
}
int i;
for(i=*size; i<(*size)+10; i++){
*p[i] = malloc(20);
}
*size += 10;
}
And from the caller
addSpace(&p, &size);

Resources