0

I've come a cross a problem where, when I'm using scanf to store a string into a char pointer, I have 3 inputs - name, surname, and age, that surname's last char value get replaced by age here's the output to better explain.

Q-riosity v0.0.1
Enter your name
Evgeny

Enter your surname
Danilenko

Enter your age
22

Evgeny Danilenk22, you are 22 years old

Here's the code

void getUserDetails(char** value)
{
    char *key[3] = {"name", "surname", "age"};
    int keySize = sizeof(key)/sizeof(char*);
    printf("Q-riosity v0.0.1\n");

    int i = 0;

    for(i = 0; i<keySize; i++)
    {
        printf("Enter your %s \n", key[i]); // name, surname, age
        scanf("%s", &value[i]);             //stores value at index i
    }

    printf("%s, %s, you are %s years old\n", &value[0], &value[1], &value[2]);
}

EDIT

Enter your name
Evgeny

Enter your surname
Danilenko

Enter your age
22

Segmentation fault

int main(int argc, char* argv[])
{

    char *key[3] = {"name", "surname", "age"};
    int keySize = sizeof(key)/sizeof(char*);
    printf("Q-riosity v0.0.1\n");
    char* value[keySize];

    int i = 0;
    for(i = 0; i<keySize; i++)
    {
        printf("Enter your %s \n", key[i]);
        scanf("%s", value[i]);
    }


    for(i = 0; i<keySize; i++)
    {
        printf("%s : %s \n", key[i], value[i]);
    }


    return 0;
}
Evgeny Danilenko
  • 181
  • 2
  • 10

4 Answers4

2

You are passing a char** to both printf and scanf. The %ss expect char*s, not char**s. So, replace the following:

scanf("%s", &value[i]);
printf("%s, %s, you are %s years old\n", &value[0], &value[1], &value[2]);

with

scanf("%s", value[i]);
printf("%s, %s, you are %s years old\n", value[0], value[1], value[2]);

The new code has one problem:

char* value[keySize];

creates an array of size keySize of pointers to char. These pointers are uninitialized and could be pointing to anywhere. You write to these uninitialized pointers via scanf and this invokes the famous Undefined Behavior.

Solutions for this include:

  1. malloc memory for each pointer.
  2. Make the pointers point to some valid memory location as shown in @SergeBallesta's answer.
  3. Use a 2D array:

    char value[keySize][64];
    
Community
  • 1
  • 1
Spikatrix
  • 20,225
  • 7
  • 37
  • 83
  • Actually before I came up with that solution, i had exact same code you are suggesting me, however, i am getting segmentation error. also im not using malloc anywhere, im just passing passing input, to vars. I'll update the post with my previous code, so you'll see it for yourself. – Evgeny Danilenko Mar 21 '16 at 14:05
2

Hmm, the output Danilenk22 suggests that your value variable was declared in caller as consecutive char arrays with size 8.

When you read Danilenko as surname, you write 10 characters (including the terminating \0. The first 8 fill the reserved array, the last 2 go in array for age. When you later read the age, it overrides those 2 characters.

Lets look at memory (? represent unitialized or don't care characters):

   0  1  2  3  4  5  6  7  0  1  2  3  4  5  6  7  0  1  2  3  4  5  6  7
   E  v  g  e  n  y \0  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?
   E  v  g  e  n  y \0  ?  D  a  n  i  l  e  n  k  o \0  ?  ?  ?  ?  ?  ?
   E  v  g  e  n  y \0  ?  D  a  n  i  l  e  n  k  2  2 \0  ?  ?  ?  ?  ?

But eight characters could also be the size of a pointer on a 64 bits architecture...

Your edit shows that you fail to initialize correctly the value array of pointers. Assuming that you want to have 32 characters for name and surname, and 4 for the age, you could do:

char _v0[32], _v1[32], _v2[4];
char* value[keySize] = { _v0, _v1, _v2 };

That way the program no longer seg fault.

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • Yea i think thats one of the reasons. I tried writing surname first, then name, etc, now the surname is concatenated with the name... How would i go about it? I am running a 64 bit machine – Evgeny Danilenko Mar 21 '16 at 14:21
1

Replace line

printf("%s, %s, you are %s years old\n", &value[0], &value[1], &value[2]);

with

printf("%s, %s, you are %s years old\n", value[0], value[1], value[2]);

Remember, you want to print a value, not its address.

NOTE : scanf() requires a pointer in order to read properly, so its syntax is

scanf("%s", &str);
Marievi
  • 4,951
  • 1
  • 16
  • 33
1

Assuming value is well-malloced before it's passed:

Simply change the printf() statement to

printf("%s, %s, you are %s years old\n", value[0], value[1], value[2]);

and your scanf() statement to

scanf("%s", value[i]);

In fact, printf("%s", &str) invokes undefined behaviour, although it usually works properly. This is because str and &str have different types, despite the fact that their values are identical. To verify this, simply run

printf("%p\n%p\n%p\n%p", (void *)str, (void *)(str + 1), (void *)&str, (void *)(&str + 1));

See also: Why scanf("%s",&str); behaves as scanf("%s",str);?

Community
  • 1
  • 1
nalzok
  • 14,965
  • 21
  • 72
  • 139