-1

I have an function that loads data and put them into an array

char array_of_string() {
    char **array;
    size_t size = 5;
    size_t index = 0;
    size_t length = 0;
    int rd;
    char *line;
    array = (char **) malloc(size * sizeof(char*));
    while ((rd = getline(&line, &length, 0) != -1) {
      array[index] = malloc(strlen(line) + 1 * sizeof(char));
      strncpy(array[index], line);
      index++    
    }

   free(line);
   return array;
}

int main() { 
  char **here;
  here = array_of_strings();
}

but this does not work , this is the ebst result of trying , how can i make it work?

6
  • 1. Althought using sizeof(char) is completely redundant since it must be 1, you have a mistake here strlen(line) + 1 * sizeof(char), since sizeof(char) has to be multiplied by the whole expression. 2. Define doesn't work! Commented Jan 14, 2016 at 22:37
  • 2
    strncpy(array[index], line); does not compile. Suggest enable all compiler warnings and first get the code to compile. If a particular compiler error is difficult post that. "this does not work" is not sufficient. Be sure to use #include <string.h> and others. Commented Jan 14, 2016 at 22:37
  • free(line); I dont see that you allocated this memory Commented Jan 14, 2016 at 22:48
  • @Lashane See getline(). Commented Jan 14, 2016 at 22:51
  • @chux yep, already noticed Commented Jan 14, 2016 at 22:51

2 Answers 2

1

As mentioned in the comment, you have several issues to correct. Starting with "Why is getline not working?" getline takes a FILE * stream pointer not a file descriptor as its third parameter. Using stdin instead of 0 will correct the problem. The remaining problems deal with allocation. Those have been discussed in the comments and corrected examples are shown below.

The biggest issue you will run into, is "How will I know how many lines were actually read?" You have hard-coded '5', but what if you read less than 5?

To answer the question, you need to, at minimum, pass a pointer as a parameter to your array_of_string function, and update it value with the index value so that the number of lines read is available back in the calling function (main() in this case). That way, you always know the number of lines read. For example:

char **array_of_string (size_t *n)
{
    ...
    free (line);

    *n = index;  /* update n with index, so available in main() */

    return array;
}

Your next challenge is "How do I check to make sure I don't read, and try to store, more than 5 lines?" Then, "What do I do if I have more than 5 lines to read?", "Then what?". That is where you either break from your read loop or, better, use the realloc function to reallocate array to increase the number of pointers available. (you can add as many as you want, but a standard approach is to double the current number of pointers you have -- that approach is shown below).

#define MAXLN 5
...
char **array_of_string (size_t *n)
{
    ...
    size_t maxln = MAXLN;
    ...
    while ((rd = getline(&line, &length, stdin)) != -1)
    {
        ...
        array[index++] = strdup(line); /* alloc & copy  */

        if (index == maxln) {   /* check limit reached  - reallocate */
            char **tmp = realloc (array, maxln * sizeof *array * 2);
            if (!tmp) {
                fprintf (stderr, "error: realloc - memory exhausted.\n");
                *n = index;
                return array;
            }
            array = tmp;  /* set new pointers to NULL */
            memset (array + maxln, 0, maxln * sizeof *array);
            maxln *= 2;
        }
    }
    ...
}

Putting all the pieces together, you could do something like the following, which initially allocate some reasonably anticipate number of pointers to hold the number of lines you expect to read. If you reach that limit before your read is done, you simply realloc the number of pointers to 2X current. (you realloc using a tmp pointer to protect against loss of all existing data in array if realloc fails. if realloc succeeds, you simply assign array = tmp;)

Take a look at the following and let me know if you have any questions about it:

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

#define MAXLN 5

char **array_of_string (size_t *n);

int main (void) {

    char **here = NULL;
    size_t i, lines = 0;

    /* assign array_of_string to here, check return */
    if (!(here = array_of_string (&lines))) {
        fprintf (stderr, "error: array_of_string return NULL.\n");
        return 1;
    }

    for (i = 0; i < lines; i++) /* print lines */
        printf (" line[%3zu] : %s\n", i, here[i]);

    for (i = 0; i < lines; i++) /* free lines */
        if (here[i]) free (here[i]);
    free (here);  /* free here */

    return 0;
}

char **array_of_string (size_t *n)
{
    char **array = NULL;
    char *line = NULL;
    size_t index = 0, length = 0, maxln = MAXLN;
    ssize_t rd = 0;

    if (!(array = calloc (MAXLN, sizeof *array))) {
        fprintf (stderr, "error: virtual memory exhausted.\n");
        return NULL;
    }

    while ((rd = getline(&line, &length, stdin)) != -1)
    {
        while (rd > 0 && (line[rd-1] == '\r' || line[rd-1] == '\n'))
            line[--rd] = 0; /* strip carriage return or newline   */

        array[index++] = strdup(line); /* alloc & copy  */

        if (index == maxln) {   /* check limit reached  - reallocate */
            char **tmp = realloc (array, maxln * sizeof *array * 2);
            if (!tmp) {
                fprintf (stderr, "error: realloc - memory exhausted.\n");
                *n = index;
                return array;
            }
            array = tmp;  /* set new pointers to NULL */
            memset (array + maxln, 0, maxln * sizeof *array);
            maxln *= 2;
        }
    }
    free(line);  /* free memory allocated by getline */

    *n = index;  /* update n with index, so available in main() */

    return array;
}

Compile - with warnings enabled

gcc -Wall -Wextra -o bin/stdintst stdintst.c

(or using similar options for your compiler)

Input File

cat ../dat/damages.txt
Personal injury damage awards are unliquidated
and are not capable of certain measurement; thus, the
jury has broad discretion in assessing the amount of
damages in a personal injury case. Yet, at the same
time, a factual sufficiency review insures that the
evidence supports the jury's award; and, although
difficult, the law requires appellate courts to conduct
factual sufficiency reviews on damage awards in
personal injury cases. Thus, while a jury has latitude in
assessing intangible damages in personal injury cases,
a jury's damage award does not escape the scrutiny of
appellate review.

Because Texas law applies no physical manifestation
rule to restrict wrongful death recoveries, a
trial court in a death case is prudent when it chooses
to submit the issues of mental anguish and loss of
society and companionship. While there is a
presumption of mental anguish for the wrongful death
beneficiary, the Texas Supreme Court has not indicated
that reviewing courts should presume that the mental
anguish is sufficient to support a large award. Testimony
that proves the beneficiary suffered severe mental
anguish or severe grief should be a significant and
sometimes determining factor in a factual sufficiency
analysis of large non-pecuniary damage awards.

Use/Output

$ ./bin/stdintst <../dat/damages.txt
 line[  0] : Personal injury damage awards are unliquidated
 line[  1] : and are not capable of certain measurement; thus, the
 line[  2] : jury has broad discretion in assessing the amount of
 line[  3] : damages in a personal injury case. Yet, at the same
 line[  4] : time, a factual sufficiency review insures that the
 line[  5] : evidence supports the jury's award; and, although
 line[  6] : difficult, the law requires appellate courts to conduct
 line[  7] : factual sufficiency reviews on damage awards in
 line[  8] : personal injury cases. Thus, while a jury has latitude in
 line[  9] : assessing intangible damages in personal injury cases,
 line[ 10] : a jury's damage award does not escape the scrutiny of
 line[ 11] : appellate review.
 line[ 12] :
 line[ 13] : Because Texas law applies no physical manifestation
 line[ 14] : rule to restrict wrongful death recoveries, a
 line[ 15] : trial court in a death case is prudent when it chooses
 line[ 16] : to submit the issues of mental anguish and loss of
 line[ 17] : society and companionship. While there is a
 line[ 18] : presumption of mental anguish for the wrongful death
 line[ 19] : beneficiary, the Texas Supreme Court has not indicated
 line[ 20] : that reviewing courts should presume that the mental
 line[ 21] : anguish is sufficient to support a large award. Testimony
 line[ 22] : that proves the beneficiary suffered severe mental
 line[ 23] : anguish or severe grief should be a significant and
 line[ 24] : sometimes determining factor in a factual sufficiency
 line[ 25] : analysis of large non-pecuniary damage awards.

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/stdintst <../dat/damages.txt
==12233== Memcheck, a memory error detector
==12233== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==12233== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==12233== Command: ./bin/stdintst
==12233==
 line[  0] : Personal injury damage awards are unliquidated
 line[  1] : and are not capable of certain measurement; thus, the
<snip>
 line[ 24] : sometimes determining factor in a factual sufficiency
 line[ 25] : analysis of large non-pecuniary damage awards.
==12233==
==12233== HEAP SUMMARY:
==12233==     in use at exit: 0 bytes in 0 blocks
==12233==   total heap usage: 31 allocs, 31 frees, 1,989 bytes allocated
==12233==
==12233== All heap blocks were freed -- no leaks are possible
==12233==
==12233== For counts of detected and suppressed errors, rerun with: -v
==12233== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)

Always confirm All heap blocks were freed -- no leaks are possible and equally important ERROR SUMMARY: 0 errors from 0 contexts.

Let me know if you have any further questions.

Sign up to request clarification or add additional context in comments.

Comments

0

If you're going to keep array_of_string outside of your main function, (which is a good idea), then you should pass a pointer to the array so that you can directly edit the contents of the array itself. If you declare or allocate memory in a scope, it will be automatically deallocated once the scope ends. If you then try to access that memory, you get undefined results. Pass array to function in C

Also:

while ((rd = getline(&line, &length, 0) != -1) {
  array[index] = malloc(strlen(line) + 1 * sizeof(char));

Getline will alter length to be the size of the string that was allocated. You could remove strlen(line) and replace it with length, or with rd instead to save some CPU cycles. Do keep in mind that it's possible for rd and length to be different. Getline(3)

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.