5 ms·
> char *buffer = malloc(sizeof(char) * bufsize); Please don't do this. sizeof(char) is always and everywhere 1. More importantly, don't do: <type> *buffer =
by nanis 6y ago
> char *buffer = malloc(sizeof(char) * bufsize);
Please don't do this. sizeof(char) is always and everywhere 1.
More importantly, don't do:
<type> *buffer = malloc(n * sizeof(<type>));
which frequently leads to bugs of the form
<new_type> *buffer = malloc(n * sizeof(<old_type>));
Instead, use
<type> *buffer = malloc(n * sizeof(*buffer));
which will always keep both sides consistent.
PS: See also http://c-faq.com/charstring/wchar.html http://c-faq.com/charstring/wchar.html
- deleted 6y ago[deleted]
- userbinator 6y agoThat's something I like to use for structured types, especially when the name is long and I can't be bothered writing "struct something" again, but I don't do it for char or other simple types. Of course, it doesn't work when you're doing things like OOP in C, where the type on the left is a "superclass", or using flexible array members and allocating more than just a header's worth.
- tediousdemise 6y agoMoreover, don’t use C at all if you have the choice. A std::string in C++ makes mincemeat of the boilerplate that C requires for the same code. In C++, you can make a very simple REPL that is superior to the one in the OP in almost every way. #include <iostream> #include <string> int main() { std::string input; while (true) { std::cout << "> "; std::getline(std::cin, input); if(input == "exit") { return EXIT_SUCCESS; } else { std::cout << "Unrecognized command: " << input << '\n'; } } } Code quoted from “Setting Up A Better REPL” (https://mikeloomisgg.github.io/2019-04-10-set-up-repl/ https://mikeloomisgg.github.io/2019-04-10-set-up-repl/). It offers good insight into why C is bad in light of the alternatives like Rust and C++.
- david2ndaccount 6y agoNothing stops you from coding a semantically equivalent solution in C, just with structs and function calls that abstract over the details of io and calling realloc correctly.
- windowojji 6y agoDoes C have destructors?
- jonathankoren 6y agoOnly if you make it and call it. C has free, which deallocates a block of memory pointed to by a pointer. If it's a struct, the struct is deallocated. If the struct contains pointers, that memory is still there. If you've lose all the pointers to that chunk of memory, you now have a memory leak. It is not uncommon to make your own allocators and deallocaters for complex structs.
- jhgb 6y ago> In C++, you can make a very simple REPL that is superior to the one in the OP in almost every way. And in Scheme, you can make a very simple REPL that is vastly superior to the one of yours in every way. But I suspect that neither fulfills the goal of learning how things are done in C, which seemed to be the goal of the author of the article.
- enriquto 6y ago> A std::string in C++ makes mincemeat Using bit-shift operators for input/output is a heinous crime against human dignity, basic decency and social order. Every use of it should be punished with 10 lashings, and the promoters of this atrocity should be tarred and feathered.
- deleted 6y ago[deleted]
- rtpg 6y agoalternatively, one could consider that bit-shifting isn't nearly as common of a thing as I/O stream redirection. I'm agnostic on C++'s std stream stuff but I am pretty anti-"yes bitwise logical operators are so important that they get priority over all these symobls".
- leetcrew 6y agoamong other things it's just not a very friendly syntax for the common case of formatting strings and getting input. printf/scanf are much less verbose (if a bit less safe).
- rtpg 6y agoThat's a good point, actually. Beyond the "default formatting" case, it seems pretty hard to imagine a good syntax that would not be very awkward.
- jcelerier 6y agobut it removes three classes of errors entirely when compared to printf / scanf: - wrong arguments types (mostly solved by libraries such as fmt tho): printf("%d", 0.5); - too much / not enough arguments passed: printf("%d", 0, 1); - passing unsanitized strings as template argument: printf(some_string_i_got_from_the_network_lol, arg_1, arg_2); the << method makes these three errors impossible. Also << does not allow you to have something like printf's %n, which writes to one of its arguments. fmt is able to give compile-time validation of string literals, but at a hefty compile-time cost. In my opinion the best solution would be string interpolation, but we're definitely not there yet...
- gens 6y agoI would never use C++ if i had a choice. And i do have a choice.
- Cyph0n 6y agoThe second tip is an important one. This also applies when using memset, memcpy/memcpy_s, and related memory manipulation functions. C gives you many ways to shoot yourself in the foot, so you need to make sure to use available language features to your advantage.
- anaphor 6y agoFWIW, instead of `*buffer = malloc(n * sizeof(*buffer))` you can omit the extra parens and write `*buffer = malloc(n * sizeof *buffer)` also, calloc is a nice idea too
- nanis 6y ago> can ... write *buffer = malloc(n * sizeof *buffer) The extra parentheses are there for the us humans who might need help distinguishing between * as dereferencing operator versus * as multiplication all happening within the space of eight or so characters.
- gens 6y agoCHAR_BIT is a minimum of 1 byte (8 bits), but is not guaranteed to be 1. http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf (Annex E)
- nanis 6y ago> CHAR_BIT is a minimum of 1 byte (8 bits), but is not guaranteed to be 1. It seems like you are conflating things. One is, a char does not have to be an octet. That is correct. The other is the unit for sizeof(char) is always and everywhere 1. That is, the size of everything else is measured relative to char. Please do see C FAQ[1]. In addition, please see 6.5.3.4.2 in [2]: > When applied to an operand that has type char, unsigned char, or signed char, (or a qualified version thereof) the result is 1. It does not matter if char is 11 bits therefore not an octet. That means you are in a universe where a byte is 11 bits long, sizeof(char) is still 1 as far as your program and the compiler are concerned. Note that the same is true in C++ as well: > Depending on the computer architecture, a byte may consist of 8 or more bits, the exact number being recorded in CHAR_BIT. sizeof(char), sizeof(char8_t), sizeof(signed char),sizeof(unsigned char), and sizeof(std::byte) are always equal to 1. HTH. [1]: http://c-faq.com/charstring/wchar.html http://c-faq.com/charstring/wchar.html [2]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf [3]: https://en.cppreference.com/w/cpp/language/sizeof https://en.cppreference.com/w/cpp/language/sizeof
- gens 6y agoYou are right. I didn't look into sizeof. So.. by the C standard, a byte is a size of char.
- pwdisswordfish6 6y agoNo. Instead, use <type> *buffer = calloc(n, sizeof(*buffer)) as that will also protect against multiplication overflow.
- montebicyclelo 6y agoI don't know what I'm talking about, but according to [1] (2008): > So naturally every existing calloc out there performs this overflow check and doesn’t just multiply its arguments together? Oh no. Even I was surprised. > On OS X (10.4.11) calloc(65537, 65537) returns a non-NULL pointer. This is a bug. > PHK’s code in NetBSD is typical, it just multiples the two arguments and uses the result, reckless to overflow. > Hurray for FreeBSD: they do almost exactly what I suggest, but with a fast test that is just the tiniest bit unportable. Which suggests you shouldn't rely on there being a multiplication overflow check. [1] https://drj11.wordpress.com/2008/06/04/calloc-when-multiply-overflows/ https://drj11.wordpress.com/2008/06/04/calloc-when-multiply-...
- neysofu 6y agoI always use `sizeof(char) * ...` in my projects when I deem fit. I feel like it helps with readability and it shows why I'm allocating a buffer with that specific size: I want it to hold exactly N characters.