Updates: Tyler on PowerHacking CSS to cutestrap your app in this latest episode!

Topic 6 - stdio: File Functions and Basic Parsing


  • data: producers and consumers
  • files - data at rest, tape era APIs
    • seek (sequential/stream) model - filepos
    • random access - doesn’t fit consume once media
  • fopen/fclose, file spec / access types
    • Input (r)
    • Output (w)
    • Appending - later
  • writing to a file and reading it back in
    • fgets (gets), fputs (puts), fprintf
    • fprintf to a string - sprintf, dangers
    • checking file I/O return types - different
  • parsing a 3 column ASN TSV and line ending pitfalls
  • naming in stdio: s, f, n conventions in function names


hello everybody here we are
i have the enceladus horus
on remote are you there hi
she's totally there okay and we're doing
c as an additional language so tonight
we're going to be doing
topic six which is the new topic six
because the old topic six that was just
a bridge too far
and uh we're going to be doing um file i
o tonight
in uh using using c standard io stuff
so for those of you who were here
earlier for the refactoring
like nathaniel i am sorry we decided at
the last minute not to go with that code
there was sort of a
insidious last minute bug and i think ah
let's let's focus on the learning stuff
but i'll hold that back uh with the
refactor for
uh next week's session so anyway in the
uh yeah let's let's do i and i actually
you saw it i rolled that 20.
that totally happened so
i'm still in shock about that so yeah
all right well
let's let's get our let's get our setup
set up all right so we have a
little bit of fun well all right i made
that up for you but
here's our regular interface and
um of course jessie's going to be
following along
some of this or the stream or however
she wants to do that
and uh we have a little bit of stuff to
go over so let me
i got the glove on so we're ready to
whiteboard all right
or as nightshade dude loves to pick on
me for blackboard
alright so files what are files
jesse oh you're asking me
we have the wonder of all this
interactivity so
uh data that's stored in memory yes
uh so memory is the fun part of that
definition so
specifically when we're talking about
files we mean kind of like
like data at rest if you yeah like like
hard drive memory not yeah um it could
be a hard drive it could be a tape it
could be
that's in the era that a lot of these
functions were written it was usually
so all right that'll that'll help you
with a little perspective on why some of
these functions will seem a little crazy
um that that actually kind of really
quickly touches on the difference
between something that's random access
and something which is seek based
so this
random access is sort of like this data
at rest
but you can kind of jump to any point
within that file
so at any moment you can just say okay
just start at like byte
3725 and read in the next meg you know
like like that
just take that and map it into memory
and so that's like i can jump anywhere i
want i can then jump back to like
five i could go five bytes in i could go
five gigs in
you know like so that that random means
that i can jump anywhere i want
seeking means that i have to get there
so this is really more of the notion of
a tape you know and if you think back
then it was usually a magnetic
reel i'm gonna guess back in back in the
and you know you had your reel and you
know this was like some sort of magnet
you know stuff there's a
really nice physics description of
what's going on there so
um and in order to be able to jump
anywhere in this file you had to
actually like
physically wind this thing and that
would physically wind this thing
so that's annoying
right because there's actually a
physical thing that's happening as we're
sort of like twisting around here and
and that action we refer to as seeking
now pretty much everything that's built
into stdio that we're going to be using
for files
which we're using the standard input
output is seek based
it's not random based so
so you have this sort of implicit notion
whenever you open up a file
you've got something associated with it
which is where
okay and this is this is kind of like
more formally called your file
pass but this is this is like where you
where the tape is like in this
particular file
so i can read ahead and when i read
the tape moves and i get the bytes that
were there and i read them into memory
and that's all cool and i can also
and i can say yeah go back and
you know move the file position negative
versus moving the
file position positive so
you always have to keep in mind that
when you're reading you don't with with
standardio you don't get to jump around
directly like you actually have to send
in commands and say i want you to go to
this place or i want
i've already consumed this input like
whenever you read something you're
moving the tape so if i have a file
and not in a tape sense but keep in mind
tapes of where this was built
so if i've got a file and it says
something like you know
i don't know nc
and then it says uh some guy
and then it says nathaniel bombo and
i don't know if i'm pronouncing that
right but uh
as i read each one of these things off
the file position is kind of moving
forward so it sort of starts off here at
zero and as i start reading this stuff
and assuming these things are separated
by new lines
then i consume that part of the file so
it's like i'm going to read this thing
and then the file is going to point here
for the file position and then i'm going
to read this thing
so here i read nc
and here i read sg and here i read
nathaniel and
as i'm reading it i'm consuming it off
it's sort of like this
this tape keep this tape analogy in mind
because that's literally what it was
okay so that does that make sense
what do you mean by it's consumed that
almost sounds like it's not
it's somehow being erased sorry i'm
using a kind of more modern term so we
we have um data we can think of as
either being consumed or produced
in in this flat model of the world so
i can either be a producer this this
could be like something like a text
or a detector off a satellite
you know it's just something that
creates data and a consumer is something
that reads data
okay and in this case like the notion of
really means moving the file position it
means like it means pulling this thing
this array of bytes array of uh
and moving the file position forward so
it might be physically moving a tape it
might be turning a hard drive to a
particular position where that file is
stored and moving it forward seeking
forward or back
it could be you know it could be a piece
of memory which is acting like a file in
memory mapped
world we don't know what the underlying
medium is and as c
programmers we're supposed to not care
standardio tries to say look what
standard of all these different access
methods like
well look there's a place where you are
you can consume stuff
and you can produce things if you want
to write to it but that's it
right you know like producing or
consuming moves the file position and if
you want to explicitly like go backwards
rewind the tape you have to send in like
a seek command you have to say like okay
go backwards
cool yeah okay at the end of every file
we have a magic marker
and we call that magic marker eof
probably something you didn't see in
python because python just does it for
python very much has this notion of eof
but it
it just kind of magically handles it for
you most of the time
what is eof this is the end of file
and bad things happen when you seek past
so if you try to send in another
consumption request like you say like i
want to do another read
but i've already hit the end of the file
what are you going to read
uh yeah you're breaking the analogy
right yeah
now c has no problem they'll go yeah
sure i'll do that you want me to do
another read fine
here's what's it going to do on the tape
it's just you're going to be reading
someone else's file
i mean like it's just going to be
whatever happens to be stored in the
next set of bytes and hard drives yeah i
mean before
operating systems would sort of protect
against this case which they do now
you could just read other stuff you know
who knows what data you're going to get
if you just keep on reading
so it's like a potential security
problem oh it apps did the old the old
operating systems were all security
problems that's pretty much all they are
um so we need to be careful about this
end of file these days you're just gonna
usually just crash your program like i
said before
if you're lucky it crashes and if you're
unlucky you don't know that you have a
problem and you ship it and you find out
from your users later
so right okay cool that's the file
view of the world so we know that we're
going to be using a seek based and
actually i'm going to
just back up because we're changing
slides we're changing colors
you like green right i do okay so
we've got a seek based this is kind of a
sea green i guess so
um we've got a seek based i o
scheme so in our world um
we're worried about like if we're
writing to the file we're probably doing
output that's by the way this is input
right yep just assuming that everyone
knows that but that's probably not a bad
good assumption
maybe everyone here knows that um so
output we're sort of writing it
somewhere we're producing
in a sense and io and i we're
doing input we're sort of consuming in a
so we can consume a file which doesn't
have that notion like in the real world
like i consumed a snack and it's no
longer available
yeah so i got worried about like so
that that sometimes is true by the way
like in the case where you're
using a seek on say a network stream
you can't really seek on a network
stream so like if somebody's like
writing to you on a network
they're producing data it's showing up
on the network and you can consume it
but as soon as you consume it it's gone
yeah like it's you can't read the
network again right you know
it's like it's there's new data there
now so
that's that's that's part of the reason
we use these terms produce and consume
um okay so how do we do that well
the first thing we need to do is we need
a little data structure which is
with um sort of the
operational burden of dealing with this
and of dealing with a file we call that
the file
structure and i'm not going to get into
structures for the moment but
basically just think of it as kind of a
collection of variables that are related
so we're going to have a file and we're
going to have a pointer because
we learned about pointers before we
don't want to copy all that stuff around
we can just
use it once and that's good um and
we're going to assign that like this is
going to be some sort of like file
now you can name your variables how you
want and see they're typically short and
non-descriptive just to confuse you
that's kind of what we talked about
before that
you know it was hard to write so it
should be hard to read
in that sort of evil world um so
what operations are we going to get to
deal with files well there's a couple
basic ones we have
f open so they all start with f for
file so f open
f close probably
not a big surprise that this opens a
file and this closes it
so um don't try closing a file that's
open don't try opening a file that you
don't have permission to you're going to
get all sorts of errors
and in a lot of bad cases like i said
you know if you're lucky then these
things will sort of return
in some sense that something bad
happened and something bad happening
is typically null so you can usually
test like to see like all right did this
thing open correctly
i would have gotten a pointer otherwise
i'll get null so if it returns
null is mapped by the way to zero so
it's just the number zero
so if the number if your file pointer
which is supposed to have a bunch of
stuff in it
is zero then you know something went
probably so most of them are gonna
follow that convention
okay um now you're already familiar with
it's a way of printing stuff in a
formatted fashion
and it defaults to printing it out on
what's called standard output
now we didn't mention standard out but
that's basically kind of like the first
there's a couple files you get for free
with every unix program
so um that's that's standard output is
what i've redirected to
the web console so that's actually what
you're seeing
there's also a standard error and that's
the reason you didn't get error messages
before because i only had standard
output and i didn't have standard error
so when we would compile something and
get an error it would show up here on
standard error and we wouldn't see it
because it wasn't in the web
ui it is now though because the world is
okay well it turns out there's an f file
equivalent of this so there's an fprintf
okay and it does pretty much the same
thing that printf does
except to a file
so for most of these file functions
they're all going to take a file
pointer as their first parameter so
this is going to be something like that
and then all the normal stuff that
you're used to doing for printf like
you know a percent s and a new line
and you know the string guy or something
you know so like that would work as long
as this is a valid file
now if i write to a file that i don't
have or the file's in a bad state
then you get to keep both pieces
so be careful about errors we're not
going to worry today we're going to be
fast and loose with errors but
you know that's life okay
there's i'm going to show you there's a
whole bunch of this is your main
output function um there's
others like f put s and you know the
this we didn't we never really used put
s that actually is just for
printing we use put care yeah i'm
guessing it's
it's the string version of it string
yeah it's like this is
like for percent s but there's no four
matters when you're dealing with f put s
it's just it only takes strings
so there is an f version of it you know
so pretty much all the functions that
exist in the normal library they have an
f version
that corresponds to them we didn't do
anything with input because there's no
scheme for you to be able to input stuff
on the web yet but
we are going to be writing files today
which means we can also input from them
there is an equivalent get operation
which we are going to be using and
there's fget s
so this is really about
consuming so this is input you know or
so and that's gonna move ahead you know
whatever file handle we pass it
it's gonna it's gonna move ahead the
file position so
keep in mind you are seeking forward
when you start reading
you are seeking forward when you start
writing okay
oh man we just got raided where is
x what's going on where is x hello raid
how are you all doing i'm a weeb
okay is that oh no
my young my youngest brother is a weeb
so that was that was a
an ono of love oh okay okay
familiarity hello everybody um
yeah we're just uh we're doing a little
bit of c we're just wrapping up the
lecture here and then we're going to
coding actually by we i mean jessie
the one with the blue hair will be in
the scene
so she says she hasn't programmed in a
little while so we're gonna make sure
she gets plenty of programming today
yes please okay so fgds is how we're
gonna start reading
it's it's sort of a line to reading
lines um
okay and and hello raiders and thank you
yaya for
catching that um so great
and when we're done with it we're going
to close it and that's cool so this will
be our
output operation is going to be f printf
and our input
operation is going to be fgts and then
we're going to have that once we have it
we've done these things we pulled it off
wherever this file is
then we get it in memory somewhere so
we're good to go once it's in memory we
know all the things that we can do with
it because it's just string
stuff right string stuff
is that is that like the coder's version
of star stuff yeah i think the uh
the correct technical definition and
maybe where is x could comment on that
the correct technical definition is this
is just yeah
string stuff always remember to flush
our cache or it might clog an overflow
yes we're going to get to flushing it a
little bit too
um there is a f flush so we are
we're going to talk about flushing
streams um the the streams that you've
so far namely standard input standard
output they're
kind of managed for you so now you get
to start doing the management
because these are not so automatic okay
so let's cut over to our
learn screen and you all can see us hi
how are you doing we're here we're doing
our things
okay so well alrighty
let's go this is our shared so she's
been following along up here
that what you've all been seeing and
this is our shared coding window so
i'm going to go hands off on this all
now the file stuff is defined in stdio
so you don't have to worry about it's
already there for you
so if we want to now actually there is
one little catch we do
we did briefly look at our um i didn't
get the online man pages set up
so we're going to use uh dye.net
i guess it is pronounced die uh not d
i don't know if a german dude made it it
says c sharp in the title
oh did i put c sharp it says sharp c
like pouncy in the title
no that was i guess it's ambiguous with
like one letter so it's
oh see i guess i am learning c sharp at
the same time
so but that's not this stream
we're doing we're doing the low level
okay so um great
here's your hey what's up strophium how
you doing
hey speak of the devil he's the one
teaching me c sharp so
but in music format nice where is that c
plus plus
no it's c c sharp is a reference to it
is a musical reference too for
the better one because it's sharp
it's above right you know here's c and c
sharp would be above a c
right i'm playing a piece on piano right
now with a lot of key changes
and so that does not give me happy
not in the mood for accidentals you're
not ready for a sharp okay all right
we'll get to accidentally
okay so um great this is how we get
things started so we need this f
open call and there's two parameters you
really have to worry about first which
is this is basically going to be the
path to the file so you specify where
the file is
and this is how you want to open it and
these do correspond to
the open parameters in python so that
you're already
kind of familiar with and hey what's up
lolfbone thanks for dropping by
so this will be something like um
oh but i just realized that's probably
not coming through on your screen so
uh uh no i've got stream up oh okay so
if we do something like
um you know first file okay so we're
just gonna call it
first file and we're not gonna say
anything else and we're going to say
we're opening this thing for writing
which means that we're only allowed to
do write operations on it
so you try to read from it and it'll
if you're lucky okay and because
we're i think we are using the syntax of
declaring on a separate line from where
we're going
so i'm going to refer to this as sort of
my file handle that's just
you could call it file if you want this
is always one of those things with like
variable naming i get screwed up because
it's like is that the file name
or the file itself or the i don't what
is happening
oh i'm this is the variable that i'm
going to use um
to deal with this file so
i'm going to open up this file and it's
a pointer why
uh because that's we looked at the man
page and it said it needs a pointer oh i
missed that i'm sorry
yeah yes okay it returns a point sorry
it's a pointer because it says it gives
you a pointer
all right so we're going to do this
assignment and
then because we're going to be good
people we're immediately going to close
so we're going to write our close
and there's nothing wrong with that code
at all right
maybe i don't know chat help me out yes
very much very much maybe um
so yeah what happens if something goes
wrong when i try to open
this file well
as you have drilled into my very thick
i'm very lucky if we get an error
normal see dark souls land then
dark souls land it will just nice
pretend to work
and i will be none the wiser yeah
okay so what does it return in the event
that this thing fails it's going to
return null
no which is zero so i didn't test to see
if it was zero i just went ahead and
closed it assuming everything was fine
but it might not be fine right say like
i tried to open up a file that didn't
exist like i open it for reading
and i execute this oh look at that nice
little crash
there how's that for a little crash you
know you got a nice segmentation fault
yeah this c doesn't mess around does it
all right just just because i don't want
call this file and
you know because then you won't know if
i mean file the type or file
the thing so i'm just going to call it
do you not need like a um
a file specifier at the end what do you
mean by file specifier like a
file type like you don't have to specify
file types
you talk about windows that's like 30
years later think about any operation no
this this is like
this is from tapes this is
this is from the era of tapes i mean
there wasn't even really file names
really all right
okay fine i'll i'll just just to make
you happy
thank you we'll give it an extension
we're gonna have to free your mind at
some point because you're learning c now
okay so now if we wanted to actually
check this and do it
properly what would we do
so if we could we kind of um so
i don't have the man page open but for f
you don't need the man page it returns
null if there's a problem
yeah yeah if there's a problem so that
we could put a check in there or we
could just have it
and by we we mean
oh boy okay um do i know how to do the
thing all right um so before we close
um let's see here
my i remember how to do
this number
okay i'm just gonna help you real quick
it is a zero but
let's get in the habit right now okay so
we've never done that before
null basically null is set to be zero
there were problems new line
new line yep yep yep i haven't gotten
there yet hold on
hold on i got you gotta make it muscle
oh no no no this is ugly land where we
do this for some
god forsaken reason that makes me sad
but you know what we're gonna do it
okay yeah and that's the reason we don't
want to f-close the thing if it failed
exactly yeah so um that's why you're
protecting it in the else
okay so we run that
i left another boat because you changed
you changed the name i'm a bad guy
i'm just a bad guy let's clear the
and there were problems
yeah that's better than crashing right
you know
okay now let's go add this file
um you want i'm sorry what did you say
so we're gonna we're gonna we're gonna
add this file because right now it was
an error and
you know because there was no file there
so let's make the file
okay all right why don't you write
something into it
but if it doesn't exist i can't write
into it i just changed its
the open line right
what mode did i open it with read
uh no right now did it not update okay
now it's right yeah
before it was read now it's in write
mode okay so we're opening this thing
for the purpose of writing
so we're going to produce data so how do
we produce
onto a file f s f
put s would be one way we're going to
use f print f
let's use let's use the one that we're
more familiar with
okay the first parameter is always the
file handle
first parameter no no you were good
there um yeah just now you have to tell
because you're doing f printf see like
in regular printf
you would just start your format
specifier right yep
and it goes to standard out but in the
case of this now we're actually saying
write it out to a file so you have to
tell it what file
would that work ah one way to find out
computers explode tapes catch on fire
okay we get no output because you didn't
write anything in the positive case
which is good though which is which
could be good or it could
we're actually we're more like
schrodinger's cat right now right like
we're uh
we're in a meta-stable state so we
until i observe it how do we observe it
funny that you mentioned that
how do i what do you mean how do i
observe it like i would think
that like me just kind of going
print something only tells us that
the open command was successful
at least we know it didn't fit it
doesn't tell me yeah it didn't fail
so it doesn't tell me that the print f
print f or whatever command was
how do we know if fprintf was successful
are we going to make nested if loops uh
sounds like a very bad time we we could
but i mean did
how do you think fprintf tells you how
it went
i mean same i guess it print returns
it returns something but you better look
in the man page
because you're not going to guess this
one trust me oh boy
oh yes it's some random integer close
it's not random but it's definitely a
it's definitely an integer you got that
okay the family produce output according
to a format as described
below it returns an integer yeah return
value is always in its own section these
man pages are
designed for quick reading turn value
upon successful return
these functions return the number of
characters printed excluding the null
okay so i'm guessing if an output error
negative values are
of course why not no nothing else
i told you there was no way you were
going to guess this one
standardization is your friend um
i love the old c stuff if i return a
random value that's not zero we win yep
so this was useful when you were kind of
wondering how many bytes actually got
written because of partial writes you
know maybe you
punched part of a card and then
something bad happened right
this is kind of i told this kind of the
era where these functions are created so
um they they do tell you the only time
you're really going to care how many
bytes get written is when you're dealing
with a network
you know where it's very unreliable i
mean but in most of the time nowadays
you'll just kind of test whether or not
it was negative
is kind of a more common thing so why
don't you go and test printf
for us i mean the way that we
so well let's see hold on
okay so fprintf returns what
what's the data type it returns an
integer all right so let's let's start
yeah stuff is good naming is hard
okay here's your nested if
oh are we just oh that's okay you can
print it out that's cool
yeah let's observe lazy all right um
nice nice
huh okay and where did that 11 come from
it is the number of characters that it
fprintf okay and how would we calculate
that to know if it printed the right
um so i would have to set it worked to
yeah that's a good one that's a good
refactor by the way
stir thing that's cool
oh we just got rid of the
yeah let's keep the new line
ah it's a string what did last miles
tell you
never print the string in the format
never print the string in the format
what this is the format specifier
so oh that right
never just print the naked string that
is dangerous
you don't know the size of that thing
don't use that size of
not size of but get away from the size
what's at the end of a c-string
a null byte yes and what's our
function that looks for oh that okay
hold on hold on hold
your horses um horses are held
let's totally eat a horse here
you should just have like a bunch of
random sounds
yep i am
pulling this out of okay
um yeah just reason through it yeah we
want the length of stir thing
we'll throw it into annoying okay
let's see what happened
okay now have your program tested
right now you're printing it out and
then we as humans have to go look at
this output and decide if it worked
how do we get the program to do that
so is there is there is there like an
in there is don't use assert assert is a
that's kind of more for like programming
by the way i don't know where you
learned this style but
yeah with a new line right
do you always have to have an else you'd
always have to close
the braces you open
i know python you're not used to braces
it's okay it happens
all right all right you can put an else
in there
because you wouldn't really know if it
strophium but i dabbed
okay i like it it's descriptive it's
very very technical
that's exactly what happens very
specific i like it
i'm not going to add any semantics i'm
not going to say what went wrong
in general i'm going to say exactly this
line failed i like it
hey all right
it's like i'm an alien no it's it's
totally fine okay i think you should
grab that program because i'm about to
erase a big chunk of it
yeah yeah um also should probably
specify for chat this is not how i write
code for work no i know how to write
this is like
learning c it's okay yeah have fun with
it right
yeah live coding too we get to oh you
already copied right
i copied okay um so
i'm gonna get rid of this stuff um
there were problems that's all fine now
we have a file
okay so how do we read from it
uh like you want me to change this or
you want to keep the
like the so never mind
like that uh that's correct that flipped
the file specifiers now we're
opening this thing to be readable
now we have to read from it if
we're committing find all occurrences
we're deleting the things let's let's
take away that
temptation my god the
variables that exist in some of my code
yes um
i mean we can run it in our current
state right yep
well we want to go ahead
okay doesn't produce any output there's
that produce word again
so if we want to write read it
i'm guessing that's the f get s
that was very hesitant yeah no that's
that's that's it so are we gonna try to
guess what the parameters are like in f
get us
um sure
why not so i'm guessing
that bad thing's about to happen
how long well given the name of it
its purpose is to get a string from from
an f
right it's an f get s yes so so my
intuition would be that we might need to
there's intuitions with the c
standard library this is new
you're learning that newfangled see i
never heard of aren't you
um and then
so i gotta join chad on this one
all right here we go friends can i guess
i don't know
all right now all right let's think
about this so the way that you described
this earlier
is that this is not going to be random
access this is going to be
seeking and i need to be able to tell it
well you said now nowadays
modern operating systems can handle it
and it'll know when to stop
but i feel like you're probably still
going to make me do it the
old sad way um let's try
so it needs the file but i feel like it
needs to know how far to go
as well i think it needs to know how
much where would we
find this out
uh first of all that line you just wrote
in line 11
string thing how big is that string
it's as big as it wants to be no no
no it's not c is
very specific about memory usage in the
stack frame you're only allowed to use
the syntax when you assign it to
oh okay well
there okay i know it's not going to be
bigger than that right so now that we're
treating this thing as a
place to store stuff we're gonna call it
a buff just because it's a buffer
okay buff thing well
well bc style about it at least you know
the opportunity was there i had to be
sad okay well go sass let's all right so
now we know that we have enough storage
but what are we not gonna know
about our file
i mean a lot of things i guess but i
mean as pertains to f get
s like as for getting a string what do
we not know
assuming i didn't just write the file we
don't know how long it's going to be
yeah we have no idea how long that
string is going to be
yeah this is kind of where things start
to get a little tricky but um
so again that's something that python
just sort of automatically like
allocates enough memory for you
and everything just kind of works out
but c no no no
coding butler yeah that doesn't happen
in c so
all right i think this is a good time to
look at the man page
let's not try to guess all of it
actually why am i pulling it up on the
web you can pull it up on the website i
actually have the manual here
oh no i don't have it on the window so
chat can see
yeah now i was going to show the
terminal but i realized i'm not showing
the terminal
okay so f get s
it's all kind of lumped together in this
page um
how many parameters does it take three
and where's the file parameter
at the end yeah that's nice isn't it
that makes
all the other f functions usually have
it up front
but you know what like it's seriously
okay um
extrophium has some wisdom here c stands
for consistent
so so don't guess because there is no
about this look up the functions
size obviously being how many can
like the the size of the string
not the size of the string it's the size
of s
like we don't know how many bytes there
are gonna be on the read
so this is basically telling f get us
this is how much is safe to buffer
like i've got this much buffer space
available so don't give me more than
that okay
so why does it take both a care and a
size then
wouldn't it just because well where is
it going to write the
result i see okay yep and then it needs
to know how much result to write and it
needs to know where it can write it
uh how does and okay
is this one of those format specifier
things where i can't put the form
i have to put like percentage d or
something no no no no no that's
i've left you in python for too long
oh oops there's a little comma
all right what are you cranky about no
your chin declared it in forward
only once each undeclared identifier
yeah what's the undeclared identifier
oh oops that was my bad okay
also a thousand huh um
so i'm going to tell you right now this
doesn't work kind of like your intuition
okay in this
it's not going to copy it it really
means that it wants
a pointer we're going to do more with
pointers a little bit later but
it works like that because the storage
is not really going to be there the
storage for it is really going to be
buffer thing that's why you're passing
that in as a
kind of a pointer so that it can do that
but um
what is the return value really used for
so how is return value different from
kind of buff thing
so the return value is more about
whether or not it was successful yes
that's exactly it yeah versus
actually the data yeah it's not actually
the storage for it right that you're
gonna have to pass in so that it has a
place to write it to
so this is really like you can think of
this more as like the return
and i'll just propagate that change for
you so this is
it's not really something that you want
to directly use unless you're comparing
it unless you're looking specifically
for an error
yeah okay
oh thanks for the subscription loaf bone
i appreciate it
you are contributing to the fund of
whiskey that i buy for this show
i still don't get the pointer there i'm
sorry okay you mean
which which point or the one that's on
line 12 yes
okay man page what is the return value
what why wouldn't i make this so first
of all
i forgot that's the return value it's
going to be an end
we know that wait is it yeah that's what
it said didn't it
uh take a look at f get s
oh i was looking after get c yeah um
s okay it does return it yep and it
tells you right there in the return
returns s on success and no
on error yeah or when end of fight and
that's kind of the reason why that's the
answer to your question like why does it
have to be a pointer because it doesn't
want to change
the data you're passing it doesn't want
to throw away the pointer you've got
so basically in line
11 you're declaring a buff thing which
is a thousand bytes big
and actually i should say it's a
thousand whatever the size care is but
a bite so um
okay well if if we go and we change that
to something else
we lose kind of our reference to buff
like if i take buff thing and i say buff
thing is now
zero like buff thing is null
then i've lost where that is in memory
right buff thing is really like kind of
like the base of this
thousand bytes but if i'm if i move buff
then i don't know where buff thing
starts anymore right
so they can't do that to you
right in fcat s you would have to like
always save whatever you're about to
pass in to see if they change it or not
so that's kind of crazy so instead they
we're going to return something that
tells you if there's an error or not
how does it know if it's an error it'll
return what
s or sorry null yeah it returns null if
there's an error
and then they say if it's not an error
so if it's not null then what's it going
to return
well it could return a 1 it could return
a 15. it could return whatever the hell
it felt like returning in this case
they decided to make it line up with the
positive case of where s
is so but that's not really like that
doesn't matter so much it's really about
the fact that like it
it's the negative case that causes them
to do this like if they
if they return if they tried to set buff
thing to null on you
you'd be in trouble
they need a way to return the error so
if it's successful yep
then ret val is going to match buff
thing they're both going to point to the
same part of memory all right
but but why does rhett val
have to be a pointer
and buff thing is not because f get s
doesn't know how big
retval is right retval would be defined
so but going back to our stack frame
view of the world like
in the stack frame where you're calling
this thing
retval has a size in the case of a
pointer it's just whatever the size of a
memory address is
but in the case of buff thing it's
pointed to
memory which has a thousand bytes
right right the difference between buff
thing and red foul red vowel is just
pointing to some piece of memory but it
doesn't allocate any memory kind of on
its own other than
enough roots we know that if it's
successful it will need to be the same
size why would we not just set it to be
that size
well now you're throwing away 2 000
for no reason
i mean why would you allocate twice when
all you're trying to do is return
whether or not why isn't everything
pointers a lot of the stuff in the
standard library is pointers that's
exactly the case
oh all right
i mean i just i mean if you want to
write your own version of fgets that
you know takes that because now you're
going to also have to pass along the
size of that thing and then
i mean are you going to write like how
are you going to pass the error back now
i mean
you could have just made it like return
int in which case you know it would be
like you know now you'd have a little
more space say like all right if it's a
five it's this kind of error if it's a
seven it's that kind of error you know
you could do that kind of convention but
they didn't
they chose to return you know something
which kind of maps the thing
or or it maps to null but they don't
want to allocate any more memory really
whatever it takes for a pointer so that
that's that's kind of the reasoning
otherwise you'd have to double whatever
your buffer size is all right well
enough talk let's see it
okay now i set it to null so we set
up sorry about that
yay it worked
okay so it just read that out of a file
yep you persisted that that's data at
rest if i run your program again
there's no it worked in here but i
execute it
magic right except i got an extra new
because when we wrote it in there was a
new line and then also when i printed it
there's a new line you got it
and that's gonna catch you a lot trust
it catches me all the time
okay great so now we know how to write
to a file we know how to read from a
what if we wanted to write a number to a
file how would we do that
um f
put i there's no f put i i
put no you already know a perfectly good
way to write to a file what
what would you use normally to print a
printf yeah what's our file equivalent
okay yeah fprintf yep we know how to
write numbers
yeah go ahead save this real quick
before i mess too much
we need that checkpoint function yeah
okay so
i'm going to put that down as a soft
why not pass another buffer
let's see what else we get
okay so we're back to writing
i don't know i guess that we made a
pointer last time but
i need that again
i didn't need a pointer before yeah i
don't print f doesn't take a pointer
it doesn't return a pointer i should say
gone to the new lines huh
so that's kind of important on file i o
f get s is typically scans until it hits
a new line
assuming it's smaller than whatever your
buffer size is
final jeopardy music nathaniel i
actually i have some i have some
music i'll go queue up i think you're
going to solve this one in time that
i'm not going to get the music in there
that's right coffee with the crew always
tells me it's like yeah it's a good spot
for you to play the music
i wrote
i'll give you a sad song
how's this nathaniel i can't hear it
all right um
yeah sizeof already makes me upset oh
come on
what is the point of that existing if
i'm not supposed to use it it's just for
it's really just for types ah oopsies
well let me think about this
why don't you print it out first so that
we see it let's develop an intuition on
print what out uh retvel
yeah before we test it let's see what it
would be
uh this is gonna be
well what type is ret val yep
i'm going to label this for you
why do you think it was two because
that's not the size of
an integer no
so last time it was about the length of
the string
right and so it's going to be the
and a null byte
what is the number that gets printed out
what do you mean what is the number that
gets printed out what are you actually
writing into that file hopefully five
okay five
binary five like the value five or five
the ascii interpretation of five
five the value five which is why i
specified to it that it's expecting a
okay so when you did f print f it turned
it into ascii values
right that's the the percent d specifier
turned it into a printable character
so if i do like 50 and i
run your routine again
then it returns three this time
so in an ascii sense how many letters
does it take to print out the number
50 how many symbols
to print out i'm not sure i'm following
this 50 i print it out right
okay how many
letters is that made up of how many
character positions is that made up
two plus and all bytes of three
new line in this case but yes yeah like
they did
yes yes yeah that's
that's the three okay yeah so it's
returning the length
it's not the size of an integer right so
in this case
i see what you're saying yeah the
integer itself on our platform is going
to be
32 bits so four bytes that makes sense
all right actually it'll be 64. we don't
really have like a
we would have to kind of use
string length but convert it to a string
yeah and because we'll do this to do the
tests that we did before basically
yeah it's a little trickier yeah because
we'd have to like
print it into a string and then see how
long that is and then make sure that
those two match
well that's handy because there's
another version of print def i want to
show you
what do you think this does
sprint um
i'm going to stop the music here
so while f printf was about printing to
a file
yes and f get s
was about reading what from a file
a string yep so s printf
is printing to a string yeah okay
yeah that's exactly what it's going to
do so if i want to know
how many letters it takes up to print
out this number
i could just print it to a string and
then calculate that right
yeah i mean so like it doesn't matter if
it's like 50
000 or 50 or whatever like
if i print that into a string it'll null
terminate it and then i can
count the number of characters until the
null byte or i could use str len to do
okay so go ahead do that how do i tell
how long number is
um how do i don't know how this one
oh s printf is almost identical to
fprintf the difference is that the first
parameter is the string you want to
print it to
so i'm guessing though that i have to
now create another
integer that is the return value for s
printf right don't worry about the
return value for the moment because we
don't check the return value on printf
anyway so we're gonna let's assume it
worked for the moment
okay um and you said i'm sorry the first
one is
the string you want to print it to so
before in fprintf it's the file you want
to print it to
but in s printf it's the string you want
to print it to so i'm going to give you
a string
which will be big enough
okay what's the next thing to print f
the what you want it to print oh no the
the specifier okay yep
there's the number cool let's assume
that that worked so we'll assume that s
print f returned properly so now this
the text of the number is stored in
another buff right
so now um
so how long is another buff
well i'm trying to find that out
right so that's
okay let's let's not confuse ourselves
because now we got multiple buffers
oh i think i i'm gonna let's reload real
refresh yeah refresh
i okay we got ourselves into trouble
there so let me just clean that up
you are writing this right
i mean we don't have a buff right now
yeah but we
we might bring it back in a moment when
we start working with the file
oh that makes sense we changed it i'm
sorry i'm sitting here going how did we
get from three to six but i forgot that
you changed it to 50 000.
so that makes sense yeah i mean that
six-ish plus it has a new line right
five-ish and a new line
okay so you feel pretty good printf
fprintf a little sneak in there of s
print f
yeah f get s
all right now it's time for the final oh
okay so you want to copy this or should
oh yeah
you're good okay so great
and uh just to nathaniel's comment uh
we're not ready to get into like trying
to develop an intuition about the
io library for right now so i don't want
to spend too much time getting into
the memory but there's there's some
dangerous memory stuff that we're sort
hand waving at that's okay i think
let's build up our intuition with the
basics first
and then we'll get i'll get a little
more critical about your notion of stack
frame and all that other stuff
okay so i've just reduced this to
opening and closing um
and then wait strophium ass is
like the scene from doctor strange if i
told you more than you already know he'd
rank this place in terry yeah i tried to
warn her strophium up front about sea
but anyway
so we'll get to that um okay so
we have this file and it's opening we
put it into the file handle
and we check to see if that worked and
then we can go back and we can f close
it so right now we're kind of in our
like identity type
we open and we close okay we're going to
go back to reading
except now we're going to go read a file
that i already prepared for you
so what is this file we could we could
have you
start writing things out or we could let
you discover this for yourself
great read a line from this file and
print it out
try not to destroy the file but i have a
copy of it here just in case
so watch your file modes
all right
i'm gonna make a note from nathaniel
pitfalls of s printf
you're absolutely right though by the
way nathaniel i mean it is definitely a
very dangerous tool
i probably shouldn't have showed you s
print def yet
there were problems
okay uh oh i'm sorry i named the
that's not what i named the file but
look your error code detected that isn't
that great
all right it's called asn.tsv my bad
okay no worries okay there's level three
okay this is some data we're gonna play
with that you're a data scientist so
here's a little public data this is a
pack i pulled from friday's session uh
teleporting anywhere in the world
because that's fun
we like doing that um and so these are
asn this is kind of
part of how the internet works so if you
pulled in
two lines and printed them out how would
you just quickly
start looping through this i'm going to
tell you that there's
like tons of lines in this file so
let's print out like you know the first
three of them
now we could just keep copying your f
get s and your
print right yeah
um so i'm thinking back to
what you said at the very start about
when you start you start
reading it it's going to kind of be
and so i think that we need to leave the
open so that iterative process is kind
of triggered
not like opening closing opening closing
and like yeah we want to keep the state
of where we are in the file but then
all right so i think
let me think this through hold on
well actually let me start with a
simpler question right now you're
reading one line from the file and
you're printing it out right
how would we read the next line from the
i mean you would just do it again okay
so let's do that
but but but i i could do the loop no i
was just thinking i just wanna
we don't know we don't need to think
let's let's let's actually see how the
file position moves
okay so then i mean you would just
uh i don't mind if you copy pasta it's
i mean we have to change all of this
don't redeclare the variables
i mean but
it doesn't
don't we do get this right we can't
overwrite why not memories right once
so we're assuming it's the same size
well we don't know what the size is
anyway we're specifying how big
buff is right
the only thing we've specified is how
big buff is it's a thousand bytes
so and then you're saying read a
thousand bytes from your file
and then read the next thousand bytes
from the file
right okay let's and look it works
cool so we're okay you're overwriting it
because that's just memory that we're
going to kind of keep reusing and it's
going to move that null byte
as as it sort of pertains so if i
printed out the length of the first line
and i printed out the length the second
they'd be different right now by the way
i'm just going to warn you about this
it's tab separated so these aren't
spaces in between like the two and the
the tabs they're tabs um okay you can't
easily see that on the output i should
make a note
but um okay so
tsv kind of told me that yeah okay cool
um so great now
let's tuck that into a loop we're okay
overwriting it
so let's print out the first five
jeopardy music
hey what's up nightshade dude sorry i
didn't see you there earlier
and this is the wow
oh that's too exciting
that's also too exciting
okay this is the right right level of
by the way nightshade dude it didn't
happen the afternoon i have a feeling
it's not going to happen tonight but
we're going to stay
just at 199 followers
just can't take over okay
nice all right so if we wanted to change
this to the first
hundred piece of cake now right yep
is that what you want me to do no that's
all right i'll do it
all right so this is cool
um what is the data that's in here this
these are asn's so i know to a data
scientist this probably doesn't matter
it's like it's just data
this this will tell you i'm going to
tell you the record format right now
it's three fields
so the first one is the autonomous
system number that's just
like an identifier that's registered to
the company that's specified in field
which is this level three parent llc and
the first one
and the third field is an iso 3166
two-letter country code okay yep i've
actually used those country codes
um in a separate data project so nice
i try to use them whenever i can
okay so great these will tell us
things like asn's now what
we're gonna go actually you know do
something with this data so
why don't we because you know this isn't
python and we don't get things like
to just easily chop them up
how do we start chopping up one of these
lines so let's go back to your
case of a single read all right so if i
clear the output and i execute i just
have a single line now i told you before
tab separated so the tab character do
you remember the escape sequence forward
c no all right it's backslash t
so okay um no biggie so
we go and we get the thing in line 15
you're storing it in buff thing okay you
have a pointer that refers to it in
retval so
that data is in buff thing
so if i start if i want to write a
function that assumes that this format
is consistent
how can i get it to chop those three
parts up
so i want to do a little parsing well so
essentially we're going to be
what you would want to do is you would
want to kind of take a similar approach
to how
we wrote the string length function
previously but instead of trying to
you know number of characters and wait
a null byte in this case you're going to
splitting on uh the the tab
right well except you're going to be
splitting on the tab so go ahead let's
do a function okay
let's pass let's get this out of main so
let's define a new function
okay your intuition sounds great by the
forgot to say so let me think this
i want to think about this for a second
yeah i was going to say don't overthink
it's too hard and see it's probably
easier to just kind of get
like what yeah start with like the
function signature
file chopper nice except let's let's
call it line chopper
because we're gonna we're gonna feed it
a line at a time
so let's think about this it needs to be
a string should be a pointer i feel like
maybe it should be yeah
yeah okay um well let's not call it a
string we
we have a better word for it now yeah
it's a line
um doesn't need anything else
no i don't think it does nope just needs
a line all right i like to start with
just the
signature like that because that's
enough thinking for that
part we want a function that takes a
line and chops it that's a great name
it's a line chopper this by the way the
technical term is a scanner
but it choppers i like chopper choppa we
could do it with an arnold accent
so line chopper just takes a line and it
chops it up now in our case we're not
going to return it
so let's return nothing
we just want to put the parts out piece
by piece
so we could store them if you want
that's kind of up to you but
um okay so
how do we get this all right so we know
that we have line we know that it's
going to be pointed
at the start of our line
so now thinking it out what do we kind
of want to accomplish right we want to
do something align right
we want to do some wait what sorry we
want to do something to the line
variable right
so yes yes what do we what do we want to
accomplish like what do we want our
function to do
so we want it to start
reading in the characters of the string
that is the line
well they're already read off the file
they're in line right okay but you're
okay you're reading the characters of
line gotcha yes and then
how many characters are there when you
hit the tab
okay and i mean we're not gonna know how
many characters it is that's the problem
yep yep we'd have to pass that along
sort of like how f get s
did it but let's let's not do that so
let's just assume that it's valid and it
ends what's at the end of our line
a new line okay there's a new line and
then at the end of every string
right after the new line the null byte
okay so
let's let's use the new line like you
said let's assume that all the
file is properly new line terminated
that's a big one right there but um
that's a doozy i'll tell you right now
so let's assume that it's new line
so and it's properly formatted so how
many tabs do you have in the line
two good so
what do we need to do
let's start with the first one so
everything up to the first tab is what
um the asn yep
okay so we're gonna have
hey what's up sonny how you doing
and for simplicity let's just assume
that all of your buffers are a thousand
so let's call them all a thousand i
don't want to get into dynamics stuff
and then there's like the company or
whatever yep it's name
it's friendly name is the official thing
but name is good
okay and then there's the country
now this one we do know the length oh
yeah so it's just going to be two but
then go a thousand because i don't want
you to get into overflows yet
okay all right so our goal of line
chopper is to get into these three
things and then we're going to print
them out let's print them out in reverse
order to know that we
properly parse this thing so we'll print
the country code first
the name middle and then the asn last
so transposing them will tell us that we
parsed it right
so yeah me too
mondays um parsing
so i just think they're gonna go scotch
after this
maybe i should open mine now no no i
don't want you to rush
you're getting the hang of these
three-part for loops huh
um okay so let me think about this when
we did this before
we made kind of the the no i think the
terminal condition can be the same i'm
i'm fine i'm talking to myself i'm sorry
okay that's okay so we need this to be
wait do we want to go until the new line
or what did you just say before
so i i have a i have a
hey talk it out talk it out so i was
thinking about
go if you go until the
tab the entire loop is going to stop
when it hits
that's okay why don't we just break it
into separate loops
so we'll do one loop for each of these
but that's
that's i guess what i'm i'm getting hung
up on
is that
i i could see you like returning the eye
or something where
the tab character was and then starting
the next loop
where that one left off but i feel like
the issue
okay here i i feel like that sounds good
i feel like there's got to be a more
efficient way to do it this time oh
don't worry about efficient we're not
worried about efficiency
we could still just pass through this in
one scan
doing it your way so from an efficiency
perspective not concerned at all
i guess it just seems like it seems
really messy to have just all of these
loops it's c together be messy
okay okay let me let me help you with
one thing though we do
to your point we don't return i from the
all we do is we just define i to be not
in that scope
right so we don't need to actually
define it there
um and so
now sunny don't don't be naughty
sonny's got her issues with uh some
python duff she worked with
and try to put python on gpus and you
care pretty fast what's efficient
all right um all right
let's think so we want to
actually i don't know if we've ever
talked about this no no no we have
had you can can you do like um slicing
string slicing you can but let's
why do you want to because okay so so
here's what i'm thinking is that
we ideally want at some point we're
gonna have to store
like asn name and country why don't we
restore as we go along
yeah that's fine and we can totally do
that but we still have to be able to say
everything up till this point from the
until this point gets stored
do you see what i'm saying don't follow
that everything up until this point is
so here let me let me
so for here for example we would go
it's going to iterate we don't really
need it to do
unless i guess trying to think this
through well
line i gives us the current character
right that would
it would work for this loop but it
wouldn't work for the first one
just can you store in asn
can you like index and go like asn 0
equals this asm
yeah totally in this case
but it's not going to work for the rest
of them yep but that's okay
one at a time that's why i gave you a
parsing problem
so start at zero it's going to
store each one in there until it hits
the tab and stop
and then we have our new value of i okay
and so i think i'll be left off at the
right place which is kind of your
earlier algorithm
yes and so then let's let's not jump too
far at once
let's let's look at what we did let's
let's print out what we've done so far
now you're manually constructing this
string keep in mind
and there's a catch with what you're
what goes at the end of every string
the null character yeah are you copying
a null character
i mean the terminal character for line
sub i is gonna be a tab
so if it's treating the entire line as
if it's training the whole line
as a single string then no we won't be
copying and null so that's your job
right i have to add one yeah exactly asn
is not going to be null terminated
not not not not every time oh at the
very end
yeah you only have to add one null byte
um oh it's just zero yeah
it's backslash zero let's backs
backslash zero there yeah
now the only thing that i wanna kind of
poke at is why is it plus one because
i should have left itself
how do you feel about that right because
increase at the start of the loop that
makes sense okay yep
so let's try this out now did we call
our function i don't remember no we have
okay so let's try calling it okay
um and then
so i can
feed it buff thing
i guess okay
we're not really testing ret val here
okay so
that'll call it
and the print is part of it so okay
let's see it
yeah sounds pretty good when it was
supposed to be so what if we fed it five
okay also good yep also still looking
good so
turns out this is not what we wanted
with this
plus one here
what do you mean so you're
null terminating i already advanced by
yeah and that's what i missed is that i
forgot that the eye advances at the
and then it does the check right so
that's kind of where that matters with
yeah okay good all right so that's good
let's grab the next part and i'm just
going to get rid of your
extra line here so that we can fit stuff
on the screen
so then
feel like
oh we could just use i right we don't we
don't need to so
so this is for the indexing later or no
wait we
found why why do i want that i'm feeling
like i want that
you don't need no your intuition's on to
i do yeah um
okay how about we create j
okay but what are we going to use j for
hold on so
jay is going to index the next
character the next character
the next um so it's going to index name
for us oh yes it's going to be our name
index yes all this weird stuff in this
space and i don't want to do that
i mean so in that case i could have just
i do i have to say no i don't i can just
say that cry
no i we need i to be plus one here we do
because no because
wait you got to finish the sentence i'm
so i
in the previous loop increased by one
and then it stopped because the
line indexed at that eye was a tab
uh-huh and we want to keep the same
logic right
right so let's keep the same logic no no
what i'm saying is that
here we need we cannot start with the i
value that we were left over with at the
end because it's
because if you index line at that i it's
going to be a tab
so it won't run anything so we have to
store did it add one on the last part of
the loop
so no no but that's that's what i'm
saying is it it doesn't add one at the
end it adds ones at the at the start of
the loop
and so i'm not 100 sure about that
well that's why why don't we start with
the naive version
let's hold on let me i want to reason
through this so okay the
the reason that why we were able to in
this in line 13
index asn by eye and put something there
is because that's where the tab was okay
and we're replacing it
with a null byte okay meaning that i
is the current index of the tab okay or
in our line
and so if we start with i being that tab
then we'll see a tab at the start of
this output right exactly
okay let's see if we see that tab so
let's test your theory
or wait no war like i like your
explanation let's see if if it matches
okay we don't have to guess
can i just do the plus plus again sure
okay does that happen
like that yeah that plus plus is just
equal j is equal to j
plus one it's just shorthand okay all
right um
in assembly it's actually an op code but
it doesn't matter there's optimizing
compilers these days
nathaniel's mentioning one of the most
heavyweight of them silang or clang
which is from the llvm package
so i am going to change this to
one again
okay so we don't i want to start
labeling these lines because we don't
really know
what's happening in the output right now
so i'm just going to preface them just
so we know that there's at least
something there that's supposed to be
okay so we execute and we're getting
nothing for name
i think that's because it's starting
with the tab i
i like your theory now the reason why i
like to do this this way first
is because we start with a failing case
and then we make it pass
okay so that makes sense i believed your
theory in fact i was pretty sure you
were right
but the thing is the other way we won't
you know like like it's it's harder to
like have a positive case that works and
then wonder if it really failed and we
just didn't see it
as opposed to seeing the failure and
then knowing that that's wrong and now
we're gonna make it past which is kind
of the more the test driven development
way to go
so there is a reason there is a method
to the madness so yeah let's set i to
what do we want to do to i i mean your
theory looks good
it's just we don't want it to iterate
but i think we can just do that yeah
yeah just kick it one at the start it's
not gonna do it every time there but
hey look at that you got two fields
you got one left yep
okay so now
let me look at nathaniel's comment while
you're writing that clang format just
uses claim front end to make
i think yeah
nathaniel it's i just really haven't
gotten to it there's more that i want to
tell you about this editor
um but i kind of like where you're going
oops she's typing off screen on my
wait why are we using a new variable
i guess j doesn't no j changes because
that's what we were indexing
with so we need a new indexer that's
also zero
why do we need a new indexer because
j changed i could reset it to zero yeah
i just figured
be do we need to make them separate yeah
i mean we don't
really need reusing j would be okay
right because we're using
j really as an indexer into the
destination and we're using k as an
or well sorry an i is an indexer into
the source
but k would have worked fine i mean it's
just burning another
memory location we're in c so we're
sensitive now about memory
and let's test it with
nathaniel i'm adding this as a
discussion topic
all right
so how do we know that there's no tabs
that we accidentally picked up
at the ends of these strings
tabs that we accidentally picked up a
is non-printable so if there was a tab
at the end of us
it would not show up we wouldn't know if
it was there or not right
well because every time that we were
assigning characters
it was within a loop whose like sort of
terminal condition
was ah so the faith for it to be
well no it's it's logic that
that this is how programmers get trapped
and see all the time
how would you verify how would you
c is very logical it's just the logic
isn't always the logic you think it is
i mean apart from setting even more
loops and iterating back through each of
the variables
how about a much simpler way i'm not
sure how why don't we
just mark the start and the end of these
what do you mean you see we're not sure
well i'm just marking these are just
plain characters that are gonna print
but they're gonna show up at the start
and the end of the string oh i see what
you're saying
okay so i can very quickly and easily
if there's an invisible character there
or not because like if there's a spacing
thing it's gonna
push my marker out right
yes this is the cheap way of not doing
what you said like
what you're saying is like kind of the
right way to verify you know but it's
like it's like why write another program
to verify this when we could just
mark our things so if we go we look at
the output
oh look at that there was an invisible
oh okay so i think um
what happened there by the way this is a
very cheap technique you'll see me use
this all the time but it's
just because doing what you said is is
correct but it's hard right you know
it's like you
have to write another loop and it's you
know is that one right
you get into the scope problem like how
do you build a multimeter when you don't
have a good multimeter to check in and
let me think
huh where is that extra one coming from
because i
i would think that it's not it can't be
i even warned you earlier that i do this
all the time
this this is why we do not try to go the
logic route we just
find a way to naively verify what the
computer's doing
all right so let's look at the output
what is it doing
what do you mean what is it doing i mean
what are we actually seeing
we're seeing that the first two
variables are fine but there's a tab at
the end of the third
is there a tab or a new line
or is there a new line
and so hold on because if we reached
let me think this through for the last
one for the last
loop yeah it it's not going to end in a
tab it doesn't end in a tag
yeah and so we need to change that yeah
that makes sense
so it's not about logic logic yeah the
computer's logical
but it's a little too logical
okay so we are terminating right right
yeah so it is ending when it's supposed
to it's ending where it's supposed to
now before we were kind of getting lucky
okay so but
it's still dropping that new line yeah
in the country variable because
because reasons i'm just thinking about
um yeah thinking's hard
so and this is
by the way our last part of the coding
so while you're thinking about it i'm
just going to start pouring
so it should be for you to listen to
when it hits
the new line it shouldn't be adding a
new like a new line
in because when it realizes this is
so i'm adding it somewhere in here
that's what i don't seem to get
so where does the new line come from
you're not adding it yourself
right no okay so
so how could it have gotten in there
i mean if you didn't add it you didn't
write a line that added it i mean it
could be in the file
it has to be in the file yeah there's
nowhere else for it to come from
so we're copying in that new line
we have to be copying it in right but
that doesn't
i agree with you i mean that's logic is
telling us
that it has to be but we literally have
like a
a terminal yeah yeah
and so it's a bummer isn't it
i mean i can kind of be hacky about it i
don't want to
get hacky you know the thing about being
hacky first is
let's prove what's happening right
because this something's happening here
that we don't expect
yeah that we don't want really so
how do we prove that yeah that's a good
way to prove it
let's see
all right so a hundred percent
we're getting that new line in there
i mean we're not getting it anymore
how do we know that we weren't getting
it earlier
how did we know we weren't getting it
earlier what we were
so what about name and asn
so it looks like we're off by one on
our third loop right
yeah somehow so
so it's still to me
i'm i'm struggling with this idea that's
somehow in the loop
ah are you struggling with it or is the
computer struggling with it
i don't know i mean we have a hard fact
in front of us
yeah it is i'm trying to understand how
it could be added in with
how we've specified the conditions of
the loop okay
what if we try your same hack but we
apply it to the other variables
i that's not a good idea let's do it
but they work why would we are you sure
so you mean
that yeah okay
okay now we have proof
yeah like the first ones are fine right
that was the problem with doing the
logic reasoning is that
we don't know what it's happening it's
clearly not doing what we expect it to
right so maybe there were two new lines
in our file or something
that still wouldn't make sense though
why because it would
when it hit the first new line it would
stop all right well
then you tell me what would be our next
no i don't either i mean let's let's
take it apart you're you're concerned
about it which is good
we're gonna we're gonna sort this out
we're gonna get to the bottom of this so
i'm gonna execute this thing we're just
gonna go with one
wait it's not it's not i think that we
possibly made an error i i mean i know
the computer didn't
no but i think we it's our problem is
assuming that it's a new line
ah i don't think it is because
how could we know
oh wait i mean because you're theorizing
but i mean we gotta we gotta know this
isn't theory
if we
put this here i'm sorry i missed that
um so i'm i'm setting i'm not gonna
overwrite whatever that
is but we know it's indexed at j minus
so i'm putting the null byte at j again
this will give us that whatever that is
we do know that it takes up
one character um
and then
let's new line your comment
so it's not a new line uh so something
else is
there is there like a ah
i warned you earlier
i warned you earlier line endings
yeah so we yeah you said we will assume
for now that it ends in a new line yeah
maybe we shouldn't have assumed that
clearly something else um oh i have an
hold on one second
so now that i have this
i'm a bad guy i shouldn't have done that
let me think this through hold on
i want to
i want to force it to give me the
yeah ascii of it right
good forcing and so
aha what is that what is that
how do we even know i'm gonna look it up
yeah let's look
in the ascii table a carriage return
okay so how
do you refer to that carriage return the
escape sequence well first of all you
could just refer to it as 13.
i mean you now know how to coerce it
into its ascii value
but fair enough there is another way
that we could do it we could say
so you want to add this to line 25 as
your terminal condition
yes okay so line is line i
is not equal to new line
and line i
is not equal to
you with this tight compact
carriage return okay
and so i'm going to for now i'm just
going to comment these out
okay so let's see oh wait you have the
no i i left it so it should be
broken it should be giving us that space
and it's not it's
i fixed it there we go