How to get and unget input from streams in C (getstring, fgetc, ungetc).

preview_player
Показать описание
---

How to get and unget input from streams in C (getstring, fgetc, ungetc) // Reading a line from a file or stdin seems super basic, but a lot of students get hung up in the details. This video shows you how to get input from a stream, file, or pipe, using fgetc and ungetc to make your own function like the getstring function in Harvard's CS50 course.



***

Welcome! I post videos that help you learn to program and become a more confident software developer. I cover beginner-to-advanced systems topics ranging from network programming, threads, processes, operating systems, embedded systems and others. My goal is to help you get under-the-hood and better understand how computers work and how you can use them to become stronger students and more capable professional developers.

About me: I'm a computer scientist, electrical engineer, researcher, and teacher. I specialize in embedded systems, mobile computing, sensor networks, and the Internet of Things. I teach systems and networking courses at Clemson University, where I also lead the PERSIST research lab.

More about me and what I do:

To Support the Channel:
+ like, subscribe, spread the word

Рекомендации по теме
Комментарии
Автор

Surprisingly concise and clear explanation of a subject I've long been a bit fuzzy about. This clears a lot of things up for me. Next I'll look on tidying up that realloc business a bit more.
Thanks so much for your treatment of such a basic and important process.

lorensims
Автор

These videos are so great, your explanations are so clear! I also love how you leave your errors in the video and point them out and fix them, great reminder that nobody's perfect. Makes me less nervous about making errors in my own code, thanks!

avocadopeel
Автор

The original use for ungetc was to allow tokenizers to look ahead one character, see the c99 rational:
"ungetc is typically used to handle algorithms such as tokenization which involve one-character lookahead in text files"

oj
Автор

Thanks for the video! One small remark: The C11 standard states for realloc "If memory for the new object cannot be allocated, the old object is not deallocated and its value is unchanged." Thus there should actually be a free call after realloc if the result is null (if the original pointer is not null, of course).

ilu
Автор

I wrote something similar for my compiler to abstract I/O. In short, it doesn't have (like here) text mode. If you treat it like a text file, it will behave like a text file. I recognize the code for getting rid of all possible line endings. Note that ungetc() isn't unlimited. On Turbo C v2.1 (and probably others) you can put back only a single character.

HansBezemer
Автор

Fantastic really love you mate😘😘😘😘You really helped me to solve my all doubts

cpubug
Автор

Nice to explain ungetc with line termination differences.
A better way to handle the line termination differences itself is to open the text file using the "rt" mode.

maxaafbackname
Автор

I'd love to see a video about cross compilation of C code if you're looking for suggestions. Seems like it's becoming increasingly relevant as aarch64 gains ground in desktop and server usage.

noodlish
Автор

I'd probably use fgets + a static buffer and append the read bytes to the buffer.

oj
Автор

the malloc(1) at the end leaks the previous 50 bytes each time there’s an empty line. surprised gcc didn’t warn you about it.

itsmaxim
Автор

Hello, Jacob, thank you for all these videos. Why we used "char" data type instead "int" for c variable into get_string functions ? Usually "int" is required to EOF detect.

MrLag
Автор

I know the point here is on actually implementing an input function. But I'm surprised the POSIX "getline" function wasn't mentioned, since it essentially does this very thing, and should be available on any POSIX system. Either way, good video, as always.

nunyobiznez
Автор

19:35 "we can't remove all of it" me thinks back to the mmap video :)

mrcrackerist
Автор

UNIX and early C had ungetc(), it was useful to look ahead, say you wanted to remove whitespace, then reading till non-whitespace then unreading a char lead to far neater code. This stuff existed before MS ever existed.
Otherwise everything would have to peek ahead, or have 2 sources of char, 1 saved another fresh.
Basically any input tokenizer with a value needs to look ahead, but the hideous <CRLF> line termination can be solved by just ignoring '\c' on input.
The code with all the if statements is horrible, there's a lecture considering such code harmful like goto, it's a sign of poorly thought out structure, I've seen complete lexical analysers that were less messy.

RobBCactive
Автор

Love your vids doctor sorber, do you think its a good idea to create a programming language, which is procedural just like c, but with namespaces and operator overloading?

ahmadhadwan
Автор

I woulda passed the string pointer also int get_string, something like this:

char* getl( FILE *file, void **end )
{
typedef struct
{
int nil0;
char *root;
size_t size, leng, next;
int c;
/* We use 2 to ensure that which ever way the compiler puts
* the members into our struct (as coded or reversed) we still
* have a terminating character */
int nil1;
} getl_line;
getl_line c = {0}, _ = {0}, *p = &_;
char *str = NULL;

if ( *end )
p = *end;
str = p->root;

while ( (c.c = fgetc(file)) != EOF )
{
if ( c.c == '\f' )
{
if ( p->c == '\r' || p->c == '\n' )
{
p->c = 0;
continue;
}
goto success;
}

if ( c.c == '\n' )
{
if ( p->c == '\r' )
{
p->c = 0;
continue;
}
goto success;
}

/* We don't want to incorrectly detect the next newline
* character as part of the previous line now that we're sure
* we're on the next line */
p->c = 0;
if ( c.leng == c.next )
{
/* 72 to 80 is the usual line length editors wrap at
* so 100 will usually be enough */
c.next += 100;
c.size = c.next + sizeof(getl_line);
str = realloc( str, c.size );
if ( !str )
break;
c.root = str;
memset( str + c.leng, 0, c.next - c.leng );
}

if ( c.c == '\r' )
goto success;

str[(c.c)++] = c.c;
}

if ( c.leng )
{
success:
*end = p = (getl_line*)(str + c.next);
*p = c;
return str;
}

if ( str )
free( str );
return NULL;
}

**Edit:** Forgot to account for '\0' so I fixed that mistake

**Edit 2:** Decided the (sizeof(size_t) * 2) looked messy so I added a constant to replace it

**Edit 3:** Decided it was till fairly messy so I simplified it with an internal typedef'd struct

**Edit 4:** Noticed there would be a problem if the caller needed to exit before hitting EOF so I modified the function to instead shift the object to the end of the buffer, had the side effect of creating an end pointer

zxuiji
Автор

I am sorry, I am still a beginner. Without using a FILE, how can you just take the input from the user and not from a file? Thanks a lot in advance, I am a bit stuck on this definition.

federicosalvetti
Автор

Wouldn't there be a memory leak on line:77?

NarekJaghinyan
Автор

neither the buffer nor the capacity was static... so, the free didn't actually do what you thought it did.

mback
Автор

Where's the "mind repeat that in C" shirt?

Xdavidel
visit shbcf.ru