0

i have the next code and I have problem with those two lines of code, printf("Ingrese una palabra: "); scanf("%s",(vector+1)); If they were not, it works fine, but if I want to modify the word "perro" and ask one the user gives error.

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

int main()
{
    int i,j,a;
    char **vector;

    vector = (char**)malloc(2*sizeof(char*));

    *(vector) = "hola";
    *(vector + 1) = "perro";

    //HERE IS THE PROBLEM
    printf("Ingrese una palabra: ");
    scanf("%s",(vector+1));
    //

    puts("\nImprimiendo caracter a caracter:");
    for(i=0;i<2;i++) 
    {
        for(j=0; j<strlen(*(vector+i)) ; j++)
        {
            printf("%c",*(*(vector+i)+j));
        }
        puts("");
    }

    puts("\nImprimiendo completo:");
    printf("%s\n",*vector);
    printf("%s",*(vector+1));

    free(vector);

    return 0;
}
EmiliOrtega
  • 159
  • 1
  • 2
  • 9
  • May you explain what are you trying to do? – Iharob Al Asimi Feb 09 '17 at 20:19
  • 3
    Isn't `(vector+1)` a pointer to a pointer? Wouldn't you want to pass a pointer to scanf? (Maybe `*(vector+1)`? Secondly those strings are read only so attempting to modify them should segfault – Michael Petch Feb 09 '17 at 20:20
  • 2
    At `scanf("%s",(vector+1));` you are writing to read-only memory. (Subject to @MichaelPetch remark). Because you initialised the pointer with a pointer to a *string literal*. Even if you could, the input is limited to the 5 character length of the doggish *perro*. – Weather Vane Feb 09 '17 at 20:20
  • @MichaelPetch Yes, but scanf receives a memory address, and when I pass it (vector * 1) I am giving it the memory address it is pointing to (vector + 1), which is the vector that is inside or is it wrong? – EmiliOrtega Feb 09 '17 at 20:26
  • @IharobAlAsimi I'm just proving things about double pointers – EmiliOrtega Feb 09 '17 at 20:28
  • 1
    With g++ and strong warning flags, I get this: `..\main.c:17:5: error: format '%s' expects argument of type 'char *', but argument 2 has type 'char **' [-Werror=format=]` – Fred Larson Feb 09 '17 at 20:28
  • @EmiliOrtega You need to learn before handling double pointers, that string literals are read only and what you apparently attempt is going to be **undefined behavior**. – Iharob Al Asimi Feb 09 '17 at 20:36
  • On a completely unrelated not, if you are in fact using _C_ (and not C++) then this question/answer may be of interest: http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc – Michael Petch Feb 09 '17 at 20:43

2 Answers2

1

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.

Schwern
  • 153,029
  • 25
  • 195
  • 336
-1

You are accessing 2 pointeurs without having initialized them. you need to reserve some space for you 2 vectors because they will contains characters.

claudio06
  • 44
  • 3
  • He created an array of char * pointers (room for 2 `char *` pointers ) and then initialized the first 2 elements of the array to the address of two strings. So the array has appropriate space for 2 `char *` allocated for it (with malloc) and both array items are initialized. Unfortunately they are initialized to pointers that will be in read only memory, and he forgot to do the pointer dereferencing on the `scanf` – Michael Petch Feb 09 '17 at 20:48
  • yes the pointers are assigned to litteral strings, so has you say they are not modifiable. That's what I mean by not initialized.. I should add properly.. – claudio06 Feb 09 '17 at 21:01