Stuff like *(vector + 1)
is unnecessarily hard to read. You can just write vector[1]
. Maybe you're doing it as an exercise, but I'm not, so I'm going to translate everything into array syntax.
You have two problems. First is this:
scanf("%s",(vector+1));
This produces a compiler warning:
test.c:17:16: warning: format specifies type 'char *' but the argument has type 'char **' [-Wformat]
scanf("%s",(vector+1));
~~ ^~~~~~~~~~
(If you didn't get a compiler warning, turn them on with -Wall
and fix all of them).
scanf
wants a char *
, a string. But you've given it vector
, a list of strings, and shifted over one pointer.
scanf
is going to try to shove a string in there anyway. vector
has only been allocated 2 * sizeof(char*)
which is 8 bytes on a 64 bit machine. You shifted it over 1 char *
, or 4 bytes so there's only 4 bytes left. So it can "safely" cram 3 characters in there, plus a null byte. But C is sloppy, so scanf
can probably shove more in there without the operating system stopping it.
$ ./test
Ingrese una palabra: 123
Imprimiendo caracter a caracter:
hola
Segmentation fault: 11
It segfaults when you try to use vector[1]
as a string, because what should be a char *
pointing at perro
has been overwritten with the characters 123
and a null byte. It tries to use that as a pointer to memory and blows up.
Instead, you need to pass in a char *
. That's *(vector+1)
or simply vector[1]
.
scanf("%s", vector[1]);
This brings us to our next problem: you only ever allocated memory for vector
, a list of strings. You never allocated memory for the strings themselves! Assigning constants to the list isn't a substitute. As soon as I run the corrected code, I get a Bus error.
$ ./test
Ingrese una palabra: adlskfj
Bus error: 10
This is because vector[1]
contains a constant string perro
. You also got a warning about this.
test.c:13:19: warning: assigning to 'char *' from 'const char [6]' discards qualifiers
[-Wincompatible-pointer-types-discards-qualifiers]
*(vector + 1) = "perro";
^ ~~~~~~~
What that means is "hey, this is a constant string, but you're using it as if it wasn't constant!"
scanf
tries to overwrite it and fails. It can't overwrite that "memory" because it actually points to part of the compiled binary. If you print out the pointer you'll see it's very different front he rest.
printf("%p\n", vector[1]);
printf("%p\n", vector);
$ ./test
0x109ce7f51
0x7ff664c08d90
When I look at the binary with a hex editor, I find perro
at position 00000f51
along with other string constants in the program (yours will be at a different location).
00000f40: ffff 6841 0000 00e9 b4ff ffff 686f 6c61 ..hA........hola
00000f50: 0070 6572 726f 0025 700a 0049 6e67 7265 .perro.%p..Ingre
00000f60: 7365 2075 6e61 2070 616c 6162 7261 3a20 se una palabra:
00000f70: 0025 7300 0a49 6d70 7269 6d69 656e 646f .%s..Imprimiendo
00000f80: 2063 6172 6163 7465 7220 6120 6361 7261 caracter a cara
00000f90: 6374 6572 3a00 2563 0000 0a49 6d70 7269 cter:.%c...Impri
00000fa0: 6d69 656e 646f 2063 6f6d 706c 6574 6f3a miendo completo:
00000fb0: 0025 730a 0000 0000 0100 0000 1c00 0000 .%s.............
You can see the 0xf51
in 0x109ce7f51
. It's some magic memory location telling C to read from the binary, plus the offset 0xf51
. Whereas 0x7ff664c08d90
is pointing to read/write memory on the heap.
To store an array of strings, you have to allocate memory for the list and for the strings.
vector = malloc(2*sizeof(char*));
for( i = 0; i < 2; i++ ) {
vector[i] = malloc( 256 * sizeof(char*) );
}
printf("Ingrese una palabra: ");
scanf("%s",vector[1]);
Note that vector[1] = "perro"
would replace the pointer to the allocated memory with the constant string and you'd be back to the Bus error.
Also note that I don't cast malloc
.