0

I have trouble trying to return the string that is scanned in a function and return the string to the first pointer string argument.

The string is a new thing I just learn this week. I tested passing back arguments as integer and character, and both of them work. The code is as follows. This is just part of the code because the whole project is in 3 files. As the code shows, the string is meant to send as an address (the string does not need a & sign). The function scans the input string, and the string gets sent back as an argument.

To be honest, this is my assignment, using return to send back the string is not an option.

`

char stringValue[7] = { '\0' };
input(stringValue, 4, 6);
printf("The string is %s", stringValue);

void input(char* string, int minimum, int maximum)
{
    char inputs[7];

    scanf("%[^\n]", inputs);

    *string = charInRange;
}

`

When I run it, the printing of the value is random. I tested with other tool, and it said:

"assignment makes from pointer without a cast."

I am sure that the problem is probably the line assigned input to the pointer. I think it's some format error. I tried adding some &, *, or removing them. I spent the whole testing and searching for an answer but no result.

2
  • 1
    Why not scanf("%[^\n]", string);?? Properly scanf("%6[^\n]", string); (you must use the field-width modifier to protect your array bounds -- that's why fgets() is a superior input function) You don't need inputs[]. Also char stringValue[7] = ""; is sufficient to initialize all zero. You cannot assign the contents of a string in C. *string = charInRange; won't work. You were thinking strcpy (string, input);, but the use of input would be superfluous. Commented Nov 18, 2022 at 2:05
  • Of course you need the scanf() a continual loop and reread if strlen (string) < mininum) -- field-width sets the maximum. Otherwise, your two parameters minimum and maximum are unused. They should be type size_t as strlen() returns size_t. Commented Nov 18, 2022 at 2:12

1 Answer 1

4

Continuing from my comments, your primary problem in input() is you read into the array char inputs[7]; with scanf("%[^\n]", inputs); and then attempt to assign charInRange (nowhere declared in your code) as the first character in string. This won't compile.

When you attempt to print stringvalue back in main, since charInRange isn't defined (or isn't initialized or is initialized outsize the range for ASCII characters), you get gibberish.

As explained in the comments, the input[] array isn't necessary. You have already declared storage for stringvalue in main() and are passing the address for that storage (the pointer char *string) to the input() function. You simply need to read into string in the input() function. The input[] array is unnecessary.

However, before looking at how you can do that, when you are providing a buffer (a character array) for user-input -- Don't Skimp on Buffer Size. When you use scanf() with "%[ ]" the user can enter any number of characters beyond you array size, writing beyond the end of your array. This is a favorite exploit by buffer overrun.

If using the "%s" or "%[ ]" format specifiers with scanf() you must provide a field-width modifier to limit the number of characters that can be read. Failure to do so renders scanf() no safer than gets(). See Why gets() is so dangerous it should never be used!

This is just one of the scanf() pitfalls, and one of the reasons why new C programmers are encouraged to take all user-input with fgets().

With that said, let's look at how we can write your input() function to only accept a user-input of between min and max chars. As mentioned, whenever you have conditions your input must meet, the approach is the loop continually reading input from the user (your read-loop). Check the length of what the user entered and only if the length is from min to max, break your read-loop and return.

To ensure your read-buffer is sufficiently sized, make it larger than what you anticipate the max string you will accept is. (a lot longer, you have a 4M stack on Linux and a 1M stack on Windows) a 1K buffer is fine. On embedded systems where memory is limited, then adjust the buffer size down. When you need to set constants in your code #define them, don't just throw Magic Numbers like 4 and 6 in as parameters. You can do that with:

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

#define INPUTSZ 1024      /* if you need a constant, #define one (or more) */
#define MAXC 6
#define MINC 4

Now you can write your input() function similar to:

void input (char *string, size_t min, size_t max)
{
  /* loop continually until valid input given */
  for (;;) {
    size_t len;   /* length to test against min */
    
    fputs ("\nenter string: ", stdout); /* always prompt for input */
    
    /* take all user-input with fgets (into a larger buffer - don't skimp)
     * validate the return of every input function used.
     */
    if (!fgets (string, INPUTSZ, stdin)) {
      puts ("(user canceled input)");   /* return is NULL, Ctrl+d (z) used */
      *string = 0;                      /* set string as empty-string */
      return;
    }
    
    len = strcspn (string, "\n");       /* get length of input minus '\n' */
    string[len] = 0;                    /* overwrite '\n' with '\0' */
    
    if (min <= len && len <= max) {     /* condition met, break read loop */
      break;
    }
    
    /* handle invalid input */
    fprintf (stderr, "input must be %zu-%zu characters\n", min, max);
  }
}

(note: you can save the length while trimming the '\n' from string in a single step, e.g. string[(len = strcspn (string, "\n"))] = 0;, but that was split for readability above. Also note 0 and '\0' are equivalent. 0 being the ASCII value for the nul-character, see ASCII Table)

And finally your main(), e.g.

int main (void) {
  
  char stringvalue[INPUTSZ] = "";
  
  input (stringvalue, MINC, MAXC);
  
  if (*stringvalue) {
    puts (stringvalue);
  }
}

(note: the stringvalue is only printed if the user didn't cancel by generating a manual EOF with Ctrl + d (Ctrl + z on windows))

Can you look and determine what line in the input() function allows you to make the test if (*stringvalue)? Note *stringvalue is the same as *(stringvalue + 0) which is the pointer notation for stringvalue[0].

Example Use/Output

Does the code limit input to the proper number of characters?

$ ./bin/inputmaxmin

enter string: 12
input must be 4-6 characters

enter string: 123
input must be 4-6 characters

enter string: 1234567
input must be 4-6 characters

enter string: 1234
1234

What about handling the user canceling input with Ctrl + d?

$ ./bin/inputmaxmin

enter string: one hundred twenty-three
input must be 4-6 characters

enter string: (user canceled input)

Also, you seem a little iffy on pointers. Here are a couple of links that provide basic discussions of pointers that may help. Difference between char pp and (char) p? and Pointer to pointer of structs indexing out of bounds(?)... (ignore the titles, the answers discuss pointer basics)

Look things over and let me know if you have questions.

Sign up to request clarification or add additional context in comments.

11 Comments

Concerning buffer size, C has "An implementation shall support text files with lines containing at least 254 characters, including the terminating new-line character. The value of the macro BUFSIZ shall be at least 256.". IMO, BUFSIZ or maybe 2x BUFSIZ is reasonable. Beyond BUFSIZ, code trends on thinning ice.
Hmm we can fix that with my trusty 1024. Thanks for the thinning ice report.
Sure. - me I tend to use max(4K,BUFSIZ) on non-embedded apps.
Agreed. So if, in the changed example, we read 1023 characters and the next, unread just happens to the '\n' char, there is no adverse effect. Perhaps a little more learning required, but compared to the scanf() which was replaced, everything, all caveats in fgets() use can be explained in a fraction of the time a detailed discussion of scanf() -- Pitfalls would (and still have time left over for dinner, movies and drinks)
As @chux-ReinstateMonica stated, unless you have reason to reduce the size of the buffer (array), use the standard BUFSZ to size char stringValue[BUFSZ];. (on Linux, that provides a standard buffer size of 4096 and if I recall correctly 512 bytes on Windows -- may be more now)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.