-1

This might look really silly, but I don't understand what is happening...

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

/*
gcc -o test test.c -std=c99 && time ./test

*/


int main(int argc, char **argv)
{
  char **s;
  s =  malloc(10);
  s[0] = malloc(100);
  s[1] = malloc(100);
  s[2] = malloc(100);
  s[3] = malloc(100);
  s[4] = malloc(100);
  s[5] = malloc(100);
  s[6] = malloc(100);
  s[7] = malloc(100);
  s[8] = malloc(100);
  s[9] = malloc(100);

  strcpy(s[0],"test");
  strcpy(s[1],"test");
  strcpy(s[2],"test");
  strcpy(s[3],"test");
  // strcpy(s[4],"test");

  printf("%s", s[0]);

  return 0;
}

If I uncomment strcpy(s[4],"test"); I get seg fault. If I malloc 149 instead of 10, I get seg fault by copying string to [20] element. I'm coding with c neraly year and it's my first time when I truly feel dump...

Could someone explain me why this is happening?

EDIT

Ok, my mistake. What about:

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

/*
gcc -o test test.c -std=c99 && time ./test

*/


int main(int argc, char **argv)
{
  char **ar = NULL;
  ar = malloc(sizeof(**ar) * 10);

  for (int i = 0; i < 10; i++)
  {
      char ic[2];
      sprintf(ic, "%d", i);
      int l = strlen(ic);
      ar[i] = (char*)malloc(sizeof(*ar[i]) * (l + 1));
      strcpy(ar[i], ic);
      // asprintf(&(ar[i]), "%d", i);
      printf("%s\n", ar[0]);
  }

  return 0;
}

Get output like this:

0
0
0
0
�@
�@
�@
�@
�@
�@
dbush
  • 205,898
  • 23
  • 218
  • 273
n3m0k54
  • 21
  • 2
  • 2
  • 3
    `sizeof(**ar) == sizeof(char) == 1`. So your allocating only 10 bytes. Also, [don't cast the result of `malloc`](http://stackoverflow.com/q/605845/3425536). – Emil Laine Sep 17 '15 at 14:40
  • 3
    Don't cast malloc() and repalce sizeof(**ar) with sizeof(char *) – Michi Sep 17 '15 at 14:47
  • 2
    Please one question per question. If the first question was answered and you have a follow-up question, please post a new question. – Lundin Sep 17 '15 at 14:54
  • always check (!=NULL) the returned value from each call to malloc() to assure the operation was successful. – user3629249 Sep 17 '15 at 18:02

5 Answers5

5

Change to s = malloc(10 * sizeof (char *)). You have array of 10 pointers (usually 4 bytes each) but have allocated only 10 bytes.

i486
  • 6,491
  • 4
  • 24
  • 41
5
s =  malloc(10);

Not enough memory for 10 pointers.

s =  malloc(10*sizeof(char *));

And instead of writing so many statements -

s[0] = malloc(100);
s[1] = malloc(100);
s[2] = malloc(100);
s[3] = malloc(100);
s[4] = malloc(100);
s[5] = malloc(100);
s[6] = malloc(100);
s[7] = malloc(100);
s[8] = malloc(100);
s[9] = malloc(100);

Use a loop.

int i;
for(i=0;i<10;i++)
  {
     s[i]=malloc(100);
  } 

And free them in similar manner.

In you posted code after EDIT -

 ar = malloc(sizeof(**ar) * 10);      

Should be -

  ar = malloc(sizeof(char *)*10);

And don't cast result of malloc .

ameyCU
  • 16,489
  • 2
  • 26
  • 41
3

Well this actually allocates

s =  malloc(10);

basically allocates about 10 bytes of memory to s

Now legally / Strictly you are allowed to use only 10 bytes not even 1 byte more, but remember there is no boundary checking for C, so one can write pass the allocated memory ( no compiler error will be generated )

Similar thing happened with your program.

An memory summary of your program looks like this ( taken from valgrind )

==4378== Invalid write of size 8
==4378==    at 0x4005C1: main (t.c:16)
==4378==  Address 0x51fc048 is 8 bytes inside a block of size 10 alloc'd
==4378==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4378==    by 0x400596: main (t.c:14)
==4378==
==4378== Invalid write of size 8
==4378==    at 0x4005D6: main (t.c:17)
==4378==  Address 0x51fc050 is 6 bytes after a block of size 10 alloc'd
==4378==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4378==    by 0x400596: main (t.c:14)
==4378==
==4378== Invalid write of size 8
==4378==    at 0x4005EB: main (t.c:18)
==4378==  Address 0x51fc058 is 14 bytes after a block of size 10 alloc'd
==4378==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4378==    by 0x400596: main (t.c:14)
==4378==
==4378== Invalid write of size 8
==4378==    at 0x400600: main (t.c:19)
==4378==  Address 0x51fc060 is 22 bytes after a block of size 10 alloc'd
==4378==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4378==    by 0x400596: main (t.c:14)
==4378==
==4378== Invalid write of size 8
==4378==    at 0x400615: main (t.c:20)
==4378==  Address 0x51fc068 is not stack'd, malloc'd or (recently) free'd
==4378==
==4378== Invalid write of size 8
==4378==    at 0x40062A: main (t.c:21)
==4378==  Address 0x51fc070 is not stack'd, malloc'd or (recently) free'd
==4378==
==4378== Invalid write of size 8
==4378==    at 0x40063F: main (t.c:22)
==4378==  Address 0x51fc078 is 24 bytes before a block of size 100 alloc'd
==4378==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4378==    by 0x4005A4: main (t.c:15)
==4378==
==4378== Invalid write of size 8
==4378==    at 0x400654: main (t.c:23)
==4378==  Address 0x51fc080 is 16 bytes before a block of size 100 alloc'd
==4378==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4378==    by 0x4005A4: main (t.c:15)
==4378==
==4378== Invalid write of size 8
==4378==    at 0x400669: main (t.c:24)
==4378==  Address 0x51fc088 is 8 bytes before a block of size 100 alloc'd
==4378==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4378==    by 0x4005A4: main (t.c:15)
==4378==
==4378== Invalid read of size 8
==4378==    at 0x400685: main (t.c:27)
==4378==  Address 0x51fc048 is 8 bytes inside a block of size 10 alloc'd
==4378==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4378==    by 0x400596: main (t.c:14)
==4378==
==4378== Invalid read of size 8
==4378==    at 0x40069A: main (t.c:28)
==4378==  Address 0x51fc050 is 6 bytes after a block of size 10 alloc'd
==4378==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4378==    by 0x400596: main (t.c:14)
==4378==
==4378== Invalid read of size 8
==4378==    at 0x4006AF: main (t.c:29)
==4378==  Address 0x51fc058 is 14 bytes after a block of size 10 alloc'd
==4378==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4378==    by 0x400596: main (t.c:14)
==4378==
==4378== Invalid read of size 8
==4378==    at 0x4006C4: main (t.c:30)
==4378==  Address 0x51fc060 is 22 bytes after a block of size 10 alloc'd
==4378==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4378==    by 0x400596: main (t.c:14)
==4378==

as you can see there have been invalid reads and writes through out the prrgram with malloc(10);

however replacing the same malloc statement with

s = malloc( 10 * sizeof( char * ) );

will instantly clear all the errors except for one thing, clearing the allocated memory which is missing from you code.

asio_guy
  • 3,667
  • 2
  • 19
  • 35
2
s =  malloc(10);

This line allocates 10 bytes, not 10 pointers! A pointer is stored on several bytes, usually 4 or 8 on todays architectures.

Do this instead:

s =  malloc(10*sizeof(char*));
galinette
  • 8,896
  • 2
  • 36
  • 87
-3

s = malloc(10); reserves you 10 bytes of memory, but you want enough memory for 10 pointers. You should be using

//s = malloc(10*sizeof(int)); Wrong
s = malloc(10*sizeof(char*));

Edit: Sorry, you are right it should be char* instead of int, my mistake

Mr. E
  • 2,070
  • 11
  • 23
  • 3
    s = malloc(10*sizeof(int)); will break on any platform on which int and pointers are of a different size, which is for example true for 64bit Windows, 64bit OSX and 64bit Linux. – Kaiserludi Sep 17 '15 at 14:38