0

I'm having a great deal of difficulty with pointers. What I am trying to accomplish sounds, to my ears, rather simple: I want to define a multi-dimensional char array, but not its size, and then have a second method allocate the necessary memory, and fill it up with the requested data.

Now, I've tried for countless hours to accomplish this, searched with Google until my eyes were dry and I still haven't been able to fix it. As such I was hoping any of you had any insight how this would be possible.

What I am imagining, is to define a pointer char** files, and a counter int total_files that will be used my the method print_files(). Print files will then calloc and malloc the variable, and then we'll fill it up with relevant data.

Now in the code below, I have attempted this; however, at runtime I just get the magnificently detailed message: "Segmentation fault (core dumped)". Upon debugging with GDB it points at:

 13  *files[i] = malloc(sizeof(char) * 100);

Now, this is for a introductory course to C programming (for Linux), and you might see numerous errors here. I do however, thank you for your time. I had no issues getting the code to work without the method / pointers, so I'm sure I might just be mixing up the syntax somehow.

#define _SVID_SOURCE
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<dirent.h>
#include <time.h>

int print_files(char*** files, int* total_files) {
int size = 10;  
**files = calloc(size, sizeof(char *));
for(int i = 0; i < size; i++) {
    *files[i] = malloc(sizeof(char) * 100);
}
*total_files = size;
}

int main() {
char** files;
int num_files;
num_files = 0;
printf("-- Start print_files\n");

print_files(&files, &num_files);

printf("-- end print_files, number of files: %d\n", num_files);

for(int i = 0; i < num_files; i++)
    printf("Out: %s\n", files[i]);

printf("total_files=%d\n", num_files);

return 0;
}

3 Answers 3

1
**files = calloc(size, sizeof(char *));

This assumes that not only files points to valid memory, but the value at that memory is also a valid pointer pointing to a pointer, which will be changed.

The problem is

char** files;
...
print_files(&files, &num_files);

&files is a valid pointer, but (**(&files)) (as dereferenced by print_files) is an illegal deference because files has not been initialized.

That print_files line should probably read

*files = calloc(size, sizeof(char *));

.

There is also a problem with

*files[i] = malloc(sizeof(char) * 100);

which is equivalent to

*(files[i]) = malloc(sizeof(char) * 100);

I think you probably mean

(*files)[i] = malloc(sizeof(char) * 100);
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for a short, simple and good answer. This was exactly what I was hunting for on Google. It told me what was wrong, why it was wrong and how I could fix it :)
1

Here's a working version:

#include <stdio.h>
#include <stdlib.h>

static void print_files(char ***files, int *total_files)
{
    int size = 10;  
    *files = calloc(size, sizeof(char *));
    for (int i = 0; i < size; i++)
    {
        (*files)[i] = malloc(sizeof(char) * 100);
        sprintf((*files)[i], "Line %d\n", i);
    }
    *total_files = size;
}

int main(void)
{
    char **files;
    int num_files;
    num_files = 0;
    printf("-- Start print_files\n");

    print_files(&files, &num_files);

    printf("-- end print_files, number of files: %d\n", num_files);

    for(int i = 0; i < num_files; i++)
        printf("Out: %s\n", files[i]);

    printf("total_files=%d\n", num_files);

    return 0;
}

The output is:

-- Start print_files
-- end print_files, number of files: 10
Out: Line 0
Out: Line 1
Out: Line 2
Out: Line 3
Out: Line 4
Out: Line 5
Out: Line 6
Out: Line 7
Out: Line 8
Out: Line 9
total_files=10

valgrind says "leaks like a sieve" but doesn't abuse memory while it is allocated.

What changed?

Triple pointers are scary. However, you want to use only one level of indirection in the assignment with calloc(). (With the double *, GCC warned that files in main() was used uninitialized!) Then, inside the loop, the parentheses around (*files) are critical too. The sprintf() simply serves to initialize the newly allocated string.

I didn't change the main() code significantly.

Comments

1
char **ppchar;
int x;
int y;

ppchar = (char**)malloc(sizeof(char*) * 100);
for (x = 0; x < 100; x++) {
    ppchar[x] = (char*)malloc(sizeof(char) * 100);
}

for(x = 0; x < 100; x++) {
    for(y = 0; y < 100; y++) {
        ppchar[x][y] = rand() % 255; // ascii range
    }
}

for(x = 0; x < 100; x++) {
    for(y = 0; y < 100; y++) {
        // char -128 to 127 or 0 to 255 - it's mostly machine
        // dependent.  This will tell you.
        printf("%d\t",ppchar[x][y]);
    }
}

//make sure to clean up the memory
for (x = 0; x < 100; x++) {
    free(ppchar[x]);
}

free(ppchar);

return 0;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.