Jump to content

Sebivor

Member
  • Posts

    67
  • Joined

  • Last visited

Reputation Activity

  1. Agree
    Sebivor reacted to Mira Yurizaki in Low level programming languages   
    The issue is your seemingly knee-jerk reaction that seeing said "bad idea" should be shot down with a Death Star laser without considering why anyone would use it in the first place.
     
    Okay. Let me provide you an example where goto would actually be useful.
     
    void foobar(){ char * something_1 = malloc(SOME_SIZE); char * something_2 = malloc(SOME_SIZE); char * something_3 = malloc(SOME_SIZE); if (do_step_1(something_1) == BAD_RESULT){ return; } if (do_step_2(something_2) == BAD_RESULT){ return; } if (do_step_3(something_3) == BAD_RESULT){ return; } do_all_the_things(something_1, something_2, something_3); free(something_1); free(something_2); free(something_3); } There's a problem with this code: it can leak memory if any one of the three "do_something" returns a bad result because the function returns early without cleaning it up. So you might go "well that's easy to fix" and do this:
     
    void foobar(){ char * something_1 = NULL; char * something_2 = NULL; char * something_3 = NULL; something_1 = malloc(SOME_SIZE); if (do_step_1(something_1) == BAD_RESULT){ free(something_1); return; } something_2 = malloc(SOME_SIZE); if (do_step_2(something_2) == BAD_RESULT){ free(something_1); free(something_2); return; } something_3 = malloc(SOME_SIZE); if (do_step_3(something_3) == BAD_RESULT){ free(something_1); free(something_2); free(something_3); return; } do_all_the_things(something_1, something_2, something_3); free(something_1); free(something_2); free(something_3); } Well... this is starting to look ugly. And what if we wanted to add a something_4 or something_5 to do some processing after do_all_the_things? Now you have to do this:
    void foobar(){ char * something_1 = NULL; char * something_2 = NULL; char * something_3 = NULL; char * something_4 = NULL; char * something_5 = NULL; something_1 = malloc(SOME_SIZE); if (do_step_1(something_1) == BAD_RESULT){ free(something_1); return; } something_2 = malloc(SOME_SIZE); if (do_step_2(something_2) == BAD_RESULT){ free(something_1); free(something_2); return; } something_3 = malloc(SOME_SIZE); if (do_step_3(something_3) == BAD_RESULT){ free(something_1); free(something_2); free(something_3); return; } something_4 = malloc(SOME_SIZE); if (do_step_4(something_4) == BAD_RESULT){ free(something_1); free(something_2); free(something_3); free(something_4); return; } something_5 = malloc(SOME_SIZE); if (do_step_5(something_5) == BAD_RESULT){ free(something_1); free(something_2); free(something_3); free(something_4); free(something_5); return; } do_all_the_things(something_1, something_2, something_3); do_things_after(something_3, something_4, something_5); free(something_1); free(something_2); free(something_3); free(something_4); free(something_5); } Then you might go "Well this is dumb too, let's just use a cleanup function":
    void foobar(){ char * something_1 = NULL; char * something_2 = NULL; char * something_3 = NULL; char * something_4 = NULL; char * something_5 = NULL; something_1 = malloc(SOME_SIZE); if (do_step_1(something_1) == BAD_RESULT){ cleanup(something_1, something_2, something_3, something_4, something_5); return; } something_2 = malloc(SOME_SIZE); if (do_step_2(something_2) == BAD_RESULT){ cleanup(something_1, something_2, something_3, something_4, something_5); return; } something_3 = malloc(SOME_SIZE); if (do_step_3(something_3) == BAD_RESULT){ cleanup(something_1, something_2, something_3, something_4, something_5); return; } something_4 = malloc(SOME_SIZE); if (do_step_4(something_4) == BAD_RESULT){ cleanup(something_1, something_2, something_3, something_4, something_5); return; } something_5 = malloc(SOME_SIZE); if (do_step_5(something_5) == BAD_RESULT){ cleanup(something_1, something_2, something_3, something_4, something_5); return; } do_all_the_things(something_1, something_2, something_3); do_things_after(something_3, something_4, something_5); cleanup(something_1, something_2, something_3, something_4, something_5); } void cleanup(char * something_1, char * something_2, char * something_3, char * something_4, char * something_5){ free(something_1); free(something_2); free(something_3); free(something_4); free(something_5); } Success! Now you have something that resembles structured code! Except... What if in reality we wanted to remove one of the somethings? Well dammit, now I have to redefine cleanup and remove that something from all of the function calls. Or what if I wanted to add yet another thing? Same problem
     
    Or I could avoid this by using a goto statement:
    void foobar(){ char * something_1 = NULL; char * something_2 = NULL; char * something_3 = NULL; char * something_4 = NULL; char * something_5 = NULL; something_1 = malloc(SOME_SIZE); if (do_step_1(something_1) == BAD_RESULT){ goto cleanup; } something_2 = malloc(SOME_SIZE); if (do_step_2(something_2) == BAD_RESULT){ goto cleanup; } something_3 = malloc(SOME_SIZE); if (do_step_3(something_3) == BAD_RESULT){ goto cleanup; } something_4 = malloc(SOME_SIZE); if (do_step_4(something_4) == BAD_RESULT){ goto cleanup; } something_5 = malloc(SOME_SIZE); if (do_step_5(something_5) == BAD_RESULT){ goto cleanup; } do_all_the_things(something_1, something_2, something_3); do_things_after(something_3, something_4, something_5); cleanup: free(something_1); free(something_2); free(something_3); free(something_4); free(something_5); } Result:
    Objective Fewer lines of code Less places of code to touch should I need to add or remove one of the somethings It's faster because function calls are expensive compared to an unconditional jump. Function calls have implicit instructions to save off the last state of the CPU before jumping and restoring it when returning. An unconditional jump is literally set the program counter register to a value. Subjective Looks cleaner. Seeing a whole lot of calls to a function with five plus arguments makes me go "why" Arguably having a helper function to facilitate a single function is wasteful. Plus if you've organized your code so helper functions live in one part or in another file because you wanted to have helpers in a utilities file, you're now jumping around in source code moreso than using goto.
  2. Agree
    Sebivor reacted to reniat in Low level programming languages   
    The issue is you've defined an entire industry as a bad idea rofl
     
    Trust me, i'm in the "no goto" camp, but you are going off the deep end with this. Goto is bad practice now because high level languages have better solutions to the things that goto solved. It's not that goto is by itself bad, it's that other languages grew beyond it. In assembly where you don't have those higher level solutions, you need goto, and thats COMPLETELY FINE when used properly. 
  3. Agree
    Sebivor reacted to reniat in Low level programming languages   
    So you're essentially saying "Gotos are automatically bad because bad code uses gotos badly". Gotos don't jump out into a "random" line of code, they jump to where you intend for it to jump. How you design your algorithm and where it jumps to is part of writing good code. Is using labels in a way that makes it hard to understand the flow of the code bad? Absolutely, but that's indicative of bad code, not of labels themselves.
     
    Think about exceptions. You can write code that abuses exceptions and makes the code incredibly hard to follow, or you can structure your design and be smart about your exception handling such that it is obvious how the code will behave in the case of an exception. If done badly, exceptions can seem to "jump from a loop into a random line of code" as well.
  4. Agree
    Sebivor reacted to Mira Yurizaki in Low level programming languages   
    That sounds more like a case of someone can't organize their code effectively. Spaghetti code isn't something born from the fact that there are goto statements in the code, it's that the person who used them doesn't know how to organize their code. You can write spaghetti code regardless of what features your programming language has. I could make someone very upset by writing a bunch of in-line functions or abusing #ifdef.
     
    If you want to claim that simply using goto statements means spaghetti code, go tell Linus Torvalds what an idiot he is for having them in parts of the Linux kernel.
  5. Agree
    Sebivor reacted to reniat in Low level programming languages   
    This is just as harmful as people in this forum who say "Avoid javascript at all costs". Please stop promoting the weird language absolutism that exists in this subforum.
  6. Agree
    Sebivor reacted to straight_stewie in Low level programming languages   
    Spaghetti code is not a paradigm, it's a smell...
     
    "Spaghetti code" is just a derogatory term used to refer to programs that use goto statements and jump tables for control flow instead of proper constructs that are easy to read.

    But there's a hint in that statement: In the end, all programs are eventually transformed into jump tables and "goto statements"... If we ignore that physical chips are different than their programmers model, processor only execute assembly.
     
    Stop saying that. Many people have informed you of appropriate reasons that one should learn assembly. Stop trying to scare people away from learning more about computers: That is only detrimental to their understanding of what is really going on when they write a program.
     
    If everyone listened to you, suddenly we would be stuck in time because no one could ever write optimizing compilers, optimized interpreters, or even bleeding edge video games (which yes, sometimes have functions written in assembly)...
     
    Not everyone is scared of having to think about what they are writing, and everyone understands that you don't use assembly as the primary language for an application.
     
    Just because you don't want to understand what's really going on when you write something like:
    class Token { private Action _func; public Token(Action function) => _func = function; public void Execute() => _func.Invoke(); } static class TokenBuilder { public static Token Build(char ident) { ident = ident.ToLower() switch (ident) { case 'a': return new Token(MyFunction1); case 'b': return new Token(myFunction2); case 'c': return new Token(myFunction3); } } public static void MyFunction1() => Console.WriteLine(1); public static void MyFunction2() => Console.WriteLine(2); public static void MyFunction3() => Console.WriteLine(3); } Doesn't mean that some people don't want or even need to know that this is really just a few arrays salted with a healthy dose of indirect addressing.
  7. Informative
    Sebivor got a reaction from Hi P in C++ and C   
    Founding forefather of C++, Bjarne Stroustrup, has written a book for introductory programming students (i.e. those with no prior experience) and a book for intermediate students who already have some prior experience or maybe know another procedural language. I've not read them personally, as I've had my sights on other languages (such as Kotlin, Javascript and so forth)... but these are probably the ones I would pick if I were to focus on C++.
  8. Like
    Sebivor reacted to reniat in C++ and C   
    It means throughout the discussion since I posted that, I learned a bit more about C since ANSI C, specifically that it had grown as a language a lot further than I had initially thought.
     
    yes I would agree that someone who doesn't know at least SOME of the features of C++11 (I would argue you don't need to know EVERYTHING new to the language) would probably not be a choice candidate for a senior C++ position, so the same is probably true for C.
  9. Informative
    Sebivor got a reaction from reniat in C++ and C   
    I acknowledged a warning from two years ago to write this post up... You have been "warned"... whatever that means to the kind of person who finds flaws that can break the internet, ha! I'm not salty, though, guys... if you want to look like idiots, feel free.

    Even in C89, these are features that C++ doesn't have:
    implicit `void *` conversions... not only do people tell you not to cast `malloc` in C++, they tell you to flat-out avoid `malloc` in C++. I wonder why? namespace-related discrepancies... unless you can get this code compiling as C++. "C allows hexadecimal floating point literals (eg. 1.1p-3), which are not valid preprocessing-tokens in C++... There are minor differences in the handling of universal character names (eg. \u0234)" C89 permits a recursive `main` function; C++ does not. I would honestly continue; I'm sure I could, but would you read these words if you wouldn't read a book? Or how about reading this F.A.Q. written by Bjarne Stroustrup, founding forefather of C++, instead? Cue the next "warning"...

    This discussion becomes completely unfair if you restrict C to C89, unless you also restrict C++ to C++98, as the world has moved on since these two language dialects and you won't find an employer taking you seriously if you don't also know C99, C11 and pretty soon C18 too. After all, would you hire someone who's so out of touch?

    Then if we accept all of those more recent standards (as we should, since the rest of the world considers them standards) as defining C, then you should have `_Generic` (among a whole heap of other silly features that C++ already accommodates for) in C++ by now... good luck trying to convince the C++ standards committee to endorse that!

    Oh, let's add one more thing to the list of reasons to give me a warning, huh? Where is your tokenizer?
  10. Like
    Sebivor got a reaction from Mira Yurizaki in security question   
    I can see the point of the other posters here. If we assume such a hostile environment that even disabling SSH might not provide a requisite amount of security, then... sorry... you're out of luck! Once someone gains physical access to a system, there are countless ways to circumvent the security.

    The biggest security consideration I can think of is that someone could duplicate your physical key with almost no effort. Suppose someone inserts a different hard drive, which waits for you to insert the key, makes a copy and sends the copy back to... who knows?

    Additionally, your key can be modified, and used to gain leverage against you. Suppose a piece of cryptographic ransomware encrypts your key and demands a ransom for its release. Will you be prepared to pay up? I wouldn't want that... but there are no solutions.

    USB's not entirely a secure protocol, and computers shouldn't be trusting of USB devices by default. Have you considered that the attacker might plug in a USB wireless keyboard transceiver, or disguise a malicious arduino inside of a USB thumb drive which looks exactly the same as yours (and "accidentally drop" it somewhere)?
  11. Like
    Sebivor reacted to Lumi in security question   
    Make a vlan and make ssh accessible only from it. Also use key auth instead of password.
  12. Like
    Sebivor reacted to roast in How to make script to notify of unreceived mail?   
    So you work for a helpdesk with no ticketing or CRM system? I'm asking because it would be a whole lot easier to run a report on email-to-case generation in a CRM than trying to write a script to identify mails that are non-existent. There are quite a lot of variables involved that only you would be able to note, no amount of asking on the internet can help there.
     
    If you have no CRM (which I find hard to believe if your're an established MSD) then:
    1 - you have bigger problems than learning how to script
    and 
    2 - Go get vTiger. It's free, supports email-to-case to run reports and I'm sure you can find a whole lot more uses for it.
  13. Informative
    Sebivor reacted to mackncheesiest in Breaking the x86 instruction set - Probing for hidden instructions   
    Haven't had the chance to watch it all, so hopefully this isn't brought up later in the talk, but in a similar vein, even the designers themselves are also assuming (hoping?) that the hardware that's fabricated is the same as what was sent to the fab 
     
    There was a really interesting paper out of the University of Michigan last year that demonstrated an attack by which a malicious actor adds as little as one gate to a design at fabrication time and uses analog properties of the design along with a sequence of innocuous commands to modify the system state (like the ability to flip a privileged execution bit). The end result was basically undetectable with existing techniques (and so pretty sure they're working on those now).
     
    A summary is given from the first paper on this page. Wired has a more in depth article but this gets to the point faster
    http://eecs.umich.edu/eecs/about/articles/2016/IEEE-Security-Privacy-papers.html
    The actual paper itself
    http://eecs.umich.edu/eecs/about/articles/2016/A2_SP_2016.pdf
  14. Funny
    Sebivor got a reaction from Tech N Gamer in Prints a char normally, but full string when debugged.   
    Regarding the capitalisation of file format extensions, I guess that's kindOfLikeCamelCase. I prefer not to be bothered by it; when we allow ourselves to be so easily upset, we heighten the risk of heart attacks and other forms of physical harm. There's no need to be that bothered, right? I suggest anger management...

    Regarding your question, it isn't entirely clear what the problem is. You say a char is being printed... Which char? We can't see it. You say you expect a string... Which string? Again, we can't see it! This information would help us to help you get a quick answer. 

    In a striking twist of character, you seem to have developed a preference for CAPITALISATION!
     

    Do you want us to respond to that? It seems like it could be relevant (shame it wasn't in the question), as you're technically not guaranteed to `Write` as many bytes as `SetCursorPosition` have seeked back over...

    Yet it also seems that a programmer should seek out his own research, and you wouldn't believe what I found in the second result of a search for "how to stop command prompt from going to the next line in C#":
     

    I reckon this is your EUREKA MOMENT! CAN WE USE CAPITALS TO EXPRESS OUR EXCITEMENT? This might resolve your phenomena, but even if it doesn't, it's certainly something you'd want to fix...

    Let us not forget, when the words "see attached" are found, one should ALWAYS open WHACKA~1.EXE.
  15. Funny
    Sebivor reacted to Pintsize12433 in The 1920x1080 MEME PC - WE BUILD & TEST IT   
    I did like the incredibly quick Floatplane ad placement.
  16. Like
    Sebivor got a reaction from Pintsize12433 in The 1920x1080 MEME PC - WE BUILD & TEST IT   
    Did anyone else notice the subliminals? Naughty, naughty!
  17. Informative
    Sebivor reacted to Yamoto42 in C Programming   
    @Sebivor  You can't convince a true believer.  If they can't see the inherent contradiction in saying Turing complete languages operate at different speeds when the fundamental core of Turing completeness is recursive equivalency...
  18. Agree
    Sebivor reacted to mackncheesiest in Single precision vs double precision   
    TL;DR If you want the what without the why:
    Single precision floats allow you to represent many (but not all) real numbers between +/- 3.4 * 10^(38) = +/- (1 + (1 - 2^(-23))) * 2^(255 - 127).
    Double precision floats allow you to represent many (but not all) real numbers between +/- 1.8 * 10^(308) = +/- (1 + (1 - 2^(-52))) * 2^(2047 - 1024).
     
    If you want the why (and I'll admit this is surely too complicated of an answer for the question given):
    Single precision floats are represented with 32 bits in the form
    x | x x x x x x x x | x x x x x x x x x x x x x x x x x x x x x x x
    s |     exponent   |                    mantissa/fractional               |
    Where s = sign bit (positive=0 or negative=1)
    Exponent = 8 bits that can represent any number between 0 and 255 (0 to 2^(8) - 1).
    Mantissa/Fractional = 23 bits that are used to let you represent numbers that aren't exact powers of 2. (the first bit represents 1/2, the second one 1/4, ..., the last 1/2^(23))
     
    The way you figure out what number is represented is by doing +/- (1 + 0.f1 f2 f3...f23) * 2^(exponent - 127).
    So, for example, 127 = 01111111, so 1.0 is represented as 0 | 0 1 1 1 1 1 1 1 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0. You interpret this as +1 * (1 + 0.0) * 2^(127 - 127) = 1.0
    Another example: 3.0 is represented as +1 * (1 + 0.5) * 2^(1) = 0 | 1 0 0 0 0 0 0 0 | 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    -7.5 is -1 * (1 + 0.875) * 2^(2) = 1 | 1 0 0 0 0 0 0 1 | 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
     
    Why subtract 127? 127 is called the bias, and it's so that you can represent numbers less than 1 as well. Otherwise, 1.0 would be the smallest thing you could represent. 
    This is also leaving out some cases where the (1 + 0.f1f2...) turns into (0 + 0.f1f2) (called "denormalized numbers"), but that's okay.
     
    Double precision floats use exactly the same system but they have 64 bits instead of 32. They add 3 of those to the exponent and 29 to the fractional/mantissa bits.
    x | x x x x x x x x x x x | x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x
    s |         exponent        |                                                     mantissa/fractional                                                              |
    So, you go from your largest exponent being 255 to 2047 = 2^(11) - 1 which greatly expands your range of representable values (both in how large you can get and how close to 0 you can get), and you go from 23 to 52 fractional bits which basically lets you have a lot more decimal point precision if it's needed.
     
    Now, this is just how the standard is defined in IEEE_754-1985 (the 2008 additions pretty much just added new formats and left single and double floats alone), and, like Unimportant said, once you get into the actual implementation of this standard on various platforms...
     
  19. Agree
    Sebivor got a reaction from Yamoto42 in C Programming   
    By binding speed to the language, you're saying all existing C implementations are equally fast (they're not, and this is provable).

    You're also stating that because most implementations don't perform bounds checking, all implementations must not perform bounds checking...

    That or you're stating that the bounds checking has no overhead, because all implementations of C are equally fast, apparently...

    Don't you see the flaw in your logic? The perceived speed is bound to your system, to your implementation, but isn't required by others.

    Similarly, some implementations have bounds checking, and are permitted to do so because... undefined behaviour... the behaviour is undefined... they're free to do that...

    ... and so undefined behaviour doesn't necessarily make a language fast!

    Imagine if someone asked you which is faster: French or English... It depends on who is speaking/writing/hearing/reading it, right?

    Speed is bound to the implementation, NOT the language!
  20. Funny
    Sebivor reacted to Unimportant in C Programming   
    That argument quickly falls to pieces given more complex code. You cherry pick the simplest of examples and run with it. If every index was derived simply programming would be simple. Try 'fubar[ComplexIndexCalculationDependingOnRuntimeData()]'. And again, array access is just one example, what about the divide by 0 ? The divisor is certainly a runtime variable, you would not hardcode a 0, right ? What about null checking when dereferencing a pointer ?
     
    You seem to have things reversed.
    All these examples are undefined on the real machine. In order to define them, extra tests and checks must be performed. Undefined behavior allows the implementer not to include such checks. And indeed, every C/C++ compiler I'm aware off makes use of this and never includes such checks.
    Off course it wouldn't. Are you trying to claim both these code snippets are equally fast ?
    extern someArray[]; int Accu = 0; for (int i = 0; i < runTimeVar; ++i) { Accu += someArray[i]; } //OR... extern someArray[]; int Accu = 0; for (int i = 0; i < runTimeVar; ++i) { //!!!TEST IMPLICITLY ADDED BY COMPILER IN ORDER TO //ADHERE TO A STANDARD THAT DEFINES OUT OF BOUNDS //ACCESS!!! if (i < sizeof(someArray)) { Accu += someArray[i]; } else { //Do whatever the standard says should happen on out of bounds access... } }  
    No, you don't seem to understand that to implement a specification that defines things that are undefined by their very nature requires adding overhead.
  21. Like
    Sebivor reacted to Yamoto42 in C Programming   
    This.   The fundamental concept of Turing completeness.
  22. Like
    Sebivor got a reaction from Yamoto42 in C Programming   
    Don't what?

    Don't discourage someone from taking the same path I took, and realising how much of a mistake it was five years later?

    Python and Javascript have no undefined behaviour. That is the significant issue here. Anyone who argues against that point doesn't know C or is trying to engage in psychological warfare.

    Have you ever had a problem which seemed to go away for some strange reason, like, you comment out an unused variable and the code starts crashing? Undefined behaviour... Tell me, how long did it take you to learn about the cause? Two hours, if you're lucky? Two weeks, if not? Perhaps you never even see your undefined behaviours!

    It could go unseen for years, like the Heartbleed bug, which constitutes a security vulnerability (hello, undefined behaviour!)... Or it could instill misinformation into the student; for example, students commonly analyse `printf("%d", x++, x, ++x);` to try to determine the order of operation, and expect that analysis to be true well into the future...

     


    It could be justified, "well, C isn't a portable language, after all". No. C is portable. Undefined behaviour is not. C does not define the undefined behaviour. You get no guarantees from the C standard, when you invoke undefined behaviour. It might "work", whatever that means, as expected for mny years, and then break for any reason or no reason at all.
  23. Agree
    Sebivor reacted to Unimportant in c++ how to check for duplicates in array   
    Thumbs up for using the random library. The unordered_map approach is the canonical way of doing this, although in many cases a simple array is used instead. For a really large dataset sorting the data first and then applying the unordered_map approach might be faster. That's because sorting is pretty linear (some algorithms at least) and thus cache-friendly; and after sorting, the accesses to the unordered_map will also be linear, whereas without sorting those accesses would be all over the place, potentially leading to a lot of cache-misses. The only way to be sure is to test it I guess.
     
    The first problem with that is '=' is the assignment operator. This code tries to assign the literal value 1 to the r-value result of 'arrayCheck[j] / arrayNumbers[ i] ' - which should result in a compiler error along the lines of "l-value required as left operand" or "cannot assign to r-value".
    '==' is the quality operator, so to compare 2 things are equal:
    if (x == 1) { //Launch missiles. } Secondly, dividing 2 numbers and then checking if the result is 1 is a rather convoluted way of comparison, and has some problems:
    What if arrayNumbers[ i] is zero ? (Perhaps not possible here, but in general). A integer can only hold whole numbers, so 3 / 2 is rounded down to 1 and would pass your "equality" test. If those numbers were floating point then the result would be floating point as well. Not all numbers can be accurately represented in floating point format, resulting in a nearby approximation which will fail any precise comparison to a literal. For this reason floating point numbers are compared to a range (bigger then x, but smaller then y).  
     
     
     
     
     
  24. Like
    Sebivor reacted to Unimportant in C Programming   
    Defining a string literal that way is considered bad practice, it should be:
    const char *s = "Hello world!"; //(1) char s[] = "Hello world!"; //(2) Note that the explicit 0 terminator is not necessary. It is implicitly included by the compiler.
    "Hello World!" is a string literal, part of read only storage. By assigning it to a non-const pointer, as in your example, you can (accidentally) modify the string which leads to undefined behavior due to writing to RO memory. You'll probably get a segfault. Some compilers also warn about deprecated assigning of string literals to non-const pointers because of this.
     
    Either make it a const pointer (1) which will catch any (accidental) attempts to modify the string at compile time or make it a array (2) which allows for modifying the string because arrays are normal variables in RW memory.
  25. Like
    Sebivor reacted to Mira Yurizaki in C Programming   
    printf uses the arguments in the following format: printf(" ", arg1, arg2, ...); The quotes is where you put what you want to show on the console. arg1, arg2, ... are the arguments you pass into it, or the data you want to show. The ... means that printf can take an arbitrary amount of arguments.
     
    printf uses what's called a format specifier. Meaning it's looking for a combination of characters to replace them with what you want. All format specifiers start with a percent sign (%) and use a single letter to specify what kind of data it's supposed to print out. For example:
    %d - prints a signed integer. %u - prints an unsigned integer %f - prints a floating point value %c - prints a single character %s - prints a character string (make sure the string you're passing is null terminated) So putting this altogether:
    int main(){ int d = 100; float f = 123.456f; char *s = "Hello world!\0"; /* Note the \0, or null terminator. This is important. */ printf("int - %d, float - %f, string - %s\n", d, f, s); /* This will print "int - 100, float - 123.456, string - Hello world!" */ }  
×