/t/ - Technology

Discussion of Technology

Index Catalog Archive Bottom Refresh
Mode: Reply
Options
Subject
Message

Max message length: 8000

Files

Max file size: 32.00 MB

Max files: 5

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

E-mail
Password

(used to delete files and postings)

Misc

Remember to follow the rules

The backup domain is located at 8chan.se. .cc is a third fallback. TOR access can be found here, or you can access the TOR portal from the clearnet at Redchannit 2.0.

Please be aware of the Site Fallback Plan!
In case outages in Eastern Europe affect site availability, we will work to restore service as quickly as possible.

WE ARE PLANNING THE 2.8 SITE UPGRADE FOR THIS WEEKEND, MONDAY EVENING 6-27. DOWNTIME WILL BE BRIEF, AND THEN WE HUNT FOR BUGS.
(Estamos planeando la actualización del sitio 2.8 para este fin de semana, del lunes 6 al 27 por la tarde o por la noche en CST. El tiempo de inactividad será breve y luego buscaremos errores.)


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

Board Nuking Issue should be resolved. Apologies for any missing posts.

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.
>>8600 I'll give you that we finally got you to write somewhat legible code, but you have so so many errors with basic concepts it's baffling. >No compiler warnings from this build, either. That's actually remarkable. I originally wrote my post calling you out but I ended up testing it and it's true. I could have sworn the compiler would have been able to catch some of the bugs, like //Set up input storage array. char userinput[1800]; //Set up the input math array int userascii[strlen(userinput)]; But I guess gcc doesn't give a damn about variable-length arrays anymore and passing uninitialized memory as a parameter is valid (even though it's a const argument, awkward). Still it's smart to stay away from VLAs. There's also stuff like int testarr[3] = {'c', 'a', 't'}; for(int i=0; i<10; i++){ xor[i] = ((userascii[i])^(testarr[i])); } and all the int conversions and other issues. I think it may be a good idea to brush up on the theory of how things work because otherwise you're just going to stumble problems you won't be able to explain all the time and it's going to be uphill and hard to learn things like that.
>>8609 >That's actually remarkable. Yeah I was sure it wasn't going to work, but thought "maybe I'm just crazy" and it worked. I can only assume the compiler understood what I was trying to do, and did it. One thing I should point out. First is that I'm not taking any kind of class for this, and there's nobody I can ask questions of. I'm totally on my own apart from the commentary ITT, and I have no idea what the proper "conventions and etiquette" for this sort of thing is. What I'm doing is learning how each tool works from the literature, doing a few small book examples with each, and then applying the tools together using logic. I don't care if its normal or efficient (yet), only if it works and doesn't cause errors or fuck something else up. That it functions as intended. You've mentioned it twice so I really want to ask you, what is wrong with this? Excuse my poor ASCII art skills. Char array [Q][W][E][R][T][Y][/0] -v---v---v--v--v--v [Q][W][E][R][T][Y]*snip* -v---v---v--v--v--v Int array [81][87][69][82][89] |-------measure-----| > into variable empty int array, how big? [0][0][0][0][0] > same as variable Random file going into empty array #!@#$$%^$%%^&^%&*^&*\0 |-------measure-----| > same as variable [!][@][#][$][%]*snip* = [33][64][35][36][37] Xor function [81][87][69][82][89] --^----^---^---^----^ [33][64][35][36][37] I don't doubt that it looks odd to an actual experienced programmer (more steps than needed, I'm 100% sure of that), but I don't see where there's a flaw in the logic.
>>8610 >I don't care if its normal or efficient (yet) For efficiency, you'll want to eliminate creating a new array for every step. I'm sure it's easier to parse when you loop over, copy, and convert, but you can just cast your char* to a uint8_t* and read them as numbers. As long as you know the first location of a null-terminator, you're fine. And the null terminator is a literal 0, so you can identify it. No other character in a char array will be exactly 0. You should also be considerate of bounds safety. memcpy is widely considered insecure, although the most popular replacement is Microsoft's memcpy_s, which can also be unsafe. With the proper checks, memcpy and strcpy are perfectly safe, but you must be certain you are not reading unintended portions of memory or writing outside of the intended bounds. The biggest place to be careful of this is on user input. You are letting users pass in some data. You should not trust this data. What happens if the data is oversized? Undersized? Can be turned into instructions? It's always good to pass junk data to a program and see how it handles it. You will learn a lot about accepting input if you treat user input as adversarial.
>>8610 >Yeah I was sure it wasn't going to work, but thought "maybe I'm just crazy" and it worked. I can only assume the compiler understood what I was trying to do, and did it. That's the thing, it didn't work. It's undefined behavior left and right, and it's working by pure chance. You really need to understand what each line you type means and does. I thought you were following some books, if you're not then there are pages like tutorialspoint and some others that hold your hand and walk you step by step through all the language features so that you don't do stuff like //Set up input storage array. /*1*/ char userinput[1800]; //Set up the input math array /*2*/ int userascii[strlen(userinput)]; where (1) defines a region of 1800 bytes with basically random data in it and (2) goes over each byte of the random data trying to find the first byte with value zero in order to get the size of the region of data you're then defining. It doesn't make any sense. What you wanted is the sizeof operator. It's not a function, it's an operator and works at compile time (vs. strlen() which executes at runtime), which is another key C concept. >ASCII art skills >in an imageboard shiggydiggy If I understood what you're trying to say you don't understand why converting and xoring the int arrays is bad. In your case it's useless and risks introducing surprising type conversions which can leave even an experienced developer scratching their head from time to time. What you're not seeing is that for instance, your '!' (=33) in your int array, is actually 4 bytes now: if little endian: {33, 00, 00, 00} if big endian: {00, 00, 00, 33} You think you're xoring a simple '!' (1 byte with value 33) but you're not. It may work because you're working with ASCII stuff which is always 'positive' 8-bit integer values, but eventually you'll fuck it up. It's a lot of risk for doing something in a way that, when you understand what's going in, is very nonintuitive, has a performance penalty on top of it, and doesn't do anything you couldn't have done before.
>>8609 >>8612 >where (1) defines a region of 1800 bytes with basically random data in it and (2) goes over each byte of the random data trying to find the first byte with value zero in order to get the size of the region of data you're then defining. It doesn't make any sense. Well we agree there. I didn't think it made sense when I did it, lol >What you wanted is the sizeof operator. It's not a function, it's an operator and works at compile time (vs. strlen() which executes at runtime), which is another key C concept. Haven't played with sizeof() yet, I'll look into that. >It may work because you're working with ASCII stuff which is always 'positive' 8-bit integer values', but eventually you'll fuck it up. It's a lot of risk for doing something in a way that, when you understand what's going in, is very nonintuitive, has a performance penalty on top of it, and doesn't do anything you couldn't have done before. That right there was why I decided to do it this way, since I had the pieces on hand to try. I think maybe we're not disagreeing, but that I'm trying to work within my current limitations on knowledge and you're wondering why I'm not dumping this to do it a better way. Its a bit like I'm riding my bike across town because I haven't learned to drive a car yet, and don't feel like waiting until I can before I just go get some ice cream. I just want two arrays with nice, clean ASCII values in them to math up, and this was the shortest way (within what I know) to get there. My gut already knows its convoluted, but that isn't the point, if that makes sense. I do have a follow question though. Concerning what you said about the ASCII int value of "!" on the endians, can you explain that a bit more? I know an integer VARIABLE occupies 4 bytes (on a 32 or 64 bit machine) but I wasn't yet aware that applied to arrays.
>>8613 As a followup, would C not allocate 4 bytes of memory to each element in an INT array by default then? Or should I presume that the side of the second array should be something more like sizeof(userinput)*4? Was that why you mentioned an overflow issue some posts back?
>>8614 because youre talking to a larper retard, there is no overflow, read a fucking c standard ffs the size of standard datatypes are not fucking defined because it doesnt fucking matter when youre reading and writing with the SAME type, how fucking dumb are you why do you think you have to fucking DECLARE the type of a variable BEFORE using it you fucking imbecile you think thats for the computer thats for the fucking compiler idiot, are you even fucking reading your shitty c books, its hilarious how youre obsessing over the most stupid and insignificant things when you cant even declare your shit properly fucking look at this shit //Set up input storage array. char userinput[1800]; //Set up the input math array int userascii[strlen(userinput)]; unsigned int xor[strlen(userinput)]; userinput is fucking EMPTY strlen( userinput ) = 0, those arrays are [0] in size, if you wanted 1800 then just fucking write 1800, if you want dynamically sized memory then fucking ALLOCATE memory you retard instead of putting trash on the stack and stop treating everything like a fucking string, you fucking pytards are always the same you cant understand anything that isnt a string because you cant comprehend the fact that it isnt fucking real
>>8613 >I just want two arrays with nice, clean ASCII values in them to math up, and this was the shortest way (within what I know) to get there Nigger you did this part just fine previously, see >>8576 Something that I don't think you understand is how types work. 0x30 (character '0') in char, short, int, uint64, etc., is 0x30. You can print it in hex, binary, decimal, octal, or some other base and it's just a matter of interpretation of the same value. 30 (hex) = 48 (decimal) = 60 (octal) = 110000 (binary). The underlying representation of the value changes, and that's important in many cases, but you don't need an int array to read the ASCII value of a char. >Concerning what you said about the ASCII int value of "!" on the endians, can you explain that a bit more? On multi-byte integer types the representation of the values can be either big endian or little endian depending on which one of those bytes is the least significant, that is, if you have a multi-byte integer variable with value 1, where the 1 is written within the memory of the variable. If it's written in the lowest memory address it's little endian and if it's written in the highest memory address then it's big endian. For a 4 byte integer type with an assigned value of 1 the memory layout may look like: //Little endian: ADDRESS | 0 | 1 | 2 | 3 | ----------------------------------------- VALUE | 1 | 0 | 0 | 0 | //Big endian: ADDRESS | 0 | 1 | 2 | 3 | ----------------------------------------- VALUE | 0 | 0 | 0 | 1 | >I know an integer VARIABLE occupies 4 bytes (on a 32 or 64 bit machine) but I wasn't yet aware that applied to arrays. Technically integer size is defined as 'at least 2 bytes' if I remember correctly. There are architectures where it's 2, 4, or 8, or whatever. But don't worry about it for now. Arrays are just a region of contiguous memory (no gaps in between each element) that can hold a given number of copies of a given type. int intArray[3]; //it can hold 3 elements of type int, the total size in bytes of the memory area of the array is 3*sizeof(int) char charArray[3]; //it can hold 3 elements of type char, the total size in bytes of the memory area of the array is 3*sizeof(char) >>8614 >would C not allocate 4 bytes of memory to each element in an INT array by default then? Yes >should I presume that the side of the second array should be something more like sizeof(userinput)*4? Yes, if you declare it properly with sizeof instead of strlen(). >Was that why you mentioned an overflow issue some posts back? That was in relation to this >>8576 for(int i=0; i<1800; i++){ fscanf(Ciphertext, "%d", &cipher[i]); } Each element in cipher is 1 byte long and you're telling fscanf() to put a 4 bytes long integer in it. It's going to overflow each element and that's going to work (given that you have a contiguous memory area because it's an array) until it runs out of bounds near the end of the array. The solution to this is to read properly using the right size specifier instead of getting a bigger memory area. Because your machine is little endian the lowest memory address is going to be written by fscanf(), and then you move to the next memory address and it seems to work. If the machine were big endian the biggest memory address would be written by fscanf(), and then overwritten in the next iteration.
So just going back and playing with this some more, and I'm stumped. I realized that I had probably two approaches to unfucking this after the endian issue and char vs int element structure differences were helpfully explained. >Either do everything as chars and figure out how to negate the read cuttoff caused by the terminator. >Or do everything as ints and negate the extra byte space in each element somehow. I considered something like xor[i] = (input[i]^key[i])-'0'); or some variation of that idea for the second option, but because I felt less confident I decided to try unfucking it with char arrays first. # include <stdio.h> # include <stdlib.h> # include <unistd.h> # include <string.h> # include <math.h> //Set a global variable k to contain strlen(userinput) long unsigned int k; int main() { //Set up input storage array. char userinput[1801]; //Set up the input math array char key[1801]; unsigned char xor[1801]; //Take the user's text input. printf("Enter your text.\n"); fgets(userinput, 1800, stdin); userinput[strlen(userinput)-1] = '\0'; //Now that the proper strlen has been set, we define the global variable k k = strlen(userinput); printf("\nYour text was:\n'%s' , with length %lu", userinput, k); printf("\n\nEnter your key.\n"); fgets(key, 1800, stdin); key[strlen(key)-1] = '\0'; printf("\nYour key was:\n'%s' , with length %lu", key, strlen(key)); //=====================================BEGIN MATH============================== //Alright, now let's try xoring. printf("\n\nNow let's try to XOR and store\n"); for(int i=0; i<=k; i++){ xor[i] = ((userinput[i])^(key[i])); } printf("Printing contents of the XOR array. I hope this works\n\n"); for(int i=0; i<=k; i++){ printf("%d ", xor[i]); } return 0; } And this just... magically works? Apart from skipping the superfluous ASCII value readbacks I feel like I was doing this exact thing before and running into the null terminator issue. I ran this just to make sure the prints were giving me correct feedback before I dealt with the 0s issue and it just... works. No early termination, reflects 0s in the xor result properly. I set the read limitation for fgets as one byte smaller than the arrays. What the fuck is going on?
>>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"); 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]); } 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]); } } 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. >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.


Forms
Delete
Report
Quick Reply