#Need help with dynamic allocation

110 messages · Page 1 of 1 (latest)

round spruce
#

I am writting a program that is designed to take any length of string as an input from stdin
This means I can't use field widths, at least I dont think I can.

This is moreso me having a ton of questions about stdin:
-What happens to characters in stdin that are not put into a string-for instance, what happens when too many characters are put into a field width? Where do the characters that aren't inputted go, is there a way to retrieve them?
-Is there a way to determine the size of whats stdin before I allocate for an array? As to prevent scanf from overflowing an array if-say for instance, 11 values are inputted into a string but it can only hold 10 values-is there a way to reallocate it before I scanf and determine that "there are 11 characters in the stream"?

ebon burrowBOT
#

When your question is answered use !solved to mark the question as resolved.

Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question run !howto ask.

round spruce
#

another question:

#

an idea i had was using errno to achieve this

#

if scanf causes an overflow, then i could reallocate and continue outputting to said string

#

but im 80% sure that runtime errors terminate the program so idk

#

my issue is that scanf dosent check to see if an overflow occurs, and since im not positive if fgets flushes the input stream

#

idk how i can dynamically allocate for an array without discarding the users input

#

and reallocating thereafter

#

my current idea is using getchar

#

since getchar gets characters one by one as opposed to scanf which reads stdin as one long string

#

i can check to see if im about to cause an overflow and reallocate accordingly

#

the problem is-as far as im aware-that would decrease the speed of my program drastically

surreal cradle
#

Is there a way to determine the size of whats stdin before I allocate for an array?
No. The reason is pretty simple: You'd have to consume the stream first. Consuming a stream may sound complex but it quiet literally just means to get the next value(s) from it. The other important characteristic of a stream is that once you've read something it's consumed and you can't "put it back" into the stream (technically it probably is possible but then it'd get really complex).

So to know how many characters there are in the standard input stream (stdin) we'd either have to count while we consume characters or we first store all characters, then count them. The problem of the first approach is that we then know how long the string would've been, but we can't get the content anymore. The problem with the latter is exactly your problem, namely that we don't know how many characters we should reserve to store the string.

Now the solution you take really depends on your problem.
F.e. if you just want to echo what the user inputted (yes, this is a real past tense of 'input'), then this can be done fairly easily like so:

char in[8];  // usually you would use a larger buffer size
while (fgets(in, 8, stdin))
    printf("%s", in);

But if you want to store the entire string in one variable then - as you've already figured out - that's not possible with arrays, you'll need pointers for that using malloc and realloc:

size_t cur_size = 1;
char *in = NULL;
char temp[8];
while (fgets(temp, 8, stdin)) {
    cur_size += 7;
    char *in2 = realloc(in, cur_size);
    if (!in2) {
        // Critical error
        return;  // what exactly you do in case of an error (or if you even need to respect it) depends on your problem
    }

    in = in2;
    strcat(in, temp)  // from string.h
}
round spruce
#

so the while statement here reads in increments of 8 correct

#

oh wait no thats the buffer size specifier

#

but why add 8? what if you come across a buffer size thats less than 8? then you would have an innaccurate vale for curr_size

#

unless thats the intention, if say we want to have a little bit of leeway for innaccurate sizes

#

for instance we have a little bit of extra space

surreal cradle
#

What happens to characters in stdin that are not put into a string-for instance?
As long as they aren't consumed they'll remain in the stream. Once they are consumed they are no longer accessible/obtainable from the stream.

what happens when too many characters are put into a field width?
This is a so called buffer overflow and one of the first vulnerabilities you learn about. Buffer overflows can have catastrophic consequences ranging from nothing happening at all over the program crashing up to hackers being able to exploit your program.

Where do the characters that aren't inputted go, is there a way to retrieve them?
That aren't input into the stdin stream? They never existed to begin with. The ones that aren't stored in a string? As I said, they are consumed and no longer obtainable from the stream.

round spruce
#

when is stdin stuff consumed

#

outside of delibrately consuming the values it holds

#

from what you've told me, they exist until they are either a: flushed from the buffer, or b: put into a variable

surreal cradle
round spruce
#

oh that makes sense

surreal cradle
round spruce
#

so i could take the approach i am now, just in a larger increment in terms of buffer

surreal cradle
#

These functions all call READ systemcalls which then consume the stream

round spruce
#

this makes way more sense now

#

imma just repeat it in my own words and call out if im wrong

#

stdin characters dont really exist until they are inputted into something

surreal cradle
round spruce
#

but as data, they stay there until they are consumed

surreal cradle
round spruce
#

here

#

i have a struct typedef that takes 3 things:

#

-1) the size of the array, set to 0

#

-2) the capacity, set to 1025 by default

#

-3) the data it holds

#

the approach im taking now is with getchar

surreal cradle
round spruce
#

where i was wrong is that i was using getchar with a variable

#

which i cant do

#

that consumes them

#

or i can actually

#

yeah i can

#

but getchar isnt the best approach

#

it works, but it reads 1 at a time

#

fgets reads several

surreal cradle
#

Yup

round spruce
#

scanf shouldnt be used here as mentioned because it dosent check as it goes along, it kinda just puts it all in at once and if it dosent fit

#

then the program terminates

#

fgets is more careful in terms of actually inputting data into strings

surreal cradle
#

Yeah. The 5 rules of scanf are:

  • Rule 0: Don't use scanf(). (Unless, you know exactly what you do.)
  • Rule 1: scanf() is not for reading input, it's for parsing input.
  • Rule 2: scanf() can be dangerous when used carelessly. Always use field widths with conversions that parse to a string (like %s).
  • Rule 3: Although scanf() format strings can look quite similar to printf() format strings, they often have slightly different semantics. (Make sure to read the fine manual)
  • Rule 4: scanf() is a very powerful function. (and with great power comes great responsibility ...)
round spruce
#

scanf is quick but dangerous

#

fgets trades a little bit of speed for a more consistent yield

#

thankyou btw, serious lack of stdin articles out there

#

most of them assume you are learning about stdio.h functions

#

not stdin itself

#

oh while im here

#

with custom headers, do you define struct datatypes with there respective values in the header or the c file it correlates too

#

wait nvm figured it out

#

thanks!

#

wait one last thing

#

is this correct syntax thus far for a header file?

#

or no?

surreal cradle
#

!f

ebon burrowBOT
#
#pragma once
#ifndef uArr.h
#define uArr .h
#include <stdio.h>
typedef struct {
  char* uStr;
  size_t capacity;
  size_t currSize;

} uarrmax_t;

uarrmax_t dSet() {}
uarrmax_t iSet() {}
uarrmax_t sSet();

#endif

Weeb
round spruce
#

oh okay

ebon burrowBOT
#
How to Format Code on Discord
Markup

```cpp
int main() {}
```

Result
int main() {}
round spruce
#

just trying to dive into abstraction because its really one of the coolest parts of programming

surreal cradle
#
#ifndef uArr.h
#define uArr .h

that should probably be #define uArr.h, no?

round spruce
#

oh shit

#

also another thing

#

headers dont have any code in terms of functions in stuff

#

all of them are overriden by the c file that correlates to it

#

there all abstract functions

surreal cradle
#

Also I wouldn't do this:

typedef struct {
  char* uStr;
  size_t capacity;
  size_t currSize;

} uarrmax_t;

but rather

struct uarrmax_t {
  char* uStr;
  size_t capacity;
  size_t currSize;

};

typedef struct uarrmax_t uarrmax_t;

Not because I know what I'm doing but again because of this #c-help-text message message I already linked.
@narrow sinew Would you be so kind as to quickly verify that I'm not completely mistaken here.

round spruce
#

ill look at that

#

again i could be wrong

#

abstract functions are found everywhere and it would be intresting if something in c made use of them and only them

surreal cradle
#

You come from an OOP language like Java, don't you?

round spruce
#

yeah

#

i do

#

kind of

#

im akward at that language but i know what im doing to some degree

ebon burrowBOT
#

@round spruce Has your question been resolved? If so, run !solved :)

round spruce
#

@surreal cradle sorry to bother you again

#

but how do you put the characters into the buffer after doing all of that?

#

not the buffer

#

the string

surreal cradle
#

wdym?

round spruce
#

well this is for allocating right?

#

but it dosent output it too the string

#

which is what is meant to happen but

#

im lost as to how to actually get them from the buffer once its don

#

*done

#

or how to terminate the loop for that matter

surreal cradle
#

Aaah

#

oaky, got it

#

What happens I think is that your program just gets hung on the fgets call since I screwed up a bit in the code earlier

round spruce
#

oh crap

surreal cradle
#
size_t cur_size = 1;
char *in = NULL;
char temp[8];
while (fgets(temp, 8, stdin)) {
    cur_size += 7;
    char *in2 = realloc(in, cur_size);
    if (!in2) {
        // Critical error
        return NULL;  // what exactly you do in case of an error (or if you even need to respect it) depends on your problem
    }

    in = in2;
    strcat(in, temp)  // from string.h

    if (strlen(temp) < 7 || temp[7])
        return in;
}
#

Okay, didn't really screw up, just forgot that one part at the end

round spruce
#

thankyou ive been stuck on this for so long this shits wack

ebon burrowBOT
#

This question thread is being automatically closed. If your question is not answered feel free to bump the post or re-ask. Take a look at !howto ask for tips on improving your question.