1

I've made a function that allows the input of a string via keyboard. This function has two arguments: the maximum possible length of the string and a pointer to char. What happens inside the function is that an array of characters, which has as many elements as the maximum length, gets declared and then the string given by the user gets temporarly stored in that very array. Once the acquisition of the string is done, I use the calloc function to allocate just the right amount of memory to store that same string in the pointer to char that has been passed as an argument.

int main(void)
{
    char* test;

    stringInput(test, 10);

    printf("%s", test);

    return 0;
}

void stringInput(char* string, int maxStringLength)
{
    char tempString[maxStringLength];

        //STRING GETS PROPERLY STORED IN tempString

    string = (char*)calloc(strlen(tempString)+ 1, sizeof(char));

    strcpy(string, tempString);

    return;
}

This sorts of work, meaning that if I try to print "string" before this function hits return, the program actually displays what it is supposed to. However, when I try to print "test" in the main function, it doesn't print anything, which means that stringInput isn't modifying the pointer that gets passed to it. I've further confirmed this by printing the address of "test" before the function call, after the calloc line and again after the function call, which showed me that it changes after the calloc but then gets back to its previous value when the function ends. How can I solve this problem?

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
Gian
  • 327
  • 2
  • 8
  • 1
    don't you need `void stringInput(char** string, int maxStringLength)` ? which is a pointer to a pointer; which will let you modify it in the method. – Shark May 07 '19 at 12:54

2 Answers2

4

The problem here is, test itself is passed by value, which is stored in string, and any change you make to string will not reflect back to test.

You need to pass a pointer to test, if you want to modify test itself.

Something like

 stringInput(&test, 10);

and

void stringInput(char** string, int maxStringLength)
{
    char tempString[maxStringLength];

        //STRING GETS PROPERLY STORED IN tempString

    *string = calloc(strlen(tempString)+ 1, sizeof(char));  // no need to cast
    if (!string) {
       printf("error in calloc!!\n");
       return;
     }
    strcpy(*string, tempString);

    return;
}
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • he does not want judging from the example – 0___________ May 07 '19 at 12:53
  • @P__J__ He does not want what? – Sourav Ghosh May 07 '19 at 12:55
  • I know this was in OP's code, but `strlen(tempString)` is invalid here (unless the `//STRING GETS PROPERLY STORED IN tempString` comment is a placeholder for some code to do that). Perhaps you could address this point in your answer. – Ian Abbott May 07 '19 at 12:58
  • 1
    @IanAbbott Why is that invalid? I think it's reasonable to assume that the comment should be changed to code that properly initializes `tempString`. – klutt May 07 '19 at 13:00
  • Thank you, this was really helpful! It's a little bit annoying that I need to pass the address of a pointer instead of just the pointer itself, but if that's how it's done and there are no other options, that's fine by me. – Gian May 07 '19 at 13:07
  • 2
    @Gian Well, that's just how C works. Everything is passed by value. – klutt May 07 '19 at 13:13
  • 1
    @Gian Reasonable and/or nice C code would either accept a pointer to a buffer and that buffer's size, and only store so many characters, or allocate and *return* a pointer to the buffer. – unwind May 07 '19 at 13:14
  • @Broman Yeah, but I actually didn't know that you can do that with pointers as well. I mean, I guess it's pretty obvious that that would be an option, but I had never tried it before. Guess I learned something new and useful today. – Gian May 07 '19 at 13:23
  • @unwind Indeed, `test = stringInput(10);` would be a cleaner-looking interface in this case. – Ian Abbott May 07 '19 at 13:23
  • @IanAbbott That's a good point, though. Are there any other reasons I should choose an approach over another, aside from how clean it would look on code? – Gian May 07 '19 at 13:30
  • @Gian, Yes, if there are several functions that modify the same object, you would pass a pointer to the object. But your `stringInput` function just allocates a new object each time it is called, so doesn't need to do that. – Ian Abbott May 07 '19 at 13:32
  • I've got a problem: when I pass an array of characters to the function, I get a warning: i.imgur.com/fXeoPzE.png Also, the function acts really weird when it gets an array as argument. Isn't an array of characters just a pointer to char with already allocated memory? Shouldn't it be working just the same? What am I missing here? – Gian May 07 '19 at 14:55
  • @Gian and why'd you do that? An array is **NOT** a pointer they are very different. Just because in some cases array name decays to a pointer to the first element, does not mean array and pointer are same. – Sourav Ghosh May 07 '19 at 14:57
  • Actually I would never have reasons to use this function with an array of characters, but I was confused by this behavior since they taught me in class that arrays are basically just pointers. Maybe a misunderstanding on my part or an oversimplification on the teacher part? – Gian May 07 '19 at 15:03
  • @Gian Or, lack of knowledge from your TA's part. :) – Sourav Ghosh May 07 '19 at 15:04
  • Can't tell you that, but it might be that he didn't delve into this because this difference hasn't really been relevant to the course yet. – Gian May 07 '19 at 15:26
2

When you calloc into string, you only modify the local copy of string, not the test variable. What you may want to do is pass in and operate on a pointer to your char pointer.

You could change you function signature to:

void stringInput(char **string_p, int maxStringLength)

Then, replace you usages of string with *string.

Finally, you would call your function passing in a pointer to test, not its value:

stringInput(&test, 10);

This is one way of doing things, though you could also return a pointer, depending on how you want to structure things.

Thomas Jager
  • 4,836
  • 2
  • 16
  • 30
  • Yeah, I had tried to return a pointer and it worked perfectly, but that's not really what I wanted. However, problem solved, thanks to you as well! – Gian May 07 '19 at 13:12