/t/ - Technology

Discussion of Technology

Index Catalog Archive Bottom Refresh
Options
Subject
Message

Max message length: 8001

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.

SHOOT GUNS, EAT BURGERS, BE RACIST! IT'S AMERICA DAY!

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.
(53.07 KB 700x921 Lain third eye.gif)

Starting off we're going to look at the basic bitch C syntax. C is a pretty verbose language IMO - it asks you to do a lot of declaring and specifying, but I guess that's one of the reasons its so versatile. >Things to know: 'int' stands for integer, but despite the fact that we think of integers as numbers, C can treat almost any character as an integer, including letters. 'float' is what you use for a short number with decimal points 'double' stands for "double-float", a long number with decimal points 'printf' stands for "print - formatted" and is the standard output stream. Coming from BASIC not just using 'print' triggered me at first. 'scanf' is "scan-formatted" which takes inputs from the linux console. C supports all of the common programming actions, like 'do' 'while' 'for' etc. C is a little different that the core of it lacks all but the most absolute basic functionality. Even just printing to the console requires loading external libraries - notably 'stdio', for "standard input and output." C is an old language and there are many default libraries that it comes with, and many many many more that people have written, allowing you to do almost anything you can imagine. For the purpose of learning I'm using a linux PC running Ubuntu, and a C "Integrated Desktop Environment" or programming panel, called CODE::BLOCKS that was available right from the repositories. To use it you'll first want to install the gcc compiler and all the default Linux code building tools by installing the 'build-essential' package. This is an all-in-one "compile things in C" package that gives you everything you need. I'm using Code::Blocks because I like being able to just click a button to test-run my code, instead of compiling it by hand and running it manually every time I play with it. Assuming you're doing as I'm doing, go ahead and install 'build-essential' and 'Code::Blocks' and then fire up the latter. >Pick your compiler (GNU-gcc) >Click "Create a New Project" >Pick "Console Application" - this is a basic program that runs in the command line >Choose C for your language, not C++ >Give it a title and pick/make a folder to keep it in >Leave the defaults on the Compiler page and click next Now the IDE will open. In the tree on the left you'll see Workspace - (Filename) - Sources. Doubleclick the Sources folder and you'll see 'main.c'. That's our code page. Doubleclick it to open it in the editor and you're in business. Notice how it already has some code in it? Every default main.c that you open for the first time will contain the old-fashioned "Hello World!" program. Well we're going to write our own, so delete that shit off the page. So from what we've learned studying the books, there's a few things to do here. First since we want to print shit in the console we need to call the stdio library. Default libraries like stdio are built-in and have meme arrows around them. Also you don't close 'include' lines with a semicolon ; like you do normal code lines. Something to remember. C uses doubleslashes '//' for comments, or you can make a comment block by sandwiching a block of text between '/*' and '*/' //Let me use the fucking console output # include <stdio.h> Now we have to tell the thing where the program starts. That's what the 'int main' function does. It says "here's the fucking code so run it." It requires a parenthises because C fucking said so, but if there's nothing important to put in there you can leave it blank, or if you're a good boy you can put the word VOID at the start of the line to make the value explicitly empty. int main(void) After this you open a curly bracket { to start the block of code. Remember to close it at the end }. Everything runs in between these. Now the program will run and is looking for stuff to do. We can call the 'printf' command to tell it to print something in the console. Because we're now writing actual code, remember to end each function with a semicolon ; or the program will trip over its own feet. Text strings go inside of quotes "" which go inside of parenthises (). This is pretty standard programming stuff. Just remember Program{ command("say stuff/do stuff");
[Expand Post]} So we want this: //Call me a faggot printf("Yer a faggot anon"); Now we want the program to stop and not freeze up right there so we need to tell it that it's done. There's 2 ways to do this. Either put a carriage return in the print function, or just add a line that tells it to stop. The first way looks like this: printf("Yer a faggot anon\n"); The \ is an escape character that tells the compiler that the next letter isn't a letter, but a mini-command or macro. The 'n' in C stands for "new line", AKA a carriage return. This is all in the books. If you don't like that way and want to be more specific, you can skip that and just add one more line to the program: return 0; Or you can do both, as the Code::Blocks example did. Anyway here's the finished product. #include <stdio.h> int main(void){ printf("Yer a faggot anon"); return 0; } Now try it out. At the top of the Code::Blocks screen is a topbar. Right in the middle are 3 options, 'Build', 'Run', and 'Build and Run'. This is why we're using an IDE even though we're in baby mode. Click Build and Run and watch the convenience of your program running instantly. It'll check your code for fuckups and typos too, and tell you if you did anything wrong.
(1.57 MB 1280x720 FOXHOUND.png)

Next I took an example lesson from the C book - a small program that takes your inputs and mirrors them back to you. We already know that we need to start with a couple things. //We're using the console for inputs and outputs so # include <stdio.h> //and we need to tell the compiler that we're running code int main(void) { So following the lesson in the book I modified it slightly. So since we're not just DOING a thing, but rather TAKING a thing (your input) and STORING it for a sec so we can make the console read it back, we need to declare a variable to store it in. You don't have to do anything fancy yo declare a simple variable, just put its type on a new line along with your made up variable name and end it with a semicolon ; int WORDS; Yeah we're gonna call it an integer. Text is an integer according to C, which is one of the weird things about it. Now we want to grab your text inputs from the console, so we use the 'getchar' command. As the name implies this command will GET any entered CHARacters so you can do stuff with them, like storing them in that variable up there. Then we'll use the 'putchar' command to PUT those CHARacters from the variable to the console output. The book uses a WHILE command do to this, that way the program keeps going after the first thing it grabs. As long as you keep typing, it'll keep running. Now C will freak out if you give it code that has NO way to stop, so we have to add a "knock it off" condition to make it happy. We're just going to tell it to stop if it receives an "end of file" signal, called EOF. This is both a linux thing and a C thing, so it will understand that perfectly well. # include <stdio.h> int main(){ //declare a variable int WORDS; while ((WORDS = getchar()) != EOF) putchar (WORDS);} In english: "Store stuff in WORDS. The stuff you will store in WORDS is whatever is typed in via the 'getchar' command, and then as long as WORDS does not have an 'end of file' signal, you will put the contents of WORDS back onto the screen." Now I looked at the code and decided this was boring, so I wanted to squeeze in some text for flavor. In a C program, code lines are always executed in order from top to bottom, and I figured as long as a simple, one-line command wasn't interrupting in the middle of anything else then the program should just do it. Well it worked. I added a printf() line to the code right at the beginning, including a \n for a carriage return, to give the user (you) a prompt for what to type. # include <stdio.h> int main(void){ printf("Type the word NIGGER over and over\n"); //declare a variable to store the shit you type int WORDS; //Put your inputs into the variable and spit them back out to you, until you hit EOF while ((WORDS = getchar()) != EOF) putchar (WORDS); } Give it a try by hitting "Build and Run" like before. This was all I did for today, but there'll be more coming. I'm hoping to go through a lesson every day, and I'll play with it and post about it here.
(2.94 MB 1535x2302 Ed0S234UcAA-Eb6.jpeg)

I'm a bit rushed for tonight's exorcise, but I wanted to try and do something from memory, without using a book example as a starter. This will serve as a baseline for a more advanced thing later. How about a very simple physics equation: Momentum. Mass times velocity, so we're just multiplying two inputted numbers. Now I did cheat a tiny bit and looked up how to use the 'scanf' command properly before I did this, but at least I was smart enough to know I'd be using it. First we call the standard IO and also the standard library, which has the basic math tools in it. #include <stdio.h> #include <stdlib.h> Plus our standard int main(){ Then we declare three variables. Because we aren't getting fancy yet, we're going to use integers with no decimal points. You can declare multiple variables in a single line using comma separation. int mass, vel, momentum; We print the instruction for what to do, just like in the above examples printf("Input mass and velocity\n"); Now we want to use scanf to take the inputs and assign them to the variables. For each variable that scanf will use, you declare it in the line using a % sign and the first letter of the type, which is integer, so they look like '%i', and you spell out which variables to use by flagging them with an ampersand &. scanf(%i %i, &mass, &vel); Then we just want to take those and multiply them, and put the answer into our last variable, 'momentum'. Fortunately C understands basic math symbols like +, -, *, and /. momentum=(mass*vel); And then we make it spit out the answer. printf("Momentum is %i", momentum); C's format is a little unintuitive (at least to me) because of how it reads. That printf line there, in english, says "Type "Momentum is VARIABLE", thisvariablereplacesVARIABLE" You have to do this little dance of variables and terms, but once you understand how to think in the right order, I find it begins to come more naturally. Here's the final program. I forgot the site has code tags, so let's see how this looks. #include <stdio.h> #include <stdlib.h> int main(){ //Two variables for 2 numbers and one for the answer int vel, mass, momentum; //Ask for those values printf("Input mass and velocity\n"); //Put the mass and vel values into their variables scanf("%i %i", &mass, &vel); //Set the 'momentum' variable to be the product of those two variables momentum=(mass*vel); //Spit out the momentum variable after the math is done printf("Momentum is %i", momentum); //Tell the program its finished return 0; } Remember to wear your programming socks.
(283.52 KB 640x480 Ryoko closed.png)

So last night after I signed off I was still getting triggered by the sloppy simplicity of my previous example, so I cleaned it up and did it right, as if it were an actual tool to be used. #include <stdio.h> #include <stdlib.h> int main(){ //Two variables for 2 numbers and one for the answer float vel, mass, momentum; //Ask for the mass printf("Input mass kg\n"); //Put the mass value into its variable scanf("%f", &mass); //Ask for the velocity printf("Input velocity m/s\n"); //Put the velocity value into its variable scanf("%f", &vel); //Set the 'momentum' variable to be the product of those two variables momentum=(mass*vel); //Spit out the momentum variable after the math is done printf("Momentum is %f kg-m/s", momentum); //Tell the program its finished return 0; } You'll noticed that I changed the variable types from 'int' to 'float', meaning that they can be decimal numbers as a typical calculation of this type would require. This meant changing the variable entries further down from '%i' -for integer, to '%f' - for float. I also split up the variable requests with new printf and scanf lines, and changed the text to specify the SI values for entry and result. The final product is something you could actually use. Tonight I'm going to spice it up a bit and continue going from my brain and not the book. We did momentum, but what about the more important kinetic energy? You might remember from basic science class that KE is equal to half the mass times the velocity squared. We already know how to do basic multiplication from the previous example, so let's hammer it out. //Basic setup # include <stdio.h> # include <stdlib.h> int main(){ //We're going to declare our variables. float mass, vel, power, ke; //Ask for the mass and store it printf ("Input mass kg\n"); scanf ("%f", &mass); //Ask for the velocity and store it too printf ("Input velocity m/s\n"); scanf ("%f", &vel); //We multiply the velocity times itself to square it. You could also just say (0.5*mass*vel*vel) below and skip this power=(vel*vel); //We put the result of the math into the variable ke=(mass*0.5*power);
[Expand Post] //And we make it spit out the result printf ("Kinetic Energy is %f Newtons", ke); //And wrap it up return 0; } You could really make this handy by doing the math under an 'if' statement that makes sure neither of the variables are zero, too. //Basic setup # include <stdio.h> # include <stdlib.h> int main(){ //We're going to declare our variables. float mass, vel, power, ke; //Ask for the mass and store it printf ("Input mass kg\n"); scanf ("%f", &mass); //Ask for the velocity and store it too printf ("Input velocity m/s\n"); scanf ("%f", &vel); //We make the math conditional on the variables being positive using a simple 'if' statement and the logical 'and' operator '&&' if (mass>0 && vel>0) { //In english this says "if mass is greater than 0 AND vel is greater than 0, THEN {dostuff //We multiply the velocity times itself to square it. You could also just say (0.5*mass*vel*vel) below and skip this power=(vel*vel); //We put the result of the math into the variable ke=(mass*0.5*power); //And we make it spit out the result printf ("Kinetic Energy is %f Newtons", ke); } //We close the 'if' statement from above with a } //And we tell if what to do if the 'if' statement was NOT met, i.e. one of the variables is 0 else printf("Variables cannot be zero"); //And wrap it up return 0; } I wrote this from memory like the last one, but fucked it up the first time because I forgot to declare my variables with the ampersands '&'. The program ran but the answer was always 0. Won't make that mistake again!
And one more before the night is up. Since I'm on an elementary physics kick here's one for constant acceleration. Same principles apply. A=dv/dt but since we're constant its simplified to A=dV/t. # include <stdio.h> # include <stdlib.h> int main() { float vi, vf, t, accel; //Process initial velocity printf("Input initial velocity m/s\n"); scanf("%f", &vi); //Process final velocity printf("Input final velocity m/s\n"); scanf("%f", &vf); //Get time period printf("Over what time period? (seconds)\n"); scanf("%f", &t); //Do math and spit out answer if(t>0){ accel=((vf-vi)/t); printf("Acceleration is %f meters per second, per second", accel); } else printf("Time value cannot be zero"); return 0; } We're going places now.
Here's another one for the middle of the day. Simple displacement in one dimension. #include <stdio.h> #include <stdlib.h> int main(){ //Displacement calculation = vf = vit+1/2At^2 //Declare variables float vi,d,t,a,x,y; //Ask for and store variables printf("Input initial velocity m/s\n"); scanf("%f", &vi); printf("Input acceleration ms/s\n"); scanf("%f", &a); printf("Input Time (seconds)\n"); scanf("%f", &t); //Calculate vit x=(vi*t); //calculate 1/2ATsquared y=((0.5*a)*(t*t)); //Add them up d=(x+y); printf ("Distance moved in one dimension is %f meters", d); return 0; } And tinkering with a little bit more complex one for some basic rotational energy calculations. #include <stdio.h> #include <stdlib.h> int main(){ //Rotational inertia is angular momentum divided by angular velocity //I=L/W, L=mrv, and W=anglef-anglei/t
[Expand Post]float L, W, m, r, I, ai ,af, t; //Ask for inputs and store them printf("Input mass kg\n"); scanf("%f", &m); printf("Input initial angle\n"); scanf("%f", &ai); printf("Input final angle\n"); scanf("%f", &af); printf("Input radius (meters)\n"); scanf("%f", &r); printf("Input time in seconds\n"); scanf("%f", &t); //Calcular angular velocity W=((af-ai)/t); printf("Angular velocity is %f \n\n", W); //calculate angular momentum L=(m*r*W); printf("Angular momentum is %f \n\n",L); //calculate rotational inertia I=(L/W); printf("Rotational inertia is %f\n",I); return 0; } When I get these to all be the way I want, I think I'll try to do something cute with them.
Alright I wanted to do something spicy and try to make a semi-useful tool out of this. So I combined all the functions into a single program, and tried to set up a menu system where you could select which function to use. It was a disaster, but I didn't give up. First I tried enclosing the program in a loop and assigning variables whose letter value would decide the program, but the whole thing would just run from top to bottom and skip all the scanf inputs. I'm still diagnosing why that was. Then I tried using 'if (opt!==a||b||c) to limit the choice of variables, but the syntax was all wrong. First time I've really stumbled at writing from my head since I started. Well on the third try I figured it out. Then I introduced a simple numeric value check to limit the menu options, removed the 'return 0;'s in the subroutines and used good old BASIC 'goto' with C's label system to let the program loop until the user is finished with it. I'm sure it's a bit crude, but I'm tickled that it works. Take a look. # include <stdio.h> # include <stdlib.h> int main(){ int opt; top: printf("\n\n Choose one: 1: Kinetic Energy, 2: Momentum, 3: Acceleration, \n 4: Displacement, 5: Rotational Inertia, 0: Exit\n"); scanf("%i", &opt); if (opt>5){printf("Invalid option\n"); goto top;} if (opt==1){ float mass, vel, power, ke; printf ("Input mass kg\n"); scanf ("%f", &mass); printf ("Input velocity m/s\n"); scanf ("%f", &vel); if (mass>0 && vel>0) { power=(vel*vel); ke=(mass*0.5*power); printf ("Kinetic Energy is %f Newtons", ke); } else printf("Variables cannot be zero"); goto top; } if (opt==2) { float vel, mass, momentum; printf("Input mass kg\n"); scanf("%f", &mass); printf("Input velocity m/s\n"); scanf("%f", &vel); momentum=(mass*vel); printf("Momentum is %f kg-m/s", momentum); goto top;; } if (opt==3) { float vi, vf, t, accel; printf("Input initial velocity m/s\n"); scanf("%f", &vi); printf("Input final velocity m/s\n"); scanf("%f", &vf); printf("Over what time period? (seconds)\n"); scanf("%f", &t); if(t>0){ accel=((vf-vi)/t);
[Expand Post]printf("Acceleration is %f meters per second, per second", accel); } else printf("Time value cannot be zero"); goto top;; } if (opt==4) { float vi,d,t,a,x,y; printf("Input initial velocity m/s\n"); scanf("%f", &vi); printf("Input acceleration ms/s\n"); scanf("%f", &a); printf("Input Time (seconds)\n"); scanf("%f", &t); x=(vi*t); y=((0.5*a)*(t*t)); d=(x+y); printf ("Distance moved in one dimension is %f meters", d); goto top; } if (opt==5){ float L, W, m, r, I, ai ,af, t; printf("Input mass kg\n"); scanf("%f", &m); printf("Input initial angle\n"); scanf("%f", &ai); printf("Input final angle\n"); scanf("%f", &af); printf("Input radius (meters)\n"); scanf("%f", &r); printf("Input time in seconds\n"); scanf("%f", &t); W=((af-ai)/t); printf("Angular velocity is %f \n\n", W); L=(m*r*W); printf("Angular momentum is %f \n\n",L); I=(L/W); printf("Rotational inertia is %f\n",I); goto top; } if (opt==0){printf("Exiting program\n"); return 0;} }
I'm personally not interested in the thread itself since I develop in C/C++ for a living already but if you need help with something I'll try to be around. >>8336 Now refactor that mess into functions, change the ifs to a switch, and change the goto to a regular loop. Also properly indent your shit and use proper brace placement.
>>8338 Yeah I just dumped the raw code from the compiler to my post as soon as it ran right. Cleaning up is always the next step. I notice that my own conventions held over from other programming are a bit different than mainstream C programs use. I like to denote the closing brackets of subroutines after a doublespace, and save newline closing brackets for major routines and the overall program. I also never intent, as I was taught that horizontal stretching makes code annoying to read, and that it's better to use your comments on newlines to show sub-function flow. Granted I learned all of this 25 years ago, but its still comfy. I'll post a cleaned up rendition later.
>>8341 Honestly this program is a great candidate to spend a few days refining into a proper program architecture. After you got everything properly compartmentalized into functions you could move that into a separate library that only contains the calculations and leave the GUI (I/O) in an executable that links against the library. Then you can create a second program that performs unit testing on the calculations library. It'll probably all be very counter intuitive if you're new but that's usually how you want to structure things in bigger projects.
>>8342 That sounds like something I'll do then. That sounds like what we used to call "branching programs" back in the day, where you have a master routine that calls your actual functions from inside independent libraries and otherwise only handles the i/o and maybe error handling. I usually consider that a more advanced way of doing things (for bigger programs), but its definitely on my list to master later. My next project is pretty ambitious (for me, at this stage) and that's to recreate my favorite pet project Visual BASIC program from 1999 - a physics auto solver for equations of motion. It gives you a bunch of options to punch in whatever variables you start with, and then uses those to compute every variable that's missing from across the whole system. It was my first year college programming project for my final exam, and now I want to do it again in C. I'm thinking I'll need to use arrays to hold all the variables and store the outputs so I'm studying that now. I'm also laughing at the modern rage over 'goto' statements that I'm seeing on the Internet holy shit. Even back in my day they were frowned upon because of spaghetti but its like the world went schizo over them, but we were taught some simple rules for them to avoid the mess. >Never set a goto target that jumps UP the program unless its for a large loopback, and all such jumps must use the same target (I used this above). >You may use a goto one time for your main error handling function >You may use up to three gotos for large jumps in the code, but only for up to your three largest and very commonly used subroutines. >You may use a goto one time to jump out of a large, nested function IIRC the reason it was like that was so that somebody following your work could have those routines open in a couple windows 98 and easily reference your progress without going insane. The whole point was to keep the code readable. C is actually easier for this because of the labeling, as you don't have to worry about screwing up your line number references or leaving lots of blank lines for modifications like with BASIC. I'm having fun.
>>8343 Just how old are you exactly? god damn. >I'm also laughing at the modern rage over 'goto' statements that I'm seeing on the Internet holy shit Yes, there's a lot of outrage over goto, but honestly goto is redundant in all but like two scenarios. The most widely used case is function cleanup because C doesn't have RAII, so it's just very useful and clean to write the cleanup to a function once and just jump there from everywhere in your function that can fail. This pattern is used extensively in well known libraries. Other than that I don't even remember other specific instances where using goto was the best choice for what I wanted to do. >spoiler I also have fun at work
>>8344 Old enough that I first touched VB on a Windows 95 machine that I upgraded from Win 3.1 with a pile of floppies just a week or two before. Same box had AutoCAD Lt on it which I used to learn drafting. A few years later I did more serious coding on a state of the art Windows 98 machine with a thirty gigabyte hard drive. If you want to know how long I've used Linux, I started in whatever year the Storm Linux distro came out in. If you want to know how long I've used computers, look up when TurboGopher was brand new. Depending on where you live I also might have banged your mom.
Man the books on arrays and pointers all read like useless gobbledygook. I get the basic idea of what they are, but the explanations all read like Geordi La Forge writing a technical manual while high on meth, and its unnecessary. >An array stores a set of variables or the discreet characters of a string within a series of adjacent memory blocks ordered from 0 to n+1. A pointer is a pseudo-variable that lets you 'point' at data based on that data's memory block location. How fucking hard was that, really? First test program for fucking with arrays. A simple take on the earlier Momentum program, but this time we store the inputs in an array, generate the answer, store the answer in an array, and then print the content of the array to spit out the answer. Ignore the comment block in the middle, it was just a reminder to myself of what variables I'll ultimately be using. # include <stdio.h> # include <stdlib.h> int main(){ //Lets try an array for storing variables, remember it needs to be slots+1 big for the hidden \0 end char float vars[3]; float answers[2]; /*mass=vars[0] vel=vars[1] accel=vars[2] force=vars[3] time=vars[4] vi=vars[5] vf=vars[6]*/ //Ask for mass printf("Input Mass in kg\n\n"); //Store the inputs in the first slot of the vars[] array scanf("%f", &vars[0]); //Ask for velocity printf("Input total Velocity in m/s\n\n"); //Store the velocity value in the second slot of the vars[] array scanf("%f", &vars[1]); //Quick print check, show us what was stored in those slots to make sure this is working printf("Mass was %f, Velocity was %f \n\n\n", vars[0],vars[1]); //Multiply the stored values and set the result to be the value of the first block in the answers[] array answers[0]=(vars[0]*vars[1]); //Spit out the contents of the first block of the answers[] array printf("Momentum is %f", answers[0]); //Finish and exit return 0; } And because I said I would, here's a cleaned up version of the combination program. I'm going to leave it like this as a sort of self-milestone, but I may write a much nicer one from scratch later just for fun.
[Expand Post] # include <stdio.h> # include <stdlib.h> int main(){ int opt; //goto target for restart loop start: //Menu controls printf("\n\n Choose Solver: 1: Kinetic Energy, 2: Momentum, 3: Acceleration, \n 4: Displacement, 5: Rotational Inertia, 0: Exit\n"); scanf("%i", &opt); //Error on invalid menu selection if (opt!=0 && opt!=1 && opt!=2 && opt!=3 && opt!=4 && opt!=5){ printf("Invalid option, try again\n"); goto start; } //Kinetic Energy subroutine if (opt==1){ float mass, vel, power, ke; printf ("Input mass kg\n"); scanf ("%f", &mass); printf ("Input velocity m/s\n"); scanf ("%f", &vel); if (mass>0 && vel>0) { power=(vel*vel); ke=(mass*0.5*power); printf ("Kinetic Energy is %f Newtons", ke); } else printf("Variables cannot be zero"); goto start; } //Momentum subroutine if (opt==2) { float vel, mass, momentum; printf("Input mass kg\n"); scanf("%f", &mass); printf("Input velocity m/s\n"); scanf("%f", &vel); momentum=(mass*vel); printf("Momentum is %f kg-m/s", momentum); goto start; } //Acceleration subroutine if (opt==3) { float vi, vf, t, accel; printf("Input initial velocity m/s\n"); scanf("%f", &vi); printf("Input final velocity m/s\n"); scanf("%f", &vf); printf("Over what time period? (seconds)\n"); scanf("%f", &t); if(t>0){ accel=((vf-vi)/t); printf("Acceleration is %f meters per second, per second", accel); } else printf("Time value cannot be zero"); goto start; } //Displacement subroutine if (opt==4) { float vi,d,t,a,x,y; printf("Input initial velocity m/s\n"); scanf("%f", &vi); printf("Input acceleration ms/s\n"); scanf("%f", &a); printf("Input Time (seconds)\n"); scanf("%f", &t); x=(vi*t); y=((0.5*a)*(t*t)); d=(x+y); printf ("Distance moved in one dimension is %f meters", d); goto start; } //Angular Momentum and Rotational Inertia subroutine if (opt==5){ float L, W, m, r, I, ai ,af, t; printf("Input mass kg\n"); scanf("%f", &m); printf("Input initial angle\n"); scanf("%f", &ai); printf("Input final angle\n"); scanf("%f", &af); printf("Input radius (meters)\n"); scanf("%f", &r); printf("Input time in seconds\n"); scanf("%f", &t); W=((af-ai)/t); printf("Angular velocity is %f \n\n", W); L=(m*r*W); printf("Angular momentum is %f \n\n",L); I=(L/W); printf("Rotational inertia is %f\n",I); goto start; } //Close the program when prompted if (opt==0){ printf("Exiting program\n"); return 0; } }
>>8346 thanks for the input anon that's pretty helpful
>>8346 >//Lets try an array for storing variables, remember it needs to be slots+1 big for the hidden \0 end char That only applies for strings. The rationale is that without the terminating null, there's no way to know how long a string (character chain) is without having additional metadata stored somewhere, which C is obviously not going to do for you.
>>8351 Thanks, I didn't realize that. Do you suppose you could tell me what the syntax is for taking command line arguments in the int main(arc char* argv[]) startup function? I can't find a reference example that uses more than one. Does the number need to be assigned, like int main(argc=5, argv[5])? Or to put the question simply, if I have seven command line arguments, then what does that line need to look like?
>>8352 The prototype should be: int main(int argc, char *argv[]); The prototype is always the same. argc gives you the number of command line arguments. There's always at least 1, which is the path to the executable. Each position in argc gives you a pointer, which points to the argument's string. You could do something like: #include <stdio.h> int main(int argc, char *argv[]) { printf("your arguments were:\n"); for(int count=0; count<argc; count++) { printf("\t%d: %s\n", count, argv[count]); } return 0; } This is the gist of it. Double check as I'm going from memory.
>>8344 >Other than that I don't even remember other specific instances where using goto was the best choice for what I wanted to do. You need goto to break out of nested loops in C and C++ for (int x = 0; x < 100; x++) for (int y = 0; y < 100; y++) { // Do stuff if (shouldExit(data[x][y])) // break; <- only breaks out of the inner most loop (the one incrementing `y`) goto loopEnd; } loopEnd: Without goto your other options are to use a bool and check it on every level if the loop should break and in C++ you can use an immediately invoked lambda where the goto is replaced with a return statement.
>>8355 Fair enough. I don't think I've ever run into that scenario but I remember scratching my head before about how to break out of a loop that had a switch inside.
this is fucking trash, go back to scripting in pyshit, c isnt for retards that dont even know how pointers work or for video games or retarded man children that still watch chinese cartoons and play with childrens toys and """""VIDYAhueheuehue"""" go pick up a handicap accessible language like pyshit or c++ for your vidya you mentally disable man child # include <stdio.h> # include <stdlib.h> float mass,vel,accel,mom,vi,vf,t,L,W,m,r,I,ai,af,a; float (*func)(); float L() { return mass*0.5*(vel*vel); } float O() { return mass*vel; } float S() { return (vf-vi)/t; } float E() { return (vi*t) + ((0.5*a)*(t*t)); } float R() { static int i = -1; switch (i++) { case 0: W=(af-ai)/t; return W; case 1: L=(m*r*W); return L; case 2: i=0; return (L/W); } } void main() { int select = 0; while ( select >= 0 && select < 5 ) { printf("\n\n Choose Solver: 1: Kinetic Energy, 2: Momentum, 3: Acceleration, \n 4: Displacement, 5: Rotational Inertia, 0: Exit\n"); scanf("%d", &select ); select--; void *vars[5][8] = { { (int*)2, &mass, &vel }, { (int*)2, &mass, &vel }, { (int*)3, &vi, &vf, &t }, { (int*)3, &vi, &a, &t }, { (int*)5, &m, &r, &ai ,&af, &t} }; char out[5][8][128] = { {"Kinetic Energy is %f Newtons", "Input mass kg\n", "Input velocity m/s\n"}, {"Momentum is %f kg-m/s", "Input mass kg\n", "Input velocity m/s\n"}, {"Acceleration is %f meters per second, per second", "Input initial velocity m/s\n", "Input final velocity m/s\n", "Over what time period? (seconds)\n"}, {"Distance moved in one dimension is %f meters", "Input initial velocity m/s\n", "Input acceleration ms/s\n", "Input Time (seconds)\n" }, {"Angular velocity is %f \n\nAngular momentum is %f \n\nRotational inertia is %f\n", "Input mass kg\n", "Input initial angle\n", "Input final angle\n", "Input radius (meters)\n", "Input time in seconds\n"} }; void *funcs[5] = { L,O,S,E,R }; for ( int i=1; i<=*(int*)(vars[select]); i++ )
[Expand Post] { printf( "%s", out[select][i] ); scanf( "%f", vars[select][i] ); } func = funcs[select]; printf( **(out + select), func(),func(),func() ); } }
>>8371 this loser >>8346
(94.88 KB 700x924 a1oWEqP_700b.jpg)

Right now I'm going through K&N C. I'm still a beginner to programming, as I've only taken the first year courses that you do in college (but in the pajeet language), so I have a ways to go. I'll stick with you anons and update with some of my own learning experiences as well.
>>8371 >Declaring function pointers for the subroutines, using a switch case for selecting the correct function for the user choice and then calling it Makes sense. I can't wing that yet but at least I can follow it. But in your haste to be a dick you forgot to make your code compile. Take a look at the first function and your switch case 1, and that isn't all.
>>8371 Here, I fixed it for you. # include <stdio.h> # include <stdlib.h> float mass,vel,accel,mom,vi,vf,t,L,W,m,r,I,ai,af,a; float (*func)(); float B() { return mass*0.5*(vel*vel); } float A() { return mass*vel; } float S() { return (vf-vi)/t; } float E() { return (vi*t) + ((0.5*a)*(t*t)); } float D() { static int i = -1; switch (i++) { case 0: W=(af-ai)/t; return W; case 1: L=(m*r*W); return L; case 2: i=0; return (L/W); } } void main() { int select = 0; while ( select >= 0 && select < 5 ) { printf("\n\n Choose Solver: 1: Kinetic Energy, 2: Momentum, 3: Acceleration, \n 4: Displacement, 5: Rotational Inertia, 0: Exit\n"); scanf("%d", &select ); select--; void *vars[5][8] = { { (int*)2, &mass, &vel }, { (int*)2, &mass, &vel }, { (int*)3, &vi, &vf, &t }, { (int*)3, &vi, &a, &t }, { (int*)5, &m, &r, &ai ,&af, &t} }; char out[5][8][128] = { {"Kinetic Energy is %f Newtons", "Input mass kg\n", "Input velocity m/s\n"}, {"Momentum is %f kg-m/s", "Input mass kg\n", "Input velocity m/s\n"}, {"Acceleration is %f meters per second, per second", "Input initial velocity m/s\n", "Input final velocity m/s\n", "Over what time period? (seconds)\n"}, {"Distance moved in one dimension is %f meters", "Input initial velocity m/s\n", "Input acceleration ms/s\n", "Input Time (seconds)\n" }, {"Angular velocity is %f \n\nAngular momentum is %f \n\nRotational inertia is %f\n", "Input mass kg\n", "Input initial angle\n", "Input final angle\n", "Input radius (meters)\n", "Input time in seconds\n"} }; void *funcs[5] = { B,A,S,E,D };
[Expand Post] for ( int i=1; i<=*(int*)(vars[select]); i++ ) { printf( "%s", out[select][i] ); scanf( "%f", vars[select][i] ); } func = funcs[select]; printf( **(out + select), func(),func(),func() ); } } Now back to my own learning.
Is there any way to automate the process of creating and compiling a C program in linux? Like, I know it only involves two commands, but can I just script something in order to automate it into one? Also, is there any noteworthy difference between gcc and cc usage wise?
>>8389 >automate builds Makefiles. >gcc versus cc I think cc might be just the compiler on its own. gcc is a driver that compiles, links, and assembles a final binary. You can do those steps yourself, of course.
>>8389 Honestly, for small programs I don't think it's worth doing anything else outside of maybe a script that executes the commands you want. There's also makefiles and bigger projects are going to have those but personally I hate them and try to avoid them. There's also CMake, which creates the makefiles for you using a language that looks more like a regular procedural script, but that's adding yet another abstraction which outside of learning sounds like a lot of trouble for just a single source file or two. >difference between gcc and cc usage wise? You can have multiple (C) compilers in your system (e.g. clang and gcc) and cc will be a symbolic link to whichever one you prefer, however you can still access each compiler by the full name, which is what 'gcc' does.
OP here. I'm still learning but life has been getting in the way this week. I'm uploading a few more resources that I've began studying. The first is "Learn C The Hard Way" which is a very nuts-and-bolts, no bullshit volume that assumes you already have some basic programming skills. I'm finding it more useful than the R&K guide now. The other is "The Small C Handbook" which talks about a minimalist version of C, Small C, that is used in embedded systems and old 8/16 bit CPUs. There's some neat stuff in there. Lastly is Expert C Programming Secrets, a sort of tips and tricks guide to doing fancy shit that the basic manuals don't cover. I've moved to an interesting project to generate a miniature encrypted message program, written in C and targeted for Linux. It's challenging me in a few ways, including using the system call, reading and writing to multiple files, and running external scripts from within the program. It's very fun!
And just for laughs, a copy of C For Dummies that I've used a few times like a pocket reference.
Just toying around with various functions and some libraries. I've been too busy to do anything serious, but I wanted to get a better feel for loops and conditionals that I haven't used yet. So here's this. #include <stdio.h> #include <stdlib.h> #include <unistd.h> int main(void){ //Count niggers from 1-60 int i=0; while (i<60){ printf("NIGGER!\n"); //Pause one second between outputs sleep(1); i=i+1; } //When the counter hits 60, announce it if (i=60){ printf("SIXTY NIGGERS"); } return 0; } And adding a reverse check with an appropriate theme. #include <stdio.h> #include <stdlib.h> #include <unistd.h> int main(void){ //Count niggers from 1-60 int i=0; while (i<60){ printf("NIGGER!\n"); //Pause one second between outputs sleep(1); i=i+1; } //When the counter hits 60, announce it if (i==60){ printf("SIXTY NIGGERS!\n\n"); } //Set up the Mark detector int answer; int c=40; printf("Now is Mark around? y/n \n"); scanf("%s", &answer);
[Expand Post]if (answer == 'y'){ puts("Mark stole 40 cakes. Forty cakes! Here we go...\n\n"); sleep(2); //New loop counting down while (c>0){ puts("Mark ate a cake\n"); sleep(1); c=c-1; } if (c==0){ puts("Time to steal another cake!"); } }else{ //If the answer was anything but 'y' for yes puts("Hah, gassed em."); return 0; } } You'll note swapping in PUTS for printf in the second example. Puts functions like printf but adds an automatic carriage return and has some other small differences. I've also found that my brain doesn't like the += or i++/-- style increment/decrement operators. Too much BASIC in there to want to see anything but i = i+1 style, but maybe I'll get over that as time goes on. Anyway, nothing fancy this week, I'm just trying to get back into my "write at least a little piece of code every night" routine.
(68.77 KB 388x429 asd.png)

>>8463 >encrypted message program like this #include <stdio.h> #include <stdlib.h> #define terminal system void main() { int8_t mssg[128] = "->SECRET MESSAGE INSIDE<-"; int64_t cipher[128] = { 0x6e69206b20726f66,0x6f66206f643b2a20,0x24206e6920692072, 0x2052312d20736c28,0x2d20706572677c7e,0x5d3a5e5b2f27206f,0x74206f643b29272a, 0x692422206863756f,0x2452454747494e2f,0x3b656e6f643b226b,0x656e6f6420, 0 }; int (*print)() = terminal; int8_t *out = (int8_t*)mssg, *in = (int8_t*)cipher; while( *in != 0 ) *out++ = *in++; *out = 0; print( mssg ); }
Do not run this code
>>8477 That's just mean. Do not run this. lol
>>8478 >>8479 What does it even do?
>>8477 >#define terminal system <Do not run this code >User codexx warned the posters of the following posts: 8477 from board /t/ with reason "Don't post malicious code". I'm still laughing the next day. Honestly pretty creative.
>>8483 It'll fill your whole filesystem up with blank files named nigger.c. It's a funny prank until you remember that linux has a maximum inode count that could make this brick your computer if its runs long enough.
Back to work playing with strings and arrays tonight. First I was figuring out how to explicitly declare an array to be empty, which turns out to be simple enough. Then I wanted to be able to take text from the user, put it into an array, and then prove that I could manipulate each element of the array (1 single character from the text) one at a time. # include <stdio.h> # include <stdlib.h> # include <unistd.h> # include <string.h> int main(){ //Declare an array with 1,800 elements, the size of a standard page char user_input[1800] = {}; //Take text input from the console and store it in the array puts("Enter some text, faggot"); fgets(user_input, 1800, stdin); //Cut out the newline characters from fgets() because they make our shit misbehave user_input[strlen(user_input) -1] = '\0'; //We loop through the array from beginning to some point, here we go 30 elements deep for (int i=0; i<30; ++i){ //And on each loop we print the single character from that element, one by one printf("Here's your plaintext back one at a time faggot '%c'\n", user_input[i]); } exit(EXIT_SUCCESS); } If you input a short sentence, like "fags are gay" you'll notice that it also preserves the spacing between words as it prints the string characters line by line. I confess to stealing the strlen concatenation idea from an online example - I didn't think of that one myself. I actually failed to make this work several times, as simple as it looks, because I still misunderstood some things about arrays and pointers and declaring them correctly. What I thought I needed to do here was quite a bit harder than what I actually needed to do. I need to re-hit the books on that. For something interesting, try removing the "= {}" part from the array declaration, and then run the program and type a short word. You'll see that without declaring the array explicitly empty, it prints your string like it should, but then other garbage shows up further down.
>>8501 >char user_input[1800] = {}; That's retarded. Either initialize it to some explicit value or leave it uninitialized. If you compile with -Wpedantic you'll see: trash.c:10:25: warning: ISO C forbids empty initializer braces [-Wpedantic] 10 | char user_input[1800] = {}; | ^ The reason it misbehaves if you don't initialize the array is because you're ignoring the end of string null character that fgets puts there so you move on to the uninitialized territory (which is technically undefined behavior). Just test whether the current array position contains the '\0' and stop printing there, or even better, catch the strlen() return from earlier and just print until strlen()-1. Also get the syntax right already you dumb nigger, that's a part of learning too and submissions like this would not be accepted anywhere. Having retarded syntax is why >>8477 is difficult to detect, but that guy made it on purpose to be clever and you're doing it because you're a nigger.
(103.39 KB 762x1048 look at the time.jpg)

Continuing to play with the same ideas. # include <stdio.h> # include <stdlib.h> # include <unistd.h> # include <string.h> int main(){ //Declare an array with 1,800 elements, the size of a standard page char user_input[1800] = {}; //Take text input from the console and store it in the array puts("Enter some text, faggot"); fgets(user_input, 1800, stdin); //Cut out the newline characters from fgets() because they make our shit misbehave user_input[strlen(user_input) -1] = '\0'; //We loop through the array from beginning to some point, here we go 10 elements deep for (int i=0; i<10; i++){ //And on each loop we print the single character from that element, one by one //We use 2 data types, %c for the char and %d for its ASCII value and look at the array twice //Note the SINGLE quotes '' around them when dealing with CHARs!! printf("Here's your plaintext back as text and ASCII: '%c' '%d' \n", user_input[i], user_input[i]); } //Pause before asking next question sleep(1); //Now ask for a key word puts("Enter some key text"); char key[1800] = {}; fgets(key, 1800, stdin); key[strlen(key) -1] = '\0'; for (int i=0; i<10; i++){ printf("Key entered was '%c' with ASCII value '%d' \n", key[i], key[i]); } sleep(1); //Now we add the values of the 2 arrays together puts("Adding the arrays together and storing the results in a new array"); //We have to specify this array as type UNSIGNED char, or else the numbers will roll back negative unsigned char cipher[1800] = {}; for (int i=0; i<10; i++){ cipher[i] = ((user_input[i])+(key[i])); printf("Cipher of input and key is '%d', '%d' = '%d' \n", user_input[i], key[i], cipher[i]); } return 0; }
[Expand Post]It took me a bit to figure out the ASCII value reversal that was pushing my original answers negative, but it turned out to be because an array of type 'char' is explicitly assumed to be signed (either + or -) and reverses after reaching 127 because that's standard ASCII's cutoff value. At first I thought it was counting modulo 128, but the values still wouldn't be correct. >Just test whether the current array position contains the '\0' and stop printing there, or even better, catch the strlen() return from earlier and just print until strlen()-1. I'll have to look at that. Thanks.
Taking it one more step tonight. Using XOR on the input and key to generate an actual cipher, and then testing reversing the XOR operation, using the key, to recover the user_input value. And it works! # include <stdio.h> # include <stdlib.h> # include <unistd.h> # include <string.h> # include <math.h> int main(){ //Declare an array with 1,800 elements, the size of a standard page char user_input[1800] = {}; //Take text input from the console and store it in the array puts("Enter some text, faggot"); fgets(user_input, 1800, stdin); //Cut out the newline characters from fgets() because they make our shit misbehave user_input[strlen(user_input) -1] = '\0'; //We loop through the array from beginning to some point, here we go 10 elements deep for (int i=0; i<10; i++){ //And on each loop we print the single character from that element, one by one //We use 2 data types, %c for the char and %d for its ASCII value and look at the array twice //Note the SINGLE quotes '' around them when dealing with CHARs!! printf("Here's your plaintext back as text and ASCII: '%c' '%d' \n", user_input[i], user_input[i]); } //Pause before asking next question sleep(1); //Now ask for a key word puts("Enter some key text"); char key[1800] = {}; fgets(key, 1800, stdin); key[strlen(key) -1] = '\0'; for (int i=0; i<10; i++){ printf("Key entered was '%c' with ASCII value '%d' \n", key[i], key[i]); } sleep(1); //Now we add the values of the 2 arrays together puts("Adding the arrays together and storing the results in a new array"); //We have to specify this array as type UNSIGNED char, or else the numbers will roll back negative unsigned char cipher[1800] = {}; for (int i=0; i<10; i++){ cipher[i] = ((user_input[i])+(key[i])); printf("Cipher of input and key is '%d', '%d' = '%d' \n", user_input[i], key[i], cipher[i]); } sleep(2); //Let's try XORing (^) them now //Remember if A = B xor C then to get back B you can do C xor A
[Expand Post] unsigned char xor[1800] = {}; for (int i=0; i<10; i++){ xor[i] = ((user_input[i])^(key[i])); printf("Xor of input and key is %d \n", xor[i]); } sleep(2); //And now we reverse the Xor to get the input value back unsigned char decrypt[1800] = {}; for (int i=0; i<10; i++){ decrypt[i] = (xor[i]^key[i]); printf("Decrypted user input values are %d \n", decrypt[i]); } return 0; //We have the basic building blocks of a simple encryption/decryption program }
>>8510 the cpu can do 32 8bit xors in a single cycle idiot # include <stdio.h> # include <stdlib.h> # include <unistd.h> # include <string.h> # include <math.h> int main(){ //Declare an array with 1,800 elements, the size of a standard page char user_input[1800] = {}; //Take text input from the console and store it in the array puts("Enter some text, faggot"); fgets(user_input, 1800, stdin); //Cut out the newline characters from fgets() because they make our shit misbehave user_input[strlen(user_input) -1] = '\0'; //We loop through the array from beginning to some point, here we go 10 elements deep for (int i=0; i<10; i++){ //And on each loop we print the single character from that element, one by one //We use 2 data types, %c for the char and %d for its ASCII value and look at the array twice //Note the SINGLE quotes '' around them when dealing with CHARs!! printf("Here's your plaintext back as text and ASCII: '%c' '%d' \n", user_input[i], user_input[i]); } //Pause before asking next question sleep(1); //Now ask for a key word puts("Enter some key text"); char key[1800] = {}; fgets(key, 1800, stdin); key[strlen(key) -1] = '\0'; for (int i=0; i<10; i++){ printf("Key entered was '%c' with ASCII value '%d' \n", key[i], key[i]); } sleep(1); //Now we add the values of the 2 arrays together puts("Adding the arrays together and storing the results in a new array"); //We have to specify this array as type UNSIGNED char, or else the numbers will roll back negative unsigned char cipher[1800] = {}; for (int i=0; i<10; i++){ cipher[i] = ((user_input[i])+(key[i])); printf("Cipher of input and key is '%d', '%d' = '%d' \n", user_input[i], key[i], cipher[i]); } sleep(2); //Let's try XORing (^) them now
[Expand Post] //Remember if A = B xor C then to get back B you can do C xor A unsigned char xor[1800]; memset( xor, 0, 1800 ); __asm__ ( ".byte 0x0f,0x05;" "mov $90, %%rax;" "xor %%rsi, %%rsi;" ".byte 0x0f,0x05;" "vmovdqu %1, %%ymm0;" "vmovdqu %2, %%ymm1;" "vpxor %%ymm1, %%ymm0, %%ymm1;" "vmovupd %%ymm0, %2;" :: "a"(79), "m"(cipher), "m"(xor),"D"(xor), "S"(1800) ); unsigned char *out = xor; while( *out != 0 ) printf("Xor of input and key is %d \n", *out++); sleep(2); //And now we reverse the Xor to get the input value back unsigned char decrypt[1800] = {}; for (int i=0; i<10; i++){ decrypt[i] = (xor[i]^key[i]); printf("Decrypted user input values are %d \n", decrypt[i]); } return 0; //We have the basic building blocks of a simple encryption/decryption program }
Still working on building blocks. Tonight I worked on storing text from the user into an array and then writing the contents of the array to a textfile. I was trying to do this via fprintf(), but I didn't manage to get it to like any of what I fed it. It would either instantly crash out with return 0 leaving a blank output file, or would segfault. I'm still diagnosing that, but I shifted gears to using fputs() instead and got the idea working. Tonight was the first time I used C to output anything to an external file instead of running internally to the program. Baby steps for sure, but it's fun. # include <stdio.h> # include <stdlib.h> # include <unistd.h> # include <string.h> # include <math.h> int main(void){ //Initialize array with 1800 elements (1 standard page) char user_input[1800] = {0}; //Prompt for input and store it in the array, trimming off the newline at the end printf("Enter text\n\n"); fgets(user_input, 1800, stdin); user_input[strlen(user_input) -1] = '\0'; //Create a FILE pointer variable named Output, and make it call fopen() on our destination file. "w" means "write" FILE *Output = fopen("/home/my_user/test.txt", "w"); //Do a quick check to make sure the file opens properly (if it fails the file will be NULL) if(Output == NULL) { printf("File Error!"); exit(1); } else{ //Use fputs() to write contents of the user_input array to the file pointer variable, and thus to the file by proxy. fputs(user_input, Output); //Give the user a little confirmation message. puts("\n\nFile write successful."); } return 0; }
>>8542 protip: if you've got to hardcode something, try to do it in only one place. This minimizes failure points as then things cannot become desynchronized and break and it's easier to improve your code as you only need to change one place. Put your hardcodes where it's visible. Also if you've got to hardcode something do not use mere immediate values, assign them to something that has a name. This not only adds readability but also allows you to highlight occurrences and use search functions. #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <math.h> int main(void) { const char outputFileLocation[] = "/home/my_user/benis.txt"; //Initialize array with 1800 elements (1 standard page) enum { sizeUserInput = 1800 }; char user_input[sizeUserInput] = {0}; //Prompt for input and store it in the array, trimming off the newline at the end printf("Enter text\n\n"); fgets(user_input, sizeUserInput, stdin); user_input[strlen(user_input) -1] = '\0'; //Create a FILE pointer variable named Output, and make it call fopen() on our destination file. "w" means "write" FILE *Output = fopen(outputFileLocation, "w"); //Do a quick check to make sure the file opens properly (if it fails the file will be NULL) if(Output == NULL) { printf("File Error!"); exit(1); } else { //Use fputs() to write contents of the user_input array to the file pointer variable, and thus to the file by proxy. fputs(user_input, Output); //Give the user a little confirmation message. puts("\n\nFile write successful."); } return 0; } This also helps you to parametrize things. If you later want to move things to a standalone function then you remove the hardcodes and add them as regular parameters instead and if you did things right then it should work without you needing to redo large portions of your code.
>>8548 Roger that. I really do listen to the advice I'm getting, I just can't learn without the "fumbling through things until it just works" stage. Once I have an idea finished, I'll revisit it several times to redo sections of it properly, memorizing conventions and techniques as I go. Just being able to stare at this thread and retrace my own mental steps and anon's comments about them is a huge asset. Tonight I focused on two things. First I insisted on getting fprintf() to work like it was supposed to, and second I decided to take the first step in combining some of the building blocks. # include <stdio.h> # include <stdlib.h> # include <unistd.h> # include <string.h> # include <math.h> int main(void){ //Initialize arrays with 1800 elements (1 standard page) each char user_input[1800]; char key[1800]; unsigned char xor[1800]; char plain[1800]; //Create a FILE pointer variable named Output, and make it call fopen() on our destination file. "w" means "write" FILE *Output = fopen("/home/my_user/ciphertext.txt", "w"); //Prompt for input and store it in the array, trimming off the newline at the end printf("Enter text\n\n"); fgets(user_input, 1800, stdin); user_input[strlen(user_input) -1] = '\0'; printf("Entry complete.\n\n"); //Wait 1 seconds before next prompt sleep(1); //Now ask for a key text puts("Enter a key at least as long as your text\n\n"); fgets(key, 1800, stdin); key[strlen(key) -1] = '\0'; printf("Key entry complete. Processing.\n\n"); sleep(1); //Now we XOR the input text with the key for (int i=0; i<1800; i++){ xor[i] = ((user_input[i])^(key[i])); } printf("Outputting encrypted text to file. \n"); sleep(1); //Do a quick check to make sure the file opens properly (if it fails the file will be NULL)
[Expand Post] if(Output == NULL){ printf("File Error!"); exit(1); } else{ for (int i=0; i<1800; i++){ fprintf(Output, "%d\n", (unsigned char)xor[i]); } } //Give the user a little confirmation message. puts("\n\nFile write successful.\n"); sleep(1); //Test quick decryption by XORing the xor and key arrays again printf("Test - Reversing encryption...\n\n"); for (int i=0; i<1800; i++){ plain[i] = ((xor[i])^(key[i])); printf("%c", plain[i]); } sleep(1); //We print the array contents from xor[] to verify the textfile is accurate printf("\n\nShowing contents of the xor array\n\n"); for (int i=0; i<1800; i++){ printf("%d", xor[i]); } //Close the output file and quit. fclose(Output); return 0; } I know its pedantic, but I like sleep()s lol. I want to breathe in between bursts of text and have a second to consider what I'm looking at.
>>8549 >printf("%d", xor[i]); Integers don't make sense for ciphertext, you want the raw hex value. Use >printf("%02X", xor[i]); or alternatively >printf("0x%02X", xor[i]); >puts("Enter a key at least as long as your text\n\n"); Look into pseudo random number generators. Basically it'd be slightly more realistic to ask the user for a seed, and generate the key yourself from that seed using an algorithm. Since it's pseudo random (and not true random), the values are dependent on the seed, so the same seed will always generate the same byte sequence and you'll be able to re-generate the key for decryption if the user gives you the same seed. C (actually POSIX) has a simple built in PRNG that's good for dumb proof of concepts like these. You call srand() once with the seed you get from the user, and then you call rand() as many times as you need to get your key to xor with the message. That's about it. Try it out. And also properly indent your shit.
>>8550 Printing the string elements as doubles just uses the ASCII value integers, which was what I wanted. That's what I was testing in the first stage proof of concept here >>8510 Is there some reason the hex values would be better? Because this is targeted at Linux, and because the whole project is just an excuse to play with as many different C elements as I can, the final version will actually use a system() call to output haveged-boosted dev/random into a keyfile which will eventually get read into the key[] array. It's more like a one-time-pad, in terms of execution. So what IS the proper, by-the-book indenting "style" anyway?
>>8552 >Printing the string elements as doubles The %d specifier prints as decimal, not doubles. >uses the ASCII value integers Get an ASCII table that has the values in hex. Usually they have the values in both bases. >Is there some reason the hex values would be better? Because the information you're trying to see is not really integers so it's a lot more difficult to see patterns in the data. In hex you can see the difference between a single flipped bit super easily but in a decimal representation it'll be a completely different number altogether with no apparent relationship to the previous one, not even in number of digits. If something is not right with your algorithm it'll stick out in the hex, the decimal will be just gibberish. >It's more like a one-time-pad, in terms of execution Fair enough. Usually that's not how commercial encryption works but if that's the way you want to go so be it. >So what IS the proper, by-the-book indenting "style" anyway? The golden rule is that if there's a brace, there must be a new indentation level. I think this is always respected no matter what style. Other than that, some people put the opening brace on the next line and some people on the same line, but the latter are niggers in my opinion.
Alright, I'm getting somewhere now. I figured out reading files into arrays with pretty minimal fuss, worked on my indenting style, and cleaned up some things. Then I started combining more building blocks. What started as a dozen pieces is now three, and here are the first two. This program will take your user inputs, store them in text files, xor them, and give you the output as a textfile named ciphertext.txt. # include <stdio.h> # include <stdlib.h> # include <unistd.h> # include <string.h> # include <math.h> int main(void){ //Initialize arrays with 1800 elements (1 standard page) each char user_input[1800]; char key[1800]; unsigned char xor[1800]; //Create 2 FILE pointers, both in write mode, one for the cipher and one for the key FILE *Cipher = fopen("/home/my_user/ciphertext.txt", "w"); FILE *Keyfile = fopen("/home/my_user/keyfile.txt", "w"); //Prompt for input and store it in an array printf("Enter text\n\n"); fgets(user_input, 1800, stdin); user_input[strlen(user_input) -1] = '\0'; printf("Entry complete. Size was %lu\n\n", strlen(user_input)); //Wait 1 seconds before next prompt sleep(1); //Now ask for a key text printf("Enter a key at least as long as your text\n\n"); fgets(key, 1800, stdin); key[strlen(key) -1] = '\0'; printf("Key entry complete. Key length was %lu. Processing.\n\n", strlen(key)); //Output the key[] array to its textfile if(Keyfile == NULL){ printf("Keyfile Write Error!"); exit(1); } else{ int k = strlen(key); for (int i=0; i<k; i++){ fprintf(Keyfile, "%d ", (char)key[i]); } //Give the user a little confirmation printf("Your key has been saved to keyfile.txt.\n\n"); }
[Expand Post] sleep(1); //Now we XOR the input text with the key for (int i=0; i<1800; i++){ xor[i] = ((user_input[i])^(key[i])); } printf("Calculating XOR. XOR length is %lu. Outputting encrypted text to cipher.txt. \n\n", strlen(xor)); sleep(1); //Do a quick check to make sure the file opens properly (if it fails the file will be NULL) if(Cipher == NULL){ printf("Cipher File Write Error!"); exit(1); } else{ //Set a variable k to the actual length of the stored string so it doesn't print all the garbage too int k = strlen(xor); for (int i=0; i<k; i++){ fprintf(Cipher, "%d ", (unsigned char)xor[i]); } //Give the user a little confirmation message. printf("Your encrypted text has been saved as cipher.txt.\n\n"); } //Now we need to read from the files and put them into new arrays, but we'll write new code for that. //Close the Cipher and Keyfile files and quit. fclose(Cipher); fclose(Keyfile); return 0; } And as the comment I left at the bottom implies, here is a program to read a ciphertext file and a keyfile, XOR them, and then give you the resulting decrypted message in a new output file called plaintext.txt. # include <stdio.h> # include <stdlib.h> # include <unistd.h> # include <string.h> # include <math.h> int main(void){ //Initialize arrays with 1800 elements (1 standard page) each unsigned char key[1800]; unsigned char cipher[1800]; char plain[1800]; //Create 3 FILE pointers for each of the cipher, key, and output plaintext files. "r" means "read" FILE *Ciphertext = fopen("/home/my_user/ciphertext.txt", "r"); FILE *Keyfile = fopen("/home/my_user/keyfile.txt", "r"); FILE *Plaintext = fopen("/home/my_user/plaintext.txt", "w"); //We read the ciphertext into the cipher[] array and verify. if(Ciphertext==NULL){ printf("Error opening ciphertext!"); exit(1); } else{ for(int i=0; i<1800; i++){ fscanf(Ciphertext, "%d", &cipher[i]); } //Print the contents of the cipher array to verify printf("Printing contents of the cipher array.\n"); int k = strlen(cipher); for (int i=0; i<k; i++){ printf("%d ", cipher[i]); } } sleep(1); //We read the keyfile into the key[] array and verify if(Keyfile==NULL){ printf("Error opening keyfile!"); exit(1); } else{ for(int i=0; i<1800; i++){ fscanf(Keyfile, "%d", &key[i]); } //Print the contents of the key array to verify printf("\n\nPrinting contents of the key array.\n"); int k = strlen(key); for (int i=0; i<k; i++){ printf("%d", key[i]); } } sleep(1); //We XOR the keyfile with the ciphertext and put the result in the plain[] array, and verify. for(int i=0; i<1800; i++){ plain[i] = ((cipher[i])^(key[i])); } printf("\n\nPrinting contents of the plain[] array\n"); printf("%s", plain); sleep(2); //Now we output the plaintext to a file as well. if(Plaintext==NULL){ printf("Error creating output file!"); exit(1); } else{ int k = strlen(plain); for(int i=0; i<k; i++){ fprintf(Plaintext, "%c", (char)plain[i]); } printf("\n\nThe decrypted file has been saved as 'plaintext.txt'"); } //Close the Cipher and Keyfile files and quit. printf("\n\n\n"); fclose(Ciphertext); fclose(Keyfile); fclose(Plaintext); return 0; } This one was interesting. Just fiddling with how the outputs changed depending on whether I was printing them as %i, %d, or %c gave me some insights into strings and arrays that I didn't have before. I played with this one a lot, testing different ways of doing the various pieces. I caught an interesting corner case to investigate. If you use the encryptor with the text "niggers" and the key "faggots" and decrypt it with the decryptor, it gives you "niggots" for the plaintext. I also got it reading in a file generated from /dev/urandom properly, but it needs to specify that the read is of %c type, because %d returns gibberish from the unconcatenated terminal dump. An easy fix, or rather adjustment.
>>8576 Here's a freebie for anyone who needs a cute little BASH script for generating pseudorandom characters. This is what I'll be calling to create the keyfiles. If you plan on using it don't forget to give it execute permissions, lol. #!/bin/bash PAGENUM=1 while [ $PAGENUM -lt 100 ]; do $(cat /dev/urandom | tr -dc '0-9a-zA-Z!@#$%^&*_+-=?[]{},./\><:;|"' | head -c 1800 >> $PAGENUM.txt) let PAGENUM=PAGENUM+1 done Bash and Basic were my first loves when it came to computer shit. This whole project gives me a nostalgia rush.
>>8576 You're (first) program a shit and has a pretty glaring bug that will cause the output to be wrong in certain circumstances. See if you can find out on your own. Also it may be time to start investing time into giving the program some actual shape. e.g. dividing shit into functions. Pretty sure the second program also has some bugs in there too. Overall you really should spend some time going over the concepts again because really there are some things in there that are very careless and will introduce really subtle bugs that would take a lot of time to figure out. For example >fscanf(Ciphertext, "%d", &cipher[i]); This will end up overflowing the buffer and may crash the program. It will also not work on big endian machines, see if you can figure out why.
>>8579 I figured it out. Most of it anyway. X^Y = 0 when X==Y, and because I'm using char arrays it picks up the 0 as a terminator and kills the operation, which is why it breaks after resolving the xor. I need to use int arrays after all, which means the other things I was working on that rely on string function tricks are probably trash now. Unless I get autistic with some strcopy() shit, anyway. What a pain, but live and learn.
>>8581 Yes, good job. Also consider whether you're gonna get the terminating null back in your plaintext in your second program. You need to be a lot more careful about string terminating null management in general, which is another reason why I mentioned you should spend some time going over the basic concepts again. You should also either pay attention to your compiler or compile properly and do the former. If you compile your second program with -Wall for example, you get: trash2.c: In function ‘main’: trash2.c:27:34: warning: format ‘%d’ expects argument of typeint *’, but argument 3 has type ‘unsigned char *’ [-Wformat=] 27 | fscanf(Ciphertext, "%d", &cipher[i]); | ~^ ~~~~~~~~~~ | | | | | unsigned char * | int * | %hhd trash2.c:31:32: warning: pointer targets in passing argument 1 of ‘strlen’ differ in signedness [-Wpointer-sign] 31 | int k = strlen(cipher); | ^~~~~~ | | | unsigned char * In file included from trash2.c:4: /usr/include/string.h:385:35: note: expected ‘const char *’ but argument is of type ‘unsigned char *’ 385 | extern size_t strlen (const char *__s) | ~~~~~~~~~~~~^~~ trash2.c:46:31: warning: format ‘%d’ expects argument of typeint *’, but argument 3 has type ‘unsigned char *’ [-Wformat=] 46 | fscanf(Keyfile, "%d", &key[i]); | ~^ ~~~~~~~ | | | | | unsigned char * | int * | %hhd trash2.c:50:32: warning: pointer targets in passing argument 1 of ‘strlen’ differ in signedness [-Wpointer-sign] 50 | int k = strlen(key); | ^~~ | | | unsigned char * In file included from trash2.c:4: /usr/include/string.h:385:35: note: expected ‘const char *’ but argument is of type ‘unsigned char *’ 385 | extern size_t strlen (const char *__s) | ~~~~~~~~~~~~^~~ These are all actually legitimate bugs in your code. 100% of the compiler output. >I need to use int arrays after all No, the ciphertext can only be considered a chain of random bytes, it's not made out of integers (strictly speaking). Switching to an int array would be a clutch. On your first program the size has to come from the user input (the xor preserves array length so the size of the xored data is the same as input data), on your second program you need to count how many bytes you read from your files and stop when you get EOF instead of trying to read beyond EOF (again, nigger, basic concepts), and also you need to use the right fscanf specifier if you want to go that way. gcc above might have given you a hint on that last thing.
>>8583 Yeah I was aware there was an issue since 2 posts ago, but I put off diagnosing it and underestimated how much of a problem it was going to be. You're also right about the input length, and I had anticipated that with a int k = strlen(user_input); for(int i=0; i<k;i++){ schema to limit the array sizes. I could probably fudge this by recalibrating the arrays and using 2-byte random outputs for the keyfiles instead, but that'd just be a crutch. I'm not trying to be a dev, but for my first real sample project I'd rather do it right. Tonight I'll start from a fresh file and go back to the drawing board.
So I went back to basics and started playing around with it. Because I don't see any way of storing the initial user input without some kind of array which must have a fixed size, I wound up doing a conversion, byte-for-byte, between an input char array and an int array to capture the ASCII values. This led to an interesting problem, because the first way I tried it was setting a global variable 'n' and the userascii array to size [n], and where my first subroutine then set n = strlen(userinput). It seemed logical. But as soon as I tried initializing another int-type array anywhere else, the userascii array would break. After fucking with it a lot I deduced that the [n] variable left "open space" in the contiguous memory elements that another int-type array with a fixed size was allowed to flow into. I didn't think it would work, but I dropped the [n] variable and set the array size to the strlen(userinput) parameter directly, and the damned compiler liked it. Go figure. # include <stdio.h> # include <stdlib.h> # include <unistd.h> # include <string.h> # include <math.h> int main() { //Set up input storage array. char userinput[1800]; //Set up the input math array int userascii[strlen(userinput)]; unsigned int xor[strlen(userinput)]; //Take the user's text input. printf("Enter your text.\n"); fgets(userinput, 1800, stdin); userinput[strlen(userinput)-1] = '\0'; printf("\nYour text was:\n'%s' , with length %lu", userinput, strlen(userinput)); //Copy each string character byte from the input array to the math array //n = strlen(userinput); for(int i=0; i<strlen(userinput); i++){ userascii[i] = userinput[i]; } //Print the ASCII contents of the math array printf("\n\nDisplaying ASCII values from math array\n"); for(int i=0; i<strlen(userinput); i++){ printf("%i ", userascii[i]); } //=====================================BEGIN MATH============================== //Let's declare a temp array full of #s for testing. We'll input the same as text and XOR them int testarr[3] = {'c', 'a', 't'}; printf("\n\nPrinting contents of test array to verify.\n"); for(int i=0; i<3; i++){ printf("%i ", testarr[i]); } //Alright, now let's try xoring. printf("\n\nNow let's try to XOR and store\n"); for(int i=0; i<10; i++){ xor[i] = ((userascii[i])^(testarr[i])); } printf("Printing contents of the XOR array. I hope this works\n\n");
[Expand Post] for(int i=0; i<strlen(userinput); i++){ printf("%i ", xor[i]); } return 0; } Lots of prints for validation purposes. But if you enter "cat" as your text input you can see that it processes the XOR operation properly. No compiler warnings from this build, either.
>>8597 And here's a cleaned up version. Shortly after posting it hit me to declare a global variable and then use it for the rest of the code. # include <stdio.h> # include <stdlib.h> # include <unistd.h> # include <string.h> # include <math.h> //Set a global variable k to contain strlen(userinput) int k; int main() { //Set up input storage array. char userinput[1800]; //Set up the input math array int userascii[strlen(userinput)]; unsigned int xor[strlen(userinput)]; //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, strlen(userinput)); //Copy each string character from the input array to the math array //n = strlen(userinput); for(int i=0; i<k; i++){ userascii[i] = userinput[i]; } //Print the ASCII contents of the math array printf("\n\nDisplaying ASCII values from math array\n"); for(int i=0; i<k; i++){ printf("%i ", userascii[i]); } //=====================================BEGIN MATH============================== //Let's declare a temp array full of #s for testing. We'll input the same as text and XOR them int testarr[3] = {'c', 'a', 't'}; printf("\n\nPrinting contents of test array to verify.\n"); for(int i=0; i<3; i++){ printf("%i ", testarr[i]); }
[Expand Post] //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] = ((userascii[i])^(testarr[i])); } printf("Printing contents of the XOR array. I hope this works\n\n"); for(int i=0; i<k; i++){ printf("%i ", xor[i]); } return 0; }
>>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]); }
[Expand Post]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");
[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