1

I am trying to write a c program, which will take an input from Linux pipe and puts each word up to the point when it encounters \n into arrays. Then it outputs the words. It works when array contain less than 3 \n but it gives me segmentation error if there is 3 \n`s in the input. Here is the code that I wrote, please help. I am new to programming,so please try to live the code as intact as possible.

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

int main()
{
  int out=0;
  int in=0;
  char **arr2D;
  int i;
  int flag = 1;
  arr2D=(char**)malloc(out*sizeof(char*));
  for(i=0;i<out;i++)
    arr2D[i]=(char*)malloc(in*sizeof(char*));

  while (!feof(stdin))
    {
      in = in +1;
      arr2D[out]=(char*)realloc(arr2D[out],(in)*sizeof(char*));
      scanf("%c",&arr2D[out][i]);

      i=i+1;
      if(arr2D[out][i-1]=='\n')
        {
        out=out+1;
        arr2D=(char**)realloc(arr2D,out*sizeof(char*));
        i=0;
        in=0;
        }
    }

  int out2=0;
  int in2=0;
  do
    {
      do
        {
          printf("%c",arr2D[out2][in2]);
          in2++;
        }
      while(in2<=in-1);
      out2++;
      in2=0;
    }
  while(out2<=out);

  printf("\n");
  return 0;
}
Ken Y-N
  • 14,644
  • 21
  • 71
  • 114
user1335175
  • 181
  • 7
  • 20

4 Answers4

2

Following code work correctly:

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


int main(int argc, char *argv[])
{
    int out = 1;
    int in = 1;
    char **arr2D;
    int i = 0;

    arr2D = malloc(out * sizeof(char *));
    for (i = 0; i < out; i++)
          /* IMPORTANT */
          arr2D[i] = malloc(in * sizeof(char));

    while (!feof(stdin)) {

        scanf("%c", &arr2D[out - 1][in - 1]);

        in++;
        if (arr2D[out - 1][in - 2] == '\n') {
            arr2D[out - 1][in - 2] = '\0';
            out++;
            arr2D = realloc(arr2D, out * sizeof(char *));
            /* IMPORTANT */
            arr2D[out - 1] = NULL;
            in = 1;
        }

        /* IMPORTANT */
        arr2D[out - 1] = realloc(arr2D[out - 1],in * sizeof(char));


    }

    int out2 = 0;
    do {
        printf("%s\n", arr2D[out2++]);
    } while(out2 < out);
    printf("\n");
    return 0;
}
Parham Alvani
  • 2,305
  • 2
  • 14
  • 25
  • Even though that's a bug, it's definitely not the cause for the segmentation fault: `sizeof(char*)` is always greater than `sizeof(char)` (unless you are on an 8 bit architecture, that is...). – cmaster - reinstate monica Feb 07 '15 at 21:48
  • That seem not to change anything my friend. – user1335175 Feb 07 '15 at 21:56
  • Sorry, I still reading your code if find something I will tell you. – Parham Alvani Feb 07 '15 at 21:58
  • @cmaster there are non-8bit architectures where those sizes are equal. (Also I never heard of an 8bit architecture that didn't actually use 16bit pointers, although theoretically they're possible) – M.M Feb 07 '15 at 22:29
0

You haven't properly initialized the variable i within your while loop.

int i;
scanf("%c",&arr2D[out][i]);
0

First you allocate a buffer for out elements, but then you proceed to access arr2D[out] which is out of bounds in the first line with realloc(). Remember that indexing of an array int arr[size] in C is always from 0 to size-1, arr[size] is never ok.

For reference: the allocation line is the first malloc() call:

arr2D=(char**)malloc(out*sizeof(char*));

and the line with the first undefined behavior is the second line within the while() loop:

arr2D[out]=(char*)realloc(arr2D[out],(in)*sizeof(char*));

within the first while() loop. That is the point that invokes undefined behavior, and after which anything is allowed to happen.

cmaster - reinstate monica
  • 38,891
  • 9
  • 62
  • 106
  • Im note sure which part of the code you are referring to, even if I am commenting the output part, I still get the error, so I know the bug is in the part when I construct my arrays. – user1335175 Feb 07 '15 at 22:00
  • I added the offending lines to my answer, hope that helps you to find what I mean. – cmaster - reinstate monica Feb 07 '15 at 22:02
  • Im sorry for redundant questioning my friend, can you specify how exactly can I fix that line ? Because in my understanding, the first parameter of realloc should be the arr2D[out] itself. – user1335175 Feb 07 '15 at 22:15
  • First, the element at `arr2D[out]` must *exist*. That is, you first need to `realloc()` the outer array so that you have room for at least one more element. Then, and only then can you proceed to write to that new element. *The first time you get to the `realloc()` line, there is* **zero** *elements in the out array `arr2D`*. – cmaster - reinstate monica Feb 07 '15 at 22:19
  • Oh I see what do you mean, any explanation why it works in the case when there is less than 3 \n in the input tough ? – user1335175 Feb 07 '15 at 22:21
  • Well, it's undefined behavior, anything can happen. Including what you expected to happen. Many implementations of `malloc()` will actually allocate a block of a certain minimal size, which can hide the bug. But you can't rely on that. The nasty thing about undefined behavior is that it generally won't crash the program right away. Instead, some other data get corrupted which you happen to overwrite with an out-of-bounds memory access, the corruption propagates silently, and strikes at a seemingly unrelated place. `valgrind` is the only tool that can effectively track down many of these bugs. – cmaster - reinstate monica Feb 08 '15 at 09:57
0

Parham`s method seems to work, Also I found another way, altough Im not sure if there is something wrong in doing this, but it works.

Evey time when I am allocating or reallocating, I multiply the *sizeof(char) buy a buffer size which is a big number.

user1335175
  • 181
  • 7
  • 20