Question

I'm doing code to save what i will read in char *tmp (the return of get_next_line is a char *, read on fd 0) Get_next_line allocate the right space for char *tmp.

So i save tmp in data[i] which is a char ** in order to have all the inputs in char **data.

But I need to malloc a char **data but i don't know exactly what size will I need.

This code works, but it Segfault because i didn't malloc char **data.

I know how to malloc a char **, but here i don't know how to mallocate it because the size isn't constant.

Here's the code :

#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#include <stdio.h>

int redirection(char *prev, char *next) {
    int b;
    char *tmp;
    char **data;
    int i;

    i = 0;
    b = 0;
    while (b != 1) {
        while (strcmp(next, tmp) != 0) {
            printf("> ");
            tmp = get_next_line(0);
            data[i++] = tmp;
        }
        data[--i] = 0;
        i = 0;
        while (data[i] != 0)
           printf("DATA = [%s]\n, data[i++]");
        b = 1;
    }
    free(tmp);
    return (0);
  }

Here's a main for tests :

int main(int ac, char **av) {
    if ((redirection("START", "STOP")) == -1) {
         printf("REDIRECTION FAIL\n");
         return(-1):
    }
    return(0);
}
Was it helpful?

Solution 2

I think what you are looking for is realloc()

When you have reached the pointer limit of what you have allocated you can add more pointers.

e.g.

size_t rows = 10;

char**  data = malloc( sizeof(char*) * rows );
size_t row = 0;

...

tmp = get_next_line(0);

if ( ++row == rows )
{
  row = 0;
  rows += 10;
  char** expanded = realloc( data, sizeof(char*) * rows );
  if ( expanded != NULL )
  {
    data = expanded;
  }
  // else error
}

data[i++] = tmp;

...

A side note:

It looks like you overwrite the last string when you do

while (b != 1) {
    while (strcmp(next, tmp) != 0) {
        printf("> ");
        tmp = get_next_line(0);
        data[i++] = tmp;
    }
    data[--i] = 0; <---- maybe you meant `data[i]=NULL;`

OTHER TIPS

A char** is a "pointer to char*".

What yo uhave to come to is a structure linke this:

char** [_] ----- > char* |_| ----> [__________]  <-- this is M * sizeof(char)
                   char* |_| ----> [__________]
                   char* |_| ----> [__________]
                   char* |_| ----> [__________]
                   char* |_| ----> [__________]
                   char* |_| ----> [__________]
                          ^                   ^
                          |                   \-- this is just char
                  This is N*sizof(char*)

This is how to malloc **data:

#define NUMBER_OF_ROWS      10
#define NUMBER_OF_COLUMNS   20

data = malloc(NUMBER_OF_ROWS * sizeof(char*));
for (i = 0; i < NUMBER_OF_ROWS; i++)
{
  data[i] = malloc(NUMBER_OF_COLUMNS * sizeof(char));
}

You should free memory as you malloced it.

Welcome to the world of manual allocation ! If you want to allocate your own buffers, you must know what you can do with them ... and free them as soon as you can ...

Here are some possibilities that I allready used depending on problem :

  • the two pass method : on first pass you don't allocate anything but simply count how many elements you will have : very simple, efficient in space, but not in time. Don't even think of that if you are reading a flow and not a file ...
  • the high max method : if you can know in advance that you will have never more than xxx elements, allocate a buffer of size xxx ... and do verify that the program do not further ! If it does, you should at least output a kind message explaining what is happening - fast and simple but not really bullet proof (you should allow user to customize your max if you ever try this method in real world, but can it deal with flows)
  • the chained buffers method : you first allocate a buffer of size n (generally n between 16 and 1024), and when exhausted you allocate another buffer. In reality, you should allocate a

    struct Buff {
        struct Buff* next;
        int nElts;
        char **elts; /* in fact enough size for nElts char pointers */
    }
    

    You can allocate buffers of same size, or double the size at each iteration depending if you have an idea of real number of elements that you will have to manage. This one is both time and space efficient, but it is no longer simple as you will have to manage pointer arithmetic over the different buffers.

If none of this methods agree you, you could also have a look to standard C++ library or Boost where efficent algorithms are allready coded ...

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top