/t/ - Technology

Discussion of Technology

Index Catalog Archive Bottom Refresh
Options
Subject
Message

Max message length: 12000

files

Max file size: 32.00 MB

Total max file size: 50.00 MB

Max files: 5

Supported file types: GIF, JPG, PNG, WebM, OGG, and more

E-mail
Password

(used to delete files and posts)

Misc

Remember to follow the Rules

The backup domains are located at 8chan.se and 8chan.cc. TOR access can be found here, or you can access the TOR portal from the clearnet at Redchannit 3.0.

Uncommon Time Winter Stream

Interboard /christmas/ Event has Begun!
Come celebrate Christmas with us here


8chan.moe is a hobby project with no affiliation whatsoever to the administration of any other "8chan" site, past or present.

You may also be interested in: AI

Let's Learn C Together, Imageboard Style Anonymous 05/02/2022 (Mon) 02:31:22 No. 8314
So I'm recently getting back into writing code again after a multi-year break. I used to be pretty proficient at BASIC and Visual Basic, BASH scripting, and I dabbled in Perl and PHP. Recently I've decided I want to learn C and git gud at it, but going through lessons and tutorials alone is boring when you have no feedback. There's already a dedicated programming thread, but I think there's enough here to warrant a standalone thread where we go through things together. We'll be using two resources. >C: How to Program - an in-depth textbook >The C Programming Language - long considered the beginner's bible for C >Why bother with C when C++ is a thing? C++ is basically object-oriented C, or C with classes. While C++ is a very useful language C is often more immediately applicable to simple, no-bullshit programs that do useful things. C is simpler, with less weeds to get lost in and is thus quicker to learn. And if you are good at C, then it's just a short hop to learning C++. We learn C to walk before we run. Since I'm a newbie too I'll post useful things I learn and code examples I write ITT for anons to play with, and explain the things I learn both for your benefit and to help me remember them better. If you want to join me, start off by reading The C Programming Language cover-to-cover. If something seems confusing, cross reference it in C: How to Program for a different perspective. Here we go.
>>8658 holy fuck you STILL cant figure it out there is no endian issue you fucking clown its completely IRRELEVANT no one fucking cares about endianess or any of that garbage the pseud larper is spewing out to hide the fact the imbecile knows nothing about c play around with this until you finally figure it out and start READING the books you posted instead of getting clowned on by a larper # include <stdio.h> void main() { FILE *fp = fopen("tmp.txt", "w"); char you, d[8], clown[] = "117clowndd=dumbass fucking"; fwrite( clown, 1, 26, fp ); fclose( fp ); fp = fopen("tmp.txt", "r"); fscanf( fp, "%d%6sd=dumbass %s", &you, d, clown ); puts( clown ); puts( d ); putchar( you ); }
>>8658 >I feel like I was doing this exact thing before and running into the null terminator issue Probably because at one point you were getting the length of the data in the xor array like this: >>8576: >int k = strlen(xor); with xor being an array filled with random unpredictable ('encrypted') bytes, the strlen() result is unpredictable because xor may contain the terminating '\0' somewhere. >I set the read limitation for fgets as one byte smaller than the arrays I don't think that's necessary. Also why the hell declare k as a global variable? >>8659 >no one fucking cares about endianess or any of that garbage Read a book nigger, and get some real life development experience while at it.
>>8682 >larper still doesnt know the cpu reads the exact same way it writes <uhhhhhhhh ur problem is there is two endian and uh byte is sometime 8 and sometime 16 so yeah it like do overflow youre a fucking clown post code or shutup show this other clown just how fucking clueless you are by fixing his code lmao fucking larping loser
>>8683 >bawwww portable software is too hard for meeee Go program in java. Actually, learn how to write English first nigger bitch, I ain't reading your schizo posts.
>>8684 >nooo i got exposed as a pseud larper and cant post code cuz it will expose me as an imbecile clown spewing garbage no one fucking cares about anymore cuz all pcs are the same now, nooo its not portable noooo cry more
>>8682 >with xor being an array filled with random unpredictable ('encrypted') bytes, the strlen() result is unpredictable because xor may contain the terminating '\0' somewhere. k is actually = to strlen(userinput), and only after the array is filled. I used the variable just to make for less writing when setting loop limits (no looping read through any array would be longer than k, because the keysize and xorsize would be the same length as the userinput if all 3 arrays are chars), and its there because I reused some of the prior code for this test. It doesn't need to be there but I left it since I'm playing around. >Probably because at one point you were getting the length of the data in the xor array like this: You might be right. I appreciate the advice you've given by the way. I'm not sure what other anon's problem is. Everyone is a retard when they first start doing something new and complex. I'm here to learn, not be praised or to be a 1337 c0d3 h@xx0r.
>>8686 no youre especially retarded for getting clowned this hard all you had to fucking do was use normal file read/writes like a normal fucking person instead of using fucking FORMAT strings say it with me you fucking clown , the F at the end stands for FORMAT-STRING the fact this clown starts faffing about byte sizes and endians is fucking hilarious but youre too stupid to realize it yet, consider it your graduation when you laugh uncontrollably rereading all this fucking gibberish thats been posted stop using gets,printf,scanf, or anything with a fucking f or s at the end, your arrays are not strings and your not writing strings you fucking imbecile stop fucking using string functions, stop thinking with strings you pyshit skid fwrite/fread is all you had to use since the begging
>>8686 >k is actually = to strlen(userinput), I was talking about the post I was quoting, which is where the bug is present. >variable It's a good use for a variable but what I'm saying is that there's no good reason for it to be global. I'm not sure what concept you have of global variables to think k needs to be global. >Everyone is a retard when they first start doing something new and complex. I'm here to learn Yes, but you should have started in some other way that holds your hand a bit more and allows you to take in more background because this way you'll just keep churning out code without understanding what really goes on and it puts a big burden on anyone that wants to help you. It'll be difficult to learn the basic concepts by virtue of just running into them in the form of bugs.
>>8314 >And if you are good at C, then it's just a short hop to learning C++. We learn C to walk before we run. That's interesting because I watched a lecture complaining about exactly this stance. yewtu.be/watch?v=YnWhqhNdYyk I'm not an experienced programmer. From what I recall from when I originally watched the lecture, it's supposedly been a common practise for years to teach programmers C first, and then teach them C++. According to the lady, this started because originally, that was the situation anyway: C programmers now switching to C++. The problem is that C++ is no longer what it was back in the '80s. There's this thing called "Modern C++" and so, the classical approach of teaching C, and then teaching C++ is not only outdated, but terrible. Somebody that's new to programming is going to feel intimidated by these "printf" and "scanf" functions, meanwhile, C++'s inputs and outputs are far more intuitive. By going straight into Modern C++, the lady explains that her young daughter was better able to get into programming. What do you think, OP? You're probably aware of "Modern C++." Should you really be maintaining this classic approach?
(193.73 KB 830x1205 string.png)

>>8708 Not OP but thinking people that feel intimidated by printf or scanf are going to be able to go anywhere in either C or C++ is retarded. I have no idea how someone that has trouble understanding those basic functions (which honestly are not difficult at all and I even prefer them over streams) is going to be able to understand movement semantics, templates, or name mangling, not to mention the fact that unless you develop over Qt or some other framework you are going to need to interact with C style functions from your OS at some point anyway, and most likely with raw pointers. C is great because it's has a simple syntax (compare that to templated types, lol) and the way everything works is easy to see at a glance because of the low abstraction level, so it gives you the chance to learn how everything is structured and fits together. C++ is much more unforgiving given how batshit insane the syntax is and how crazy the abstractions can become (e.g. std::bind), not to mention that most documentation for C++ is absolutely fucking cryptic. I mean, son of a bitch, pic related is the definition of the constructor for the string class, which you'd think would be the most trivial class in any language. Show that to a newfag and watch him run away screaming.
>>8708 OP here. Honestly I don't know. Back in my college days I got scolded the other way around, because I took an interest in learning C++ when I had never learned anything about C. I opted not to take the course but dabbled a little bit in my free time until I got sick, which ended my coding career. I don't really have an interest in C++, today, personally. If the "Modern" method its how it is done now than I have no reason to argue the point. Going back on topic, I spent a few days working outside the country and now I'm back to tinkering. Frankly the cryptic business with arrays and file streams and memory were getting annoying and I resolved to solve the issue to at least my own satisfaction. So I took a core component of my code, stripped it down, and built a little tool with it which I then beat the problem into submission. I wanted to understand the mechanics going on under the hood of the various file stream reading systems and their relations to the data that would appear in the array based on a dozen combinations of array size, read functions, terminator formatting, newline or no newline, etc. etc., and much of what I was reading on the subject was in the vein of "just draw the rest of the fucking owl" so I went in the hard way. # include <stdio.h> # include <stdlib.h> # include <unistd.h> # include <string.h> # include <math.h> int main() { int k; FILE *Keyfile = fopen("/home/USERNAME/keyfile.txt", "r"); puts("How many character bytes do you want to read from the keyfile? MIN=1 MAX=1800"); scanf("%i", &k); char key[k+1]; printf("\n\nReading the key.\n"); if (!Keyfile){ printf("Error opening keyfile!"); return(1); } else{ fgets(key, k+1, Keyfile); //for(int i=0; i<k; i++){ //key[i] = fgetc(Keyfile); //fscanf(Keyfile, "%c", &key[i]); //key[strlen(key)-1] = '\0'; } //Check for the newline that fgets can add to the end and replace it with a null (proper way) size_t len = strlen(key); if (key[len - 1] == '\n'){ key[len - 1] = '\0'; } //Print the contents of the key array to verify printf("Key array is of length %lu with size of %lu\n\n", strlen(key), sizeof(key)); //printf("%s", &key); for (int i=0; i<=k; i++){ //printf("%c", key[i]); printf("%d ", key[i]); } // } printf("\n\n");
[Expand Post]return 0; } So let me go over a few things. The most effective read I found, for my purposes, was fgets(). It reads k-1 bytes from the file stream into a buffer, which in this case is just the key array because I'm running it internal to the IDE. When it puts k-1 bytes in there, the last byte will have the null terminator appended automatically, which does not happen in a lot of what I was doing before. For this program it sets both the char array length and fgets read length to k+1. I did this to see the output of trying to read a single byte from the keyfile. Remember, fgets() reads k-1. So if k=1 you'd just get a null. However because fgets() also stops reading at EOF, even if you give it a huge k, like 2000 against a file 1800 bytes long, it will make the array that big but will neatly halt reading the keyfile into it at the end. I also changed out the hard replacement of the newline character and implemented it as a check function that doesn't just assume there's a \n to get rid of, but looks for one and puts the null terminator there if one is found. Finally it prints the strlen of the array and its size side by side, and prints the array either as characters or their ASCII values depending on what you comment out. Try running this a whole bunch of times with the different options enabled or disabled with comments and compare how the various implementations behave. I've learned a whole lot from this dumb little block of code. Here's a sample keyfile for you too. <;5*ilZ!Kdy%:%?jg"gQbYl!os0?P4/+,%ps*N9<!zvn}-kF++y3oe3;mKg8Riy9|Q!U$@A}.U^3?TJmKftyV:5;S{m/$,DG?4#aX2s,2Z>7K.zde1%nQV!*r}y78NgU=2;?%ZTlyO>EoV}ys55vBZr3j2tDm|.bLC0=%i+^oZ;@c8mckZxK3mq_r"{etd-Iy/-T>c&%&>ID<Sg}Nb-wc%qwbzZ:}qEKl>v|BlzKLV^QEyaqv^t"Mq-rMqRN{BE7D!cFzaM@E-_O-V9v>iO<U=*ZBUudupD8g4h[N49XioD;x]Bak3VoC]a3yL?7JcM:yfz9H!giK.=D:yV&J.V=j"QHn5x>*Ly[;R0dW*=O1Yt$5F+70haM4b<,VI7.-HHLO@W2Pge7a/5bveAfa0wiVBA<=l9z?R11VYSVu2qC*u/ESlKTZA-,"d0F8E89O0t|xnjj+Jz#|^vtf?YF?Z!rrD5P96N90BbcuLJra=$ft6+xh1I}{?4QSUX1+j%>iVS#2sux;;cjJg^ZbP]fbi=-aBM-iPLJagVhu2.oy<F"c.o@5z9YnpR.oY>}%R5EYbzYu}9^-nrkrcqYyGz{f{W,*xb/L]IhL@UcYww[BH,2.u<%/hYEOE#,&R,TQTwQxZLDOk:U>|UuiB!kq205A4S+:p2O#LAhyO61rPiach_x,4?gQol5i9;=SjUbr!U!7}|_&I?45]D=DO>el-xV2!aEWF,-O=5AKuGRN#OM$2UdpcjNS5_mY;I>I0srF1#3dld$#vdj^OV$$:huajE8,RLwGiYe>51$Ue[o_!TP52y<]JDiCg$I5qD99*e0CKdL=:*gOEIJHN^-/h;[ZN9%pcpX#A&T;-*AOilOuhlgV8toRulh]GQIJ:sY_jn4.*d&=vHGnlq-*yNGuR.bb,CII]ZY-8[en#]g$VRnd{p",8/f%jJ<YB+IXPuLry^%*O=|MS]5Py!ae*C*#:ZjuexGI4Cd?:CEcmA9fS]l_nU}2!y^yqG};=W]LP2LB4Pjh,D]0Yj|N2gX[>|cX-@N[Swh^n!H;NVGs+HsUM#2EeNSQ;Z8.*0@x"Y1|JR7/=Uj}:d!6;U]{j<:!URTpyb_q1I.fyAx]v".0y,#Q_EC<#hFou,FV-z$F3]pL3s^}p#uwfAZmI&ZC|"@Z#gr$:$}f{M_e|JH0[37*2l2S[?{XJj5Bh;{+"RZ0$Uk/#e1f[^d-QZ"9dCe.H#h=S|_9Hrw{fNP92QjPzx!y<4^3v_my?G{f/u_AuEAx,|u#NHGz8kbSsOjC%?$XuCi9K=X|.I7|;fg7bS}6u;k"fcyU/2ORq&KSPDxB[S>pUOarfFbZk@7+Uy5wT-<^Anx*WT?Bo!*6t9Of;2sQ;w-E#_tqLVhY$b=tJlPo73"K<G:zLX{^K|3;EehTx}E,;z!3Hn-TQZNi|p:hmRub,-UmtI.NPT,C:luA@cT3t?W>[z;Em]abps31et.wW0LK!s3eQWpiPt^D%+"|3X6a5#N0ZFuV<1iFnpQb&v;s<fTm|n=q!#f|kQ*kV1L-;G1q@J9_/S5D>M*CAjD*ZZ2q@ebwpLw[91}]d1m:AZofl=odf_CwFHrzf{L2JE+UXIvy_D*@VF^@-yQlmIUq@tO.O,Nwjt}6Y.@{ya&#uvQ=0R&7dDQbVTH^WWE#G/oOcE[oK1.h:NL8uNl.61!M"cx0tNCEvhCgGsC+$6_P}zS[Of>-ZK7#%X=?*m[!Y4^Pu}YKd=Tr<wRTvY-#_.[1?E1RH:uCzS<DcO,CAEVssC]N[<KY{1gdGAXXp=TQjGtz]GGs;f0{}Le
>>8714 Here's a slightly better version with an error handler to prevent running over the array, and it also has one tiny difference that I had been playing with and forgot to readjust before I posted. For other people learning, see if you can spot it. # include <stdio.h> # include <stdlib.h> # include <unistd.h> # include <string.h> # include <math.h> int main() { int k; FILE *Keyfile = fopen("/home/USERNAME/keyfile.txt", "r"); puts("How many character bytes do you want to read from the keyfile? MIN=1 MAX=1800"); scanf("%i", &k); /*if(k>1800){ puts("Error, array exceeds maximum key size"); return 0; }*/ char key[k+1]; printf("\n\nReading the key.\n"); if (!Keyfile){ printf("Error opening keyfile!"); return 1; } else{ fgets(key, k+1, Keyfile); //for(int i=0; i<k; i++){ //key[i] = fgetc(Keyfile); //fscanf(Keyfile, "%c", &key[i]); //key[strlen(key)-1] = '\0'; } //Check for the newline that fgets can add to the end and replace it with a null (proper way) size_t len = strlen(key); if (key[len - 1] == '\n'){ key[len - 1] = '\0'; } //Print the contents of the key array to verify printf("Key array is of length %lu with size of %lu\n\n", strlen(key), sizeof(key)); //printf("%s", &key); for (int i=0; i<k; i++){ printf("%c", key[i]); //printf("%d ", key[i]); }
[Expand Post] printf("\n\n"); return 0; }
>>8713 >I have no idea how someone that has trouble understanding those basic functions (which honestly are not difficult at all and I even prefer them over streams) is going to be able to understand movement I think the issue is that those functions, when learning C, are introduced really early, they're kind of complex, and aren't fully explained and understood, until much later. Meanwhile, C++'s output method, even if you don't fully understand it as a beginner, at least feels less intimidating at the start. Personally, I remember finding it quite jarring learning C and finding that I have to use "%d" in my output, without even knowing what it means or what it does. I literally didn't even know what a "placeholder" was. The "%d" thing definitely enhanced the feeling that C is something "cryptic" and "deep." If you're going to teach children programming, if you want to avoid intimidating newcomers, C++ seems like the preferable option to C. I don't think it's a matter of understanding. I think it's a matter of approachability. The lady, IIRC, was a teacher, and she seems to believe that approachability would improve retention as she felt that people were abandoning the class shortly after starting it because it felt unapproachable. I have to say though: you do drive a good point. If you're willing to give up at such a hurdle, could you have really gotten far to begin with? I don't think the answer is "yes," but I do think that the answer lies more towards "yes" than you might think. More and more women are entering Chess. Before Women-Only Chess Tournaments and Clubs were created, people used to say things like: "there's nothing really stopping women from playing Chess" and "if they want to succeed in Chess, they're free to do so." Most critically, you'd even hear "if there was going to be a great female chess player, we would've seen one by now." By giving women these women-only spaces, they had a place they could improve their skills whilst also feeling welcome. Then, when they're good enough, they start competing in open tournaments. Just to give you an idea of what women face in Chess, one woman was accused, upon victory, of using cheats in her lipstick. I think how the Chess community treated women is a good example of a successful outreach program and is proof that approachability does work. Maybe not a lot of programmers would persevere if the introduction was easier, but I think there would be some improvement, and I think that would help.
>>8714 >sizeof(key) I'm honestly surprised that works. sizeof is supposed to execute at compile time, but when you do char key[k+1]; the result isn't available at compile time. Defining arrays with sizes undefined at runtime can be controversial, but at this stage I guess it's more important for you to focus on other stuff. >IDE I'm surprised you're using an IDE since they usually keep the indentation neat and consistent. Does it get fucked once you post? Actually, does it look fucked only for me? Either way, if you're not doing it yet consider using your debugger to inspect the memory of the arrays and see what data gets stored there and what happens with the array space in different situations and for different types. >>8715 >for (int i=0; i<k; i++){ Since key is defined with k+1 size technically it was valid to do <=k. >>8717 I'll concede that streams are safer to use and may have friendlier syntax to a newcomer, but ultimately if you're asking questions about what %d means it's fair to also think you'd be asking questions about how the shift operator overloading works for streams to automagically handle I/O and then you're left with an explanation that's a whole lot more complicated than explaining printf. Maybe however you learned the language wasn't that good at teaching it. Additionally, I think your notion of approachability is inconsistent considering the cryptic syntax and documentation of C++. >The "%d" thing definitely enhanced the feeling that C is something "cryptic" and "deep." >If you're going to teach children programming If you want to teach, why do you not expect people to have to learn? Hiding implementation details behind an abstraction is the opposite of learning. Why even teach C or C++ if you can teach some language like Javascript that doesn't even mandate that you understand types? Surely that would be a whole lot easier to figure out for a newcomer. The whole idea of teaching children 'programming' is in the first place retarded and perpetuated by people that turn a blind eye at how kids can't even get right basic reading or maths anymore, and politicians cling to that trend because it is convenient to them to create idiots and makes them look progressive in the same sentence. I wouldn't even teach anyone 'programming', I would teach them computer science because then it doesn't matter what's the language of the day, but it's a lot more fancy to create an HTML webpage and feel accomplished than understanding an ABI.
>>8718 >I'm honestly surprised that works. I've found that as long as you define the variable somewhere in the code before calling the array that uses it, it works fine. Like Basic, C executes from top to bottom. It may just be GCC being smart enough to see the array and the variable definition at the same time and realizing it can compile it, but for testing purposes I'm not going to complain. >I'm surprised you're using an IDE since they usually keep the indentation neat and consistent. I unironically hate the way it auto indents. If I have to use indentations then whenever I see a closing curly I want to be able to scan straight up the column that its in and run right into the first letter of the function that opened it. Code::Blocks indents one more tab than that by default and it drives me batty. I literally couldn't give a shit about using an IDE except that I really want "build and run and give debug output" in a single click. I don't have all day to play with these and recompile them 50 times the manual way. >Since key is defined with k+1 size technically it was valid to do <=k. Right. In this case I wanted to read past the end of the string and make sure the null terminators and/or newlines were present in the array's memory block. I did some more work tonight. After my long session fucking with that little program above (and having spent my free time at work digging around in ANSI C and C99 docs for bits of trivia), I finally felt confident enough to try expanding it into the XOR operation again. This is the result, and you can test it using the keyfile text I posted up above. # include <stdio.h> # include <stdlib.h> # include <unistd.h> # include <string.h> # include <math.h> #define arrsize 1802 int main(){ FILE *Keyfile = fopen("/home/USERNAME/keyfile.txt", "r"); char input[arrsize]; //Take text input from stdin puts("Enter your text - MAX 1800 characters."); fgets(input, arrsize, stdin); //Check text input for a newline and null it if it exists, and we'll reuse this variable k as a limiter downstream size_t k = strlen(input); if (input[k - 1] == '\n'){ input[k - 1] = '\0'; } //Make sure the user doesn't put too much into the array (still learning about malloc) if (k > 1800){ puts("Error, message was >1800 characters. Don't be a fag."); return 1; } else{ printf("Verifying your text input was length %lu and size %lu...\n", strlen(input), sizeof(input)); //printf("%s", &input); for (int i=0; i<k; i++){ printf("%c", input[i]); //printf("%d ", input[i]); } }
[Expand Post] char key[k]; printf("\n\nReading the key.\n"); if (!Keyfile){ printf("Error opening keyfile!"); return 1; } else{ fgets(key, k, Keyfile); } //Print the contents of the key array to verify printf("Key array is of length %lu with size of %lu\n\n", strlen(key), sizeof(key)); //printf("%s", &key); for (int i=0; i<k; i++){ printf("%c ", key[i]); //printf("%d ", key[i]); } /////////////////Begin Math//////////////////// char xor[k]; for (int i=0; i<k; i++){ xor[i] = (char) (input[i] ^ key[i]); } printf("\n\nExecuting XOR and storing in xor array of length %lu and size %lu\n\n", strlen(xor), sizeof(xor)); for (int i=0; i<k; i++){ printf("%d ", xor[i]); } printf("\n\n"); return 0; } I actually fucked up handling the text input at first because I was so used to file reading. I set the array size as 2 bytes larger because fgets() for the input read will initially add both a newline and a null, so the maximum stdin size is actually 2 bytes larger than the maximum length of the keyfile and 1802 reflects that. This code makes a few assumptions. One is that it will use the generated keyfiles from my BASH script, so encountering a newline in the keyfile won't happen and doesn't require handling. I'm keenly aware of the buffer overflow potential when the text input is too large, but I haven't gotten into using malloc and calloc yet, so a fixed array size with an error condition is the best I can do right now. This doesn't care about actually showing you the null terminators in the input and key arrays since I've verified about a thousand times that the base code will put them where they need to go, so it doesn't bother with the K+1s and/or i<=ks, and the print from the xor array does confirm that the terminators are there, and were xored. You can also determine this by seeing that the strlen() sizes on the arrays are always one byte (one element in a char array) smaller than the sizeof(). The missing byte is the space of the null. This build has no compiler errors or warnings.
Since it keeps coming up, and I just bothered to research my assumption, yes you can use an array whose length is defined as a variable and declare them both at the top. ISO C99 supports this as Variable Length Arrays (VLAs) and if the array size cannot be computed at compile time, then GCC and (most, but not all) other compilers will instead compute it at runtime. You get a compiler error if your code isn't structured in such a way that the variable is defined before the array is used (because then runtime compilation would be impossible too), but if you avoid that then it's a legal operation. It's just unusual, which doesn't bother me in the slightest.
(609.27 KB 1123x1500 FVVzrfAUUAI-EQW.jpeg)

Now I have a question. This seems like the sort of thing that'd get asked on Cuckoverflow, but I'm looking for where to start researching it. I have this first stage of the program working to my satisfaction. Now what I need is to write the XOR result to a file, and then be able to read that file back into a char (really should just be a byte) array. There are a lot of file I/O tools and I spent tonight playing with a few, but didn't get anything working correctly. The (current) output file format is generating by printing the byte values in the xor[] array elements with spaces between. It looks like 72 94 70 94 0 Attempting to read from the file as %c gives me one digit per element, but reading them as integers brings back the endian problem. I'm looking at a tool from stdlib called itoa but I'm not satisfied that it's what I want. I also considered restructuring the output file to print each byte value on its own line and then reading them all with fgets() and some formatting, but this also failed, possibly just because I fucked it up. What is my best approach here? Any suggestions?
>>8719 >I unironically hate the way it auto indents I imagine it should be possible to configure it somewhere so that it behaves as you want. Might be worth to check it out if you're going to be dedicating enough time learning C to warrant it. size_t k = strlen(input); if (input[k - 1] == '\n'){ input[k - 1] = '\0'; } Here you might be changing the input length (shortening it by 1), but you don't recalculate k and you're using k below with the previous value. I think you're aware of this, however it is kind of weird that you'd be willing to xor the terminating null with your key (and you're additionally disclosing one byte of your key because you're xoring it with \0), and also I think the behavior won't be consistent if you input more than 1801 characters so that fgets() doesn't give you a '\n' as last character. >I'm keenly aware of the buffer overflow potential when the text input is too large I'm not sure where you're seeing this potential overflow. fgets() will not try to go beyond bounds given that you're specifying the bounds as a parameter. >>8720 The problem is that believe it or not, not all compilers support all the features in C99, so if you're working with portable code you're going to get fucked by them eventually (I was). If I remember the story correctly, some developers were just being stubborn and wanted to explicitly not implement VLAs into their compilers (Microsoft comes to mind), and because of that when the newer version of the standard came around (C11) the standard was changed to make them optional. As a result, whether it's going to work or not is up in the air, but in a scenario like this it doesn't matter that much. >>8724 The simplest option is to ditch text files and work with binary files. Doing that you can just dump the whole byte array to a file and read it exactly the same, as if it were just an area of memory. If you want to inspect the file you'll need to use a hex editor however. Otherwise if you're using fscanf() with text files like before, just use the right specifier, gcc was suggesting %hhd in >>8583
>>8737 >The simplest option is to ditch text files and work with binary files. I actually came to this same conclusion last night. I was laying in bed after a nap and lazily thinking about computer stuff, and had a sudden epiphany. "In the same manner that in Linux, everything is a file, in C, everything that I'm manipulating is just bytes." And it blew up my thought process a bit. In the moment I saw the abstraction layers of the code strip away and I realized what I was doing was completely different to what the code looked like I was doing. Just choosing to view data in a certain way, whether as a char, or an ASCII, or an int, or an array, is completely fucking irrelevant. What I see is irrelevant. What I'm doing is manipulating raw-ass, on-the-bare-metal bytes. Having some programming experience I obviously know that computers think in bits and bytes, and that even under BASIC down there at the bottom of the pool my code is niggering bytes around, but I suddenly realized how shallow the C pool was. I get it. And honestly it's a trip. I'm more excited now than I was when I started. So yes, binary input and output files and let the chips fall where they may. This made me realize I had a whole bunch of very important questions to answer, so for now I've returned to the literature.
>>8739 Yes, that's pretty much how it works. Have fun.
>>8741 Yeah. I've now realized there's actually a few ways to skin this cat. And I've started punching myself everything I think of a "type of array." An array isn't even a thing that exists, all you have is a contiguous memory blocks holding one of a selection of different byte sizes that can be conveniently looked at in certain ways. There's no such thing as a "char array". It's "a 1-byte array that's convenient to read as characters." Or an int array is "a 4-byte array that's convenient for looking at integers." C is so low to the ground that even the data type descriptors on the basic building blocks are fluff. That's what blew my mind. For instance, one solution to my problem would be to make a stubby 2D buffer with 1800 subarrays each with a single 4-byte element. Then read the space-delineated values from the textfile into each one as integers, terminate read on whitespace, and then do an itoa loop through the 2D array to convert each 4-byte integer into a 1-byte "char" and put those into a 1-byte array. It'd be wordy but it would sidestep the endian issue because you'd always be doing the two conversions on the same hardware. I'd call this "doing it wrong the right way." Binary files just make the most sense, then read the bytes into a 1-byte array directly. I looked into fscanf %hhx but from what I'm reading there'd be issues to overcome that way too. Specifically you have to compensate because the read values aren't all a common length. 1 byte expressed as an integer can be 1, 2, or 3 digits long. There was quite a bit of stackoverflow whining about making that work. I'm wondering if formatting can be imported in the read now. Suppose the output file just delineated the byte integers in single quotes, the way they are when initialized into an array: '72' '94' '70' '94' '0' Is there a handy way to read that as byte values with one of the file I/O tools?
>>8747 Oh shit, don't tell me I could just read it as a string and load the string into an array initialization like a variable. I bet you can, especially if you slap the preprocessor in the face with it and mind the formatting of the output file. Something like int array[1802] = { #include /path/to/textfile.txt } Since you're using the preprocessor I'd bet you don't even need to specify the array size, huh. Man, its too bad this would only work at compile time. I'm still gonna try it later, I just want to see if I'm right.
>>8747 I think you're getting way too ahead of yourself nigger holy shit. >2D buffer You mean a matrix. Avoid them as much as you can. >1800 subarrays >each with a single 4-byte element Call it like it is, an integer. It's confusing otherwise because you make it seem like the 4 elements are something separate when you're supposed to interpret them as a whole value. And when you do that you realize you're just niggering your way into using a 1800 elements int array, in fact the memory layout would be no different. >itoa itoa means int to ascii. it's going to grab e.g. 0x62 and convert it into into a string (i.e. "98" or 0x39, 0x38, 0x00). A valid output will never be a 1 byte value. >It'd be wordy but it would sidestep the endian issue The endiannes issue was related to how you were writing an array several attempts ago, it was an interesting and funny mistake that would have caused a difficult to find behavior in certain cases but otherwise it's not as much of an issue as you think and I don't think you should worry about it for the most part, you have other shit to worry about nigger. The worst part is that instead of niggering the solution and concerning yourself with several different arrays and conversions and sizes you can just read it all into a 1-byte array like it'd be anyone's first guess because it's the most straightforward thing which is what I've been mentioning for some time. >fscanf %hhx but from what I'm reading there'd be issues to overcome that way too. Specifically you have to compensate because the read values aren't all a common length. 1 byte expressed as an integer can be 1, 2, or 3 digits long. There was quite a bit of stackoverflow whining about making that work It's %hhd (or %hhu), not %hhx. The function (fscanf) is supposed to convert things according to what you specify, it's the function's problem to deal with the implementation (e.g. how the algorithm works). You just go by the interface (API spec). I don't have time to research what you could have found but it fucking works fine nigger, it ain't that difficult. while(1) { uint8_t nigger=0; int result = fscanf(fp, "%hhu", &nigger); if(result == 0 || result == EOF) break; printf("--->%u\n", nigger); } exit(1); samples: >1 2 3 4 --->1 --->2 --->3 --->4 >2 44 123 250 --->2 --->44 --->123 --->250 <error condition >1 22 333 5 --->1 --->22 --->77 --->5 That last one isn't working completely well. I'm not going to go read the whole doc or research what the issue might be for you (though I was expecting it to return a matching failure as it is, it seems it may not recognize it as such and instead just AND the result with 0xFF and call it a day.) You can do it yourself, or continue assuming the inputs will be correctly formatted like you've been doing so far, or do some other solution too.
[Expand Post] >Is there a handy way to read that as byte values with one of the file I/O tools? Possibly fscanf() could do it but I've never used it like that. Otherwise make a function to parse it yourself, it ain't that difficult either and you'll get more predictable results so that you don't come across what happened to me above.
>>8748 >mfw That's an interesting one. The syntax in the file would need to be a bit different though, but let us know how it goes.
>uint8_t nigger=0; uint8_t specifying a 1-byte standard unsigned integer, corresponding to an unsigned char. I think that's the piece I was missing. >>8750 I can confirm this works, hilariously. You have to comma delineate the input file and remember to put the path in quotes. Its useless for this application, but yeah it works. It just pulls the text from the file into the array brackets and off you go.
>>8752 "uint8_t" is for practical purposes the same as "unsigned char" on desktop platforms nigger. It's literally going to be aliased to unsigned char inside your system's headers.
OP here again, I finally got some time to implement some of the ideas discussed here. I'm very pleased to say that it all, finally, seems to work. And no errors or warnings. Encryption: # include <stdio.h> # include <stdlib.h> # include <unistd.h> # include <string.h> # include <math.h> #define arrsize 1802 int main(){ FILE *Keyfile = fopen("/home/USERNAME/keyfile.txt", "r"); char input[arrsize]; //Take text input from stdin puts("Enter your text as a single line, no paragraphs, max 1800 characters. Press Enter when finished."); fgets(input, 1800, stdin); //Check text input for a newline and null it if it exists, and we'll reuse this variable k as a limiter downstream size_t k = strlen(input); if (input[k - 1] == '\n'){ input[k - 1] = '\0'; } //Make sure the user doesn't put too much into the array if (k > 1800){ puts("Error, message was >1800 characters. Don't be a fag."); return 1; } else{ printf("\n\nVerifying your text input was length %lu and size %lu...\n", strlen(input), sizeof(input)); //printf("%s", &input); for (int i=0; i<k; i++){ printf("%c", input[i]); //printf("%d ", input[i]); } } char key[k]; printf("\n\nReading the key.\n"); if (!Keyfile){ printf("Error opening keyfile!"); return 1; } else{
[Expand Post] fgets(key, k, Keyfile); } //Print the contents of the key array to verify printf("Key array is of length %lu with size of %lu\n\n", strlen(key), sizeof(key)); //printf("%s", &key); for (int i=0; i<k; i++){ printf("%c ", key[i]); //printf("%d ", key[i]); } /////////////////Begin Math//////////////////// char xor[k]; for (int i=0; i<k; i++){ xor[i] = (char) (input[i] ^ key[i]); } printf("\n\nExecuting XOR and storing in xor array of length %lu and size %lu\n\n", strlen(xor), sizeof(xor)); for (int i=0; i<k; i++){ printf("%d ", xor[i]); } /////////////////Begin Cipher Output//////////// FILE *Cipher = fopen("/home/USERNAME/ciphertext", "wb"); if(!Cipher){ printf("Error writing to file!"); return 1; } else{ printf("\n\nWriting XOR array contents to binary file ciphertext"); //fputs(xor, Cipher); //for (int i=0; i<k; i++){ fwrite(xor, sizeof(xor), 1, Cipher); //} } fclose(Keyfile); fclose(Cipher); printf("\n\n"); return 0; } And decrypting: # include <stdio.h> # include <stdlib.h> # include <unistd.h> # include <string.h> # include <math.h> #define size 1802 int main(){ FILE *Keyfile = fopen("/home/USERNAME/keyfile.txt", "r"); FILE *Cipher = fopen("/home/USERNAME/ciphertext", "rb"); FILE *Plain = fopen("/home/USERNAME/plaintext.txt", "w"); char ciphertext[size]; if (!Keyfile){ printf("Error opening keyfile"); return 1; } else if (!Cipher){ printf("Error opening ciphertext!"); return 1; } else if (!Plain){ printf("Error opening plaintext!"); return 1; } else{ printf("Reading ciphertext into array...\n\n"); fread(ciphertext, 1800, 1, Cipher); } //FSEEK for the size of the ciphertext file to set our read limits fseek(Cipher, 0L, SEEK_END); size_t j = ftell(Cipher); rewind(Cipher); //Print the contents of the ciphertext array to verify puts("Printing contents of the ciphertext array to verify."); for (int i=0; i<j; i++){ //printf("%c ", ciphertext[i]); printf("%d ", ciphertext[i]); } //We attempt to read the keyfile into an array char key[j]; printf("\n\nReading the key...\n\n"); fgets(key, j, Keyfile); //Print the contents of the key array to verify printf("Key array is of length %lu with size of %lu\n\n", strlen(key), sizeof(key)); //printf("%s", &key); for (int i=0; i<j; i++){ printf("%c ", key[i]); //printf("%d ", key[i]); } //////////////////////////////BEGIN MATH////////////////////////// //Attempt to XOR the ciphertext and key arrays and view the plaintext char plain[j]; for (int i=0; i<j; i++){ plain[i] = (char) (ciphertext[i] ^ key[i]); } printf("\n\nExecuting XOR and storing in plaintext array of length %lu and size %lu\n\n", strlen(plain), sizeof(plain)); //for (int i=0; i<j; i++){ printf("%s", plain); //} //Write the contents of the plain array to the file plaintext.txt puts("\n\nOutputting plaintext to plaintext.txt"); fputs(plain, Plain); printf("\n\nAll done."); fclose(Keyfile); fclose(Cipher); fclose(Plain); return 0; } Lots of validation prints and comment blocks where I was trying different things just to see how they'd behave. I noted pretty quickly that you can't read binary data interpreted as a string because it's never null terminated (not a C string). In setting the read limits for the decryption process I had to make my first use of fseek because strlen was a no-go, but I had already known I was going to have to, so that was gratifying. Both of these programs worked with every combination of inputs I could throw at them, including escaped characters and special cases and natural 0s from the XOR. As an aside, I've found that C99 is my absolute favorite C iteration. It's a black sheep and normalfags all seem to hate half of what it brought to the table like VLAs. Half of the interesting (to me) quirky little things I read about in C came in C99. I don't care if I'm never a pro at this. just getting these things to work and see the correct output on my computer is entirely rewarding enough.
>>8813 So since I'm relatively satisfied with the way the core up there has turned out (I did make a couple tweaks after posting that code, like moving the fseek function up so I didn't have to lock in the size of the first array), I went ahead and moved on to the next step. Directory operations are very similar to file operations, and with all my recent reading and experience I banged this out in about 30 minutes. # include <stdio.h> # include <stdlib.h> # include <unistd.h> # include <string.h> # include <math.h> //Include the Directory tools # include <dirent.h> int main() { //This code opens a directory and reads off a list of files within //Create a DIRECTORY pointer named Directory and point it to our destination DIR *Directory = opendir("./network/Alice"); //Call the default struct from the tools and make a pointer to it struct dirent *Dname; //Make an integer variable to count the files in the dir int filecount = 0; //Make a variable for the random offset in the file list int randfile; //Standard file check if (!Directory){ puts("Invalid directory."); return(1); } else{ //Read the dir file by file until we hit NULL while ((Dname = readdir(Directory)) != NULL){ //Only show actual files and not symlinks or '.' '..') if (Dname->d_type == DT_REG) { //Print the d_name variable from the struct, which contains the filename printf("%s\n", Dname->d_name); //Each time we loop, increment the filecount variable by 1 filecount++; } } } printf("\nFile count was %i", filecount); //Now we check if the file count was positive and pick one at random if (filecount > 0){
[Expand Post] randfile = rand() % filecount; //Print the random number to verify printf("\nRandom offset is %i", randfile); } else{ puts("Error generating random offset"); return(1); } printf("\n\n\n"); closedir(Directory); return(0); } Works great, but now I'm stuck. What I want to do is choose a file from the directory at random. I was hoping to use the filecount and rand() function to generate an offset that would define the nth file in the directory, which I could grab with some sort of fseek()-like function for directory reading. And it doesn't seem like any such function exists! So what the hell should I do with this? Use a FOR loop to read through the dir and stop on the nth, and put that filename into a variable? Seems wasteful. Suggestions are welcome. I tried a quick search for "C select file at random" and got a bunch of hits for C++ shit for Windows systems but nothing that would help me here.
Well I kept working at it solo and have started forming a solution. This isn't finished yet (it sucks, actually), but its a working piece of progress. Instead of the nice FILE-like DIR operations, I picked up a new tool called scandir() and learned how to use it instead. This sweeps the directory and puts the file data into an array of structs for us. Then we pull a (really bad) random number out of our ass and read the d_name value from that struct in the array. It works well, but its shit. I need to exclude the '.' and '..' directory elements from the results somehow, and also get srand() working for a better random number selection. Scandir has some sort of filtering mechanism that can be invoked, but I need to study that more. #include <stdlib.h> #include <stdio.h> #include <dirent.h> #include <string.h> #include <sys/dir.h> int main(){ //Call up the default struct from dirent, but this time we set an array pointer to it struct dirent **namelist; //Some variables we'll need int n; //Scandir returns the number of files it sees, so we'll put those in n. You need the explicit '&' here n = scandir("./network/Alice", &namelist, NULL, alphasort); //Timing is important. Now, AFTER we know n, we can use it to generate a random number x int x = rand() % n; //Error checking if (!namelist){ puts("Error reading directory!"); return(1); } //Let's see which file out random number gives us. Remember, name the ARRAY and then the piece of the STRUCT inside else{ printf("%s", namelist[x]->d_name); } //Handy way to see the file count too printf("\n\nFile count was %i", n); //Free that hogged up memory free(namelist); printf("\n\n\n"); return 0; } What's interesting about using an array pointer here, that took me a minute to figure out, is that the "array" called namelist actually has a copy of the whole default dirent struct in each element! That could wind up being a good chunk of memory. Now scandir will malloc all the memory you need for this automatically, but we have to remember to FREE it when we're done.
>>8839 yes i also know how to use a man page
Now it works how I wanted it to. I admit that this is a bit of a hack, but considering I can control the final directory structure of the program I'm tempted to call this section "good enough" for now and to worry about learning to use qsort() later. I also renamed a lot of things here to avoid collisions in the code later on. #include <stdlib.h> #include <stdio.h> #include <dirent.h> #include <string.h> #include <sys/dir.h> #include <time.h> int main(){ //Call up the default struct from dirent, but this time we set an array pointer to it struct dirent **randpage; //Some variables we'll need int numpages; /*Scandir returns the number of files it sees, so we'll put that number in "pages". You need the explicit '&' here, and we sort the data alphabetically.*/ numpages = scandir("./network/Alice", &randpage, NULL, alphasort); /*Timing is important. Now, AFTER we know n, we can use it to generate a random number x. First we seed the randomness with srand based on the system time, and then we calculate a random number between 2 and the number of files -1. This is because the array counts from 0-n and we want to ignore elements 0 and 1 to get rid of the '.' and '..' directories. We set the upper random number bound to n-1 to keep pick=101 (max) from reading out of bounds*/ srand(time(0)); int randupper = numpages-1; int randlower = 2; int pick = (rand() % (randupper-randlower+1)+2); //Error checking if (!randpage){ puts("Error reading directory!"); return(1); } //Let's see which file our random number gives us. Remember, name the ARRAY and then the piece of the STRUCT inside else{ printf("%s", randpage[pick]->d_name); } //Handy way to see the file count and random number too printf("\n\nFile count was %i, random number was %i", numpages, pick); //Free that hogged up memory free(randpage); printf("\n\n\n"); return 0; }
>>8839 Your program is leaking memory. >>8855 int randupper = numpages-1; int randlower = 2; int pick = (rand() % (randupper-randlower+1)+2); If the directory is empty this will crash. Your program is still leaking memory.
>>8866 For once I had already figured something out before you said it. Though I'm curious if I'd need to free all the elements of (Current) as well, since its just a string and not an array of structs. #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <dirent.h> #include <string.h> #include <sys/dir.h> #include <time.h> int main(){ //Call up the default struct from dirent, but this time we set an array pointer to it. struct dirent **pages; //Some variables we'll need. int numpages; //Make a Char pointer variable to hold the current working directory. char *Current = getcwd(NULL, 0); /*Scandir returns the number of files it sees, so we'll put that number in "pages". You need the explicit '&' here, and we sort the data alphabetically.*/ numpages = scandir("./network/Alice", &pages, NULL, alphasort); /*Timing is important. Now, AFTER we know numpages, we can use it to generate a random pick. First we seed the randomness with srand based on the system time, and then we calculate a random number between 2 and the max number of files -1. This is because the array counts from 0-n and we want to ignore elements 0 and 1 to get rid of the '.' and '..' directories. We set the upper random number bound to n-1 to keep pick=101 (max) from reading out of bounds.*/ srand(time(0)); int randupper = numpages-1; int randlower = 2; //This is how many directories ('..') to ignore. int pick = (rand() % (randupper-randlower+1)+2); //Error checking if (!pages){ puts("Error reading directory!"); return(1); } //We make sure there are usable pages in the directory, since elements 1 and 2 don't count. else if(numpages <= randlower){ puts("This pad is out of usable pages!"); return(1); } //Print the current working directory. printf("Current directory is:\n%s\n\n", Current);
[Expand Post] /*Create a character pointer variable to hold the filename. Don't forget to specify that we want to point out (->) the d_name from the struct.*/ char *Pick = (pages[pick]->d_name); //Let's see which file our random number gave us. printf("Selecting random keyfile %s", Pick); //Handy way to see the file count and random number too. printf("\n\nFile count was %i, random number was %i", numpages, pick); //Free that hogged up memory. //Elements first. for(int i=0; i<numpages; i++){ free(pages[i]); } //Then the array itself. free(pages); //And the array holding the working directory. free(Current); printf("\n\n\n"); return 0; }
>>8867 >Though I'm curious if I'd need to free all the elements of (Current) as well, since its just a string and not an array of structs. No, that wouldn't make any sense. Each element in the string is basically an integer, not a pointer. >its just a string and not an array of structs. Technically you've never used an array of structs, only an array of pointers. Try to make a drawing of the memory layout to understand it properly if it's confusing. Then post it so that we can bully you.
>>8870 I mean, in the struct dirent **pages line I'm dereferencing a pointer twice. I suppose it'd be more explicit to say I'm "looking at a pointer that's looking at a pointer that's pointing into an array of structs", but is the pages array created by scandir() not an array of structs? The official literature is a little obtuse as to the structure of the memory segment that scandir() creates.
>>8867 >int pick = (rand() % (randupper-randlower+1)+2); what is this shit its like this idiot pick = rand() % ((randupper+1) - (randlower-1));


Forms
Delete
Report
Quick Reply