 Alrighty, welcome back to 105. So, learned about string's last lecture? Guess what? In this lecture, we get to use strings even more. So, there are luckily a bunch of string functions for us in the standard library, which we will go over today. So, you don't have to do anything special, except for just doing an include string.h at the top of your file with the rest of your includes for the standard lib, standard IO and all of that. So, throughout this thing, just remember that strings are arrays of characters that end with a null byte and they could be allocated anywhere on the heap on the stack, doesn't really matter. So, keep that in mind because some of these functions are tricky to use correctly because, well, in order to store a string, well, we need like the length of the string. So, how many characters actually comprise of the actual string? Plus, we need one additional byte to hold that null character in order to actually successfully hold a C string. So, sometimes remembering that we need another byte for the null byte causes a lot of issues and then sometimes the character pointer might point towards an array of characters that is not null terminated, so someone forgot and that causes all sorts of issues that we kind of touched on last lecture. So, previously we wrote a function called string length to get the length of a string. Turns out we didn't actually need to write that. So, we didn't have to write it ourselves. There is a function called stir lane. So, it's string length. Again, they just shortened it because I guess making things like saving, typing some characters was very, very important. So, they named it str short for string and then len short for length. So, this function takes a single argument. So, a pointer to essentially an array of characters and then they put a const there because this function will not modify any of the values. So, it can be a const char because it will not modify them and then it returns a size underscore t. Again, that's basically like an integer. For the purposes of this course, we could just explicitly cast that size t to an int and everything should work just fine. So, it just returns the length of the string for you and the rules are that S has to be a null terminated string. So, throughout the slasher and throughout people talking about C code, you might hear people saying, hey, this is a null terminated string or this is a C string. Those two things mean exactly the same thing. So, if I say C string, even if you hear that in other programming languages, it means that it is an array of characters and you know when to stop actually looking at characters in that array whenever you hit a null byte. So, they mean the exact same thing. I will probably also use them interchangeably during the slasher. So, as a quick little example, let's go to this. So, if I have the string hello world and then I call string length on it, I should get back the length of the string. I can convert it to an integer. Everything should be okay and store it in a variable called slain. So, now if I print off whatever this value is without even running this code, can anyone tell me what the length of the string hello space world is? Again, this goes against my goes against my counting of like I can't count past seven so I'll need some help with this. So, how many characters are actually in hello world? Yeah, 11, right? Everyone agree with 11? So, we've got H-E-L-L-O and then a space that counts as a character. So, that is up to six and then for the rest of it, seven, eight, nine, 10, 11. So, there are 11 characters in the string and to store it in memory, well it needs 12 bytes, right? Because I need that null character at the end of it to actually let's see, know that I'm done with the string. So, if I go ahead and I run it, 11, I have 11 characters. So, any questions about that? Just a function we can go ahead and use. Perfect. So, there might be the case where you're not sure if that string is null terminated and if that string is null terminated while that function string length, we implemented it before, it just keeps on going until it eventually finds a null byte and maybe it would access invalid memory or something like that. So, there is another version of string length that actually has a limit. So, there is stir, again, why do they shorten it? I don't know. Basically, it's the same thing but it has a limit and they just call the limit n. So, this takes two arguments. So, the string to get the length for and then another size here for max length. So, the rule with this one is, it will only access the values in that S array from like index zero all the way up to max length minus one. So, it would access at most max length bytes even if there's no null bytes. So, it will stop if it makes it to the end of max length. This reads the last character and then it will just return that value. So, it will turn max length as the length of the string even if it's longer than that, this function sets a limit on it. So, the maximum value that this function would return is max length, again, even if the underlying string is larger. So, do, do, do. So, now, if we do that, while maybe the string like the string pointer or this char pointer, we get back from a user, maybe we're not sure it's null terminated, maybe we're not sure where it came from or something like that, but we know that at least five bytes of it is valid. Well, we might try stir n length with the string and give it the max length of five. So, in that case, it would only access the bytes H-E-L-L-O and then stop. So, in this case, if I do, if I give it the max length of the five, this string is actually longer. So, if I run this, it should just return simply five. So, just ran out of space. But the nice thing about this is if I know how many bytes are like storing or how many valid bytes of memory this pointer points to, well, I can set that at the max length and then I'm sure that I won't get a segfault or anything like that. I might get a maximum that is not accurate, but I'm sure to not corrupt memory or anything like that, which is probably actually more important. So, this function is something we would want to use if we do not trust the user. And, yeah, a good suggestion of like, well, I won't really know the max length here. Like, I don't know how long the string could possibly be, but the idea here is you might not know how long the string will be, but you know how much memory you set aside for it. So, just in case they did not null terminate it, you don't want just some random data you want to actually make sure it stops before it just starts reading anything. So, if your shirt's null terminated, you can just use stir length, but if you're unsure for any reason, you should probably use this function and set a limit. So, in case it is not null terminated, you won't run into issues. All right. So, next function is there is a function to copy a string. So, remember if we just like a get a pointer, like if we just do char star s, so a pointer to a bunch of characters that we assume is an array, and we do this, well it's pointing to memory that is read only, so we are not allowed to modify it. So, if we wanted to modify it well, and we didn't want to store it on the stack, we could go ahead malloc some memory, and then we could copy the contents of that string to the region of memory we malloc'd, and then we can go ahead and we can modify it. So, that is what the string copy does. So, takes two arguments, so source is the pointer to the string to copy, you might notice here it has a const, so that means it will not modify that string, so it is safe to use even if it is read only, and then the pointer to this char should also be an array called destination, so that is where I'm copying the values of the string to, and it needs to actually represent valid memory, so I would have to in this case, to store hello world, that is 11 characters plus I need a null byte, so what I could do is I could just malloc 12 bytes, and then the pointer I got back from malloc, I can use it as the destination pointer, and then use this hello world as a source, and it will go ahead copy all those values including the null byte into my array, and then I can use that now as a string. So, source is the C string to copy values from, test is the location in memory to copy the values to, and you are responsible for making sure that you have malloced at least string length, whatever the source string is, sorry this should be source not just S, so the length of the source string plus one because you need that null character, so you need to make sure you set enough memory aside because whatever you copy will be null terminated, so let's look at that example. So, here, oh I made a common mistake here, so what I did is I have the string hello world, so this takes up 12 bytes in total because it is again 11 characters plus the null byte, so if I made a mistake I could malloc space for only five characters, and then I could do the string copy, so I'm using memory I shouldn't be, but it turns out if I run it, well I'm not sure what will happen, but I'm feeling lucky and this will probably work by accident, so here I get the same string both times because while string copy doesn't know the size, like how many valid bytes D points to, so it just randomly copies or just copies everything and goes off the bounds of the array and just starts using some invalid memory, so we could have seg faulted, but in this case we didn't, if we use our good old friend valgrind, we'll be very, very, very unhappy, so if we look through we get like pages and pages of errors of we invalid write of size one, invalid write, invalid write, invalid read, because we're accessing memory we shouldn't have. In order to use this correctly, well I needed at least 12 bytes here, so now if I have 12 bytes I compile, still runs and still works, so I get hello world both times, but valgrind doesn't yell at me or anything like that and of course I should remember to go ahead and free D at the end, so any questions about that? Yeah, yeah so if I did like a stack allocation and did, I don't know, let's say T, but made it too small? No, I mean, no, I'm just wondering like. Oh, yeah, string copy doesn't care if I set aside 12 bytes on the stack here and did something like this and just copied it to T, T and then I don't have to free, then that also works no problemo, so that also works but what I could have done before without having to do the copy, remember if I just do something like this, it automatically does that copying for us, so this is, you pretty much only use the string copy if we are using malloc. All right, any other questions about this? Makes sense and well, this one is also hard to use correctly, so you might be asking like, oh, okay, well what if I actually don't know the size of the string and I don't know how much memory to set aside? Well, as you might imagine, there is a function for that, so there is a version of this that has that N, so there is some limits, so instead there is strn copy, again, why they even forgot, like felt the need to get rid of the O to make it three characters? Don't ask me, but same idea here, so this is the pointer to a char array to actually write the values to, this is the source and then there is a third argument N, so this function will always write N characters to DEST, so in other words, another way of saying it's writing characters to DEST is saying that it will assign values all the way starting at DEST at index zero, all the way up to DEST at index N minus one, and yeah, there's another question going back, why did we use strn copy with malloc? So the reason I use strn copy with malloc is because if I just malloc some space here, or if I go back to the code, so if I just malloc some space here, well, it's uninitialized, I don't know what the values are, so in order to make the string look exactly the same, I just need to copy the string to that region of memory and now I can go ahead and I can do things like I can just modify it if I want, so I could modify it like I couldn't before, so in that case it would make it lower case because before I could not just do that with the S, so I'm not allowed to do that with S because it's read only memory and I am not allowed to assign it, so I could have done it on the stack, but I just showed you how to do it on the heap as well. Okay, hopefully that got that, so yeah. Let's go over the limits. So looks a bit weird because it says it always writes N characters to DEST and you might be like, okay, well, what if the source string has more characters in DEST or what if it has actually less characters? So if N, like the size, the number of bytes it's going to write is less than the string length plus one, so it doesn't have enough room to hold the entire string pointed to by source and the null byte, well, then it just copies up to that many bytes and the resulting string is not null terminated and you may have issues, so it will just try, for some reason, it just copies all the way and would not put a null byte at the end. Otherwise, if N is greater than stir length of the source string plus one, so it has more space than is needed, well, then it will fill the rest of the bytes with just zeros, so all the values from string length, so where the null byte would be, so this would definitely be the null byte because it's a copy of the source string, but it would make all the other bytes also zero all the way up to and including DEST for N minus one. So we can see an example of that. So here's that same one, so here I'll show you I had the string hello world, I will print it off and then I'm going to just create a size, so I'm going to keep track of how many characters I'm actually malloc-ing, so let's say I malloc six characters, so I malloc size of char time size, so this should be six and then I get a pointer back. Now, if I do string copy DEST size, well, how many bytes do I need to store this string? 12, right? Same string as before and then well, I only have six, so this will only, if I give N as size, it will only copy bytes at index zero, one, two, three, four, five from this, so it would copy H E L L O and then it would stop. So it would stop, it would not have a null byte or anything like that, so if I tried to print D here, I'm not sure what I would get, I would get hello and then maybe I got lucky and there was a null byte there, maybe I get random stuff. So to check, I just checked, so I looked at the last byte it would have written and then check if it is not equal to the null byte, if it isn't, I'll just yell, oh crap, there's no null byte and I will change it to null myself. In that case, well, it would just replace the O with a null byte and it should funnily just print off hell, right? Or sorry, it has six bytes, so it would copy H E L L O and then a space and then it would change, take that space and change that space to a null byte and then it would just say hello, right? If I set the size as five or just say five, I wanted to avoid that so it didn't say that. So this should just print hello, that's it, and it should also print that there's no null byte. So also to check, I can go ahead and allocate 16 bytes just to make sure that what I said was true. So I'm pointing to 16 bytes, I do the same string copy, but now I have way more bytes than are required. So I just wrote a little loop that starts at the length of the string. So that should be where the first null byte is and then it goes up to the size and it checks that everything else is a zero. So if it encounters a not zero, it flips padded zeros to false and then breaks out of the loop and then this whole thing would be false and we would never see this printed. But since it does actually write zeros to every single memory location, we will see that the rest of the bytes are null bytes and then we are done. So let us run this quick, oops. So if we run that, see hello world, see that there is no null byte and then we put one in so we replace the space by the null byte. So when we print the string, it is not complete garbage and just says hello and then when it was too big it just says the rest of the bytes are null bytes. So any questions about that specifically the first one? So this will get you into trouble because it's the first function we've seen where the resulting string may not be null terminated. So if I, let's say I just here, let's say we finish our program here. So if I didn't have this check and I just use the string directly, it is not null terminated. So our program is technically incorrect and see how easy that was to screw up our program if we just don't know that this can result in a non-null terminated string. Sometimes if we go ahead and run it, in this case, it looks okay because we got lucky. If we actually go ahead and use VALGRAND on it, it will be very, very unhappy, well, not very, very unhappy because we're off by one but it's fairly unhappy. And it says here, we accessed some memory, we got lucky but it was past the size that we alloc. So it eventually hit a null byte. So what we actually saw that we can't really see is it printed hello and then a space and then it hit the null byte. So questions about that? Yeah. So the question is basically, why doesn't it do what I did there? Automatically, your guess is as good as mine. So that's just the way it was written. You just have to remember that's how it works and it would probably be smarter if you always use that. In fact, for in some other implementations of libraries and operating systems, it actually behaves like that and typically that those systems are a lot more secure because well, it's really easy to make a mistake with this, but that is the story of C. It is very easy to make mistakes which is why I'm doing string functions all this lecture. Any other questions? All right, so we'll see more things we can break. Yeah, and then someone's also asking just to clarify on the security thing does C have any rules that avoid us from getting access to things we shouldn't have access to? The answer to that is no. So in order to prevent you from having things like in checking that you shouldn't access things that you shouldn't access, well, turns out that's slow. So that's slow. Sometimes it makes the programming language way more complicated. C is actually a fairly small programming language. It's just really hard to get right. So you either make things slow or you make a programming language that's very, very complicated. So there is current moves to try and get rid of C and replace it by something that is more complicated but helps you prevent these issues. But in terms of learning about how a computer works, C is actually quite close to how a computer works and you're just hoping something essentially writes good C for you instead of you having to write it yourself. But some of the issues, even if you use other things, sometimes you might run into the same issues or sometimes they might implement it in C and then at some point someone has to implement it and they might screw up this and then, well, then you're in for a world of hurt. So next function is kind of like a string copy so we can basically extend a string with the content of another. So in other words, we can concatenate strings together so we're just kind of adding stuff on to the end of one string. So it is short for string cat. So cat is short for concatenate and it takes a destination string and then a string that we are going to copy from and it does the copying just like string copy except it will start copying at the end of the destination. So it starts at the end of the destination kind of tax it on to the end of it. So it starts copying source from the null byte of destination so it will replace that with the contents of source including the null byte. So this destination must be able to hold well, the number of bytes in the source string plus the number of bytes that we are using with the current string and then plus the null byte at the end. So that makes sense, it kind of adds two strings together. So let's see that example. So here we have the little string, I just put a space world here and then I declare an int size of 12 because I want to set aside 12 bytes. So I malloc 12 characters and then, well, I need to copy the string hello to desk. So after this, because I have enough space if I wanted to, I could just, if I printed, if I printed D, well it would just print off hello and everything would be okay. Now, if I do string cat, so concatenate S on to D while it's going to look at the string hello, so it's going to go H-E-L-L-O and then to the null byte which would be the next character. It's like, okay, now I will start copying from source. So it will copy the space and then the world and then put a null byte at the end of that so our resulting string will just be hello space world, the same 12 byte string we had before. So if we run that, we get hello world all as one string, it just kind of copied them all together. If we wanted to, right, we don't really need cat, it's just a nice function to have. I could have just started writing, I could have just done another string copy and just move the pointer forward a little bit and just made sure I started copying at the end and it would have done the same thing but you can go ahead and use string cat and it'll automatically go to the end for you so you don't have to remember how many characters there are in that string. And yeah, on line 10 here, this hello would have a null byte because we did the string copy. This, the number of bytes needed to hold this is six and our size is 12 so we have enough bytes to actually hold it so we are all good. So yeah, it would be a null terminated string here so this function goes to the end, tax on space world and then puts a null byte at the end so we finally get the string hello world. So questions about that? Yeah. Yeah, so the question is, is the string library faster than if we were to implement them ourselves? Answer to that is yeah, it should be faster. Also it saves you from having to write it yourself which is most of the point but they do some tricks to make it slightly faster too. And also it works on, depending on the implementation, it works on more complicated things because this is only English. What if you had another language or something like that? You might like, it only holds a byte per character and if you look at all the languages in the world there's not 255 characters so it might have to do something more complicated than that but for this it'll be pretty fast and work with ASCII so we're just assuming just US characters because that actually fits in a byte. All right, so here's our example. If we want to implement string cat like if you just thought the name was dumb or something like that you could implement this like this. So we figure out the length of dest so we just store the string length and then we declare a variable called i and size t basically an integer and then we can just start at i equals zero and then copy from the source string until there is not a new byte or null byte so this is just our condition and then we can just increment i every time through. So this would start writing at destlen so destlen plus zero so that's where the null byte was originally and it would go ahead and start overwriting that null byte with the characters from source and then as soon as we encounter a null byte from source this loop would terminate and then i would essentially be the index that should be the end of the string so it just changes destlen plus i and then writes the null byte there so it's always null terminated. So this is basically the implementation of stir cat and I should delete that because I had a typo. Oops. All right, questions about that. Because well, this one's hard to use too because guess what? If I did that, oh crap. Now I don't have enough room, like I have enough room to store hello but I don't have enough room to store hello world and I know how many bytes I set aside so maybe I would like to set a limit on that like we've seen in other functions. So there is another version of string cat that has a limit. This one, it's called stir end cat. So we got dest source and then the number of bytes we copy at most and this will copy at most end bytes from source and isn't directly related to dest which is kind of annoying because that's like the memory we're allocating and we actually know the size of that and also if you use this function the source does not have to be null terminated so it would just read up to end bytes and then it stops there no matter whether or not it was null terminated and this function it will always add a null byte to the end of destination so in order to not run into memory issues this one is harder to use and dest might must point to at least string length so how many characters were in the original string plus the end characters we copy from source plus one byte for the null byte in order to be valid which makes it a lot trickier to use so if we go back to it so say for some reason I just decided to allocate this on the array because if I do this this will not have a null byte right I will have space and then John so this does not have a null byte so if I just use stir cat well I would be in for a world of hurt because I'd be running into invalid memory all the time so I could should only write read four bytes from this so if I allocate let's say I just allocate 10 bytes well then I can malloc my 10 bytes I can copy hello to it so this would be five characters plus the null terminator so it would be six bytes and then I can do this so this does not take into account the number of bytes D has so it would just copy array length bytes so they would only copy four bytes from here and then tack them into D so I would get hello which is five bytes and then a space J O N and then a null byte so it would be 10 bytes in total and turns out it can actually fit so if I do that and I run it so looks correct so fits everything is good but if I go ahead and say it was too small so if I only allocate eight bytes well this function doesn't help me at all it just says copies all the bytes up to four so goes all the way up to four and then just tax a new line at the end and then that or sorry a null byte at the end and that's it so this one even though it looks like it works it has some problems so if I wanted it to work a bit better I should use this one so I know how much memory I set aside so I set aside size bytes and then while I can take that and use that to calculate how many bytes I can copy at most so it would be size and then minus the string length of whatever already existed so in this case minus five and then there also has to be a null byte at the end so I should minus one and then that is how many bytes I can copy at most so now if I set my size to eight well I have eight minus five minus one so what's that that is two so at most it should just copy two bytes from this array here and I won't have any issues so oh sorry just John yeah two bytes which would be the space in the J so now this doesn't have any memory problems whatsoever it all fits within and this one's actually safe to use but you have to remember to do this big calculation in order to figure out okay how many bytes at most can I actually write to the end of the string before I'm using invalid memory so is that okay for everyone so probably the most important one to do because you will probably use this function and this one is really really easy to screw up because you might just think that oh yeah well I'll put a limit on it and I'll just limit the number of bytes I copy from the source string and I will be fine but that doesn't take into account the number of bytes you actually have to store the result so always have to remember that one all right so good about that probably the most tricky one to get right so that's that example so we can also compare strings to each other so has anyone ever like in Windows or anything like organized by file name and like the file names are in weird orders that you don't really expect especially if they start with numbers so we'll get into that so we can compare strings with each other using this function called stir comp again short first string compare so we're just comparing the content of two strings with another so this function returns an integer if it returns a negative value it means S2 is larger than S1 if it returns a zero it means the strings are equal so the content is the same and if it returns a positive value it means S1 is greater than S2 so note this is the function you need to use to compare strings otherwise if I just say hey S1 equal equal S2 they're just pointers C doesn't care you're just seeing if this address equals another address which isn't going to help you if you actually care about the contents of the string being different or not so this is how it works with different strings so it compares the ASCII values and then stops when the first character differs so if you organize like in Windows sometimes well you might have a 9 and then a 10 well you might want the 10 to come after the 9 that would make sense but if you name a file called 9 something and then 10 something well in Windows likely you'll see the 10 first before the 9 because how it compares it is it just compares the first character in both so 9 to a 1 and 1 is less than 9 so that means this like 10 the string 10 is less than 9 so it would be positive which means 9 is greater than 10 so if you sorted by lowest first or tried to do alphabetical then 10 would come first even though well you as a human probably reads that as a number and you're like what the hell 10 is definitely greater than 9 so if I do like if your string ends before so if I do JO compared to John this would be negative which means JO is less than John so if it encounters the end of a string when it's comparing the two characters so it would essentially compare the null byte to an N then while the null byte is always smaller so it would say JO is less than John and again it just does character by character so if I do AAAB well it would just compare the first A with the B A is less than B and then it's done they're different so it would say AAA is less than B doesn't really care about the length so that explains the ordering of files in Windows because it tries to do alphabetical and they essentially just use this function and yeah a combination of letters and numbers again just searches for the first thing that is different so we can go ahead and play with some if you want any examples so if I just compare alpha and beta well I'll just call string comparison on them see if it's less than zero that means S1 is less than S2 if it's greater than zero that means S1 is greater than S2 otherwise the only other result is that it returned a zero and that means they are the same so if I run this oops should say that S1 is less than S2 because well it would just check A and check B A is less than B it's done so you can go ahead and play with this if you have any other questions with that but the important thing is to know you might be tempted to actually just compare the pointers so let's say here I have some string testing and then I calculate its length then I get I malloc two pointers I can hold it S1 and S2 and then copy it to both of them so the contents of the string should be the same so I copy the same string to both S1 and S2 it can hold it but you might be tempted and you will probably run into this several times so I'm explicitly showing this again just to make sure you don't do this so the contents are the same but if I do S1 equal equal S2 that compares the pointer values so if I compare the pointer values and they're different well I don't know whether or not the strings are different or not I would actually have to see their values this just compares the pointers it should say that the pointers are different because I got two different things back from malloc it would be the case however that if the pointers are equal then their contents are the same because they're the same string so you might get into the situation where you accidentally write equal equals but turns out the same pointer value as well as being the same and it works and then suddenly your program doesn't work and you're like what the hell my program worked before and you might just skip over this line assuming that it worked when it really didn't so now and yeah so if you de-reference then they would have different values essentially string ncomp is going to or string comp in this case I used ncomp I'll show that later it will go ahead check all the values and see do the comparison between the values so here if I compare the two strings I should see that the contents of the string are the same and then of course oops that's some testing code then of course I could go ahead and free them so now if I run this it should indeed say that the pointers are different oops so the pointers are different but the contents of the string are the same right so I copied the same string to them they both if I were to print them both they both say testing but they're stored in different memory locations so just remember if you want to compare the contents of the string you can either de-reference them yourself or use string comp that will de-reference them for you all right I have to speed through the rest of them so whoops so there's a comparison function that you can set a limit on so there's stir n compare so it compares like the other one at most n bytes if the strings these strings do not have to be null terminated and it just stops reading early in the case that there is a null character so as a quick example of that one if I do like have the strings John Elfson and John Stewart and then I compare only using the first three bytes while the first three bytes of them are both John, J-O-N so I should get that they are exactly the same so if I run this I see that they're the same because it only compares the first three bytes all right so we can also search so there's a function that kind of does what was on your midterm so you can see if a string is within a larger string using stirr stirr so it essentially takes a really long string that they call a haystack and then lets you find a substring in it or just some other word and it returns a pointer to the starting character wherever it matched and then or it returns a null if it didn't find anything so if the pointer is not null it points to essentially a character within that string so how it would look is sorry I have to go fast we have lots of time next lecture so if I have the string this is a long line and I do search for the string long well that one is actually in it and it will return a char pointer whoops it will turn a char pointer to the first character so this l so in this case it would go ahead f would be it would find long and the pointer would be pointing to right here this l and if I went ahead and printed it out it would just print long line so it would print long line all the way to the end which is where the null byte would be alright so sorry again going fast so we can also just find a character in a string so there is star char I take a big string and I look for a character in it it returns a pointer to that character within the string or like the other function null if it doesn't exist so if I have hello world and I look for w well it would be found and the first w would be right here so it would return a pointer right to that w so if I printed it it would print starting at that w all the way until it encounters a null byte which in this case it would just print world alright two minutes so we can convert strings to an inter-double as well these functions are in standard lib.h and not string.h but they look like this there's A O T I which takes a string and then converts it to an integer and then A O T F which takes a string and converts it to a double and gives you that value back so in this example if I give it the string one two three four it goes ahead and converts that to an integer for me and then I get the value so if I printed the value back out it would be one two three four similarly for A O T F if I just gave it the string one point three three seven and then I printed the value while it would print out one point three three seven probably with some other zeros because I believe by default it will print six decimal places unless you tell it not to so at the end of the slides this is a nice reference for you that is all the functions we have used today so most of them are in string.h basically string length string copy string concatenate string comparison and then searching for a string within a string searching for a character within a string and then these two ones will convert a string to an int or convert a string to a double and yeah someone also asked what if you give a string that has weird characters in it for these functions and well they would fail they wouldn't be able to convert it and looking up if they have an error or not is actually kind of a pain but you would have to look it up we might go over it tomorrow you probably won't use these in a lab if you have to use one of these in a lab I will tell you how to use it correctly if it's possible to have an error so just remember pulling for you we're all in this together