3 ms·
#include <stdio.h> #include <stdlib.h> int main() { size_t len = 0, cap = 0; char *buffer = NULL; int c; while ((c = getchar()) != EOF) {
by wizzwizz4 4y ago
#include <stdio.h>
#include <stdlib.h>
int main() {
size_t len = 0, cap = 0;
char *buffer = NULL;
int c;
while ((c = getchar()) != EOF) {
if (len >= cap) {
cap = (cap << 1) + 1;
{
char *newbuf = realloc(buffer, cap);
if (!newbuf) {
fprintf(stderr, "Could not reallocate to %zu. Printing what I've got.", cap);
break;
}
buffer = newbuf;
}
}
buffer[len++] = (char)c;
}
while (len --> 0) {
if (putchar(buffer[len]) == EOF) {
fprintf(stderr, "Output failure.");
return 1;
}
}
free(buffer);
return 0;
}
Most of the verbosity here is in correctly handling errors, something that isn't much easier to do in C++. (Be warned: I haven't tested this code.)
- zabzonk 4y agoor in c++, simply call getline? i haven't traced thru your code, but i would not be surprised if there were errors in it, having written similar stuff myself. compare with using std::string and std::getline - easy to use and battle-hardened.
- wizzwizz4 4y agoHow does getline handle the out-of-memory condition? How do I avoid leaking memory – is that handled by std::string's RAII destructor? To detect the end-of-file condition, there's something about a failbit, but I'm only four pages of documentation in, so I don't know what that is yet. What would the equivalent code look like in C++, handling EOF and OOM conditions appropriately?
- blackpill0w 4y agoprobably std::string would throw std::bad_alloc, and there is also the failbit flag which std::getline sets
- zabzonk 4y agoif memory is exhausted, then getline throws a bad_alloc exception. if end of fileis reached (which i am not sure your code deals with correctly) then getline returns a stream in a bad state. so something in outline like this (syntactically correct. std:: omitted for brevity, but probably not what you would really write): string input; try { if ( cin.getline ( input ) ) { // ok read input, do something with it } else { // some sort of predictable error - look at state of cin to diagnose EOF } } catch (...) { /// something terrible happened - as hard to recover as it would be in c }
- johndough 4y agoJust to clearify: Do you make the assumption that the input only consists of a single line?
- zabzonk 4y agothat was my intention, but in the case of multiple lines c++ is evrn easier than in c - just use std::vector <std::string>.
- johndough 4y agoYou could check for ferror when getchar returns EOF. Otherwise very nice. I wrote almost exactly the same code before I saw yours. The only difference was that I used multiplication by 2 instead of left shift since the goal was easier understanding. gcc can perform this optimization (for unsigned integers). I also looked up whether the cast from int to char is safe. Seems that it is not, but probably fine in practice https://stackoverflow.com/questions/19250521/best-way-to-portably-assign-the-result-of-fgetc-to-a-char-in-c https://stackoverflow.com/questions/19250521/best-way-to-por... Of course all bets are off when someone tries to reverse emoji soup with this, but I am not knowledgeable enough about this topic to claim whether a general solution is even possible.
- wizzwizz4 4y ago> but I am not knowledgeable enough about this topic to claim whether a general solution is even possible. The correct way to reverse a Unicode string is to blit it back to front. Addendum: a real C programmer helped me write (i.e., wrote most of) the following program: #include <skalibs/skalibs.h> int main() { stralloc sa = STRALLOC_ZERO; slurp(&sa, 0); stralloc_reverse(&sa); if (allwrite(1, sa.s, sa.len) < sa.len) { strerror_diefusys(1, "output everything"); } } In the event of an allocation failure, this program will output nothing; other than that, it's the same as my C program above. Perhaps the problem isn't C, but its standard library?
- steveklabnik 4y ago> Perhaps the problem isn't C, but its standard library? That's certainly at least a factor. In Rust, the "reverse a string byte by byte" bit could look like: let reversed_string = String::from_utf8(some_string.bytes().rev().collect::<Vec<u8>>())?; This is just what I thought of first. Peeking at the standard library examples, this one is fun: unsafe { let vec = some_string.as_mut_vec(); vec.reverse(); } This is unsafe because you may create invalid utf8, but we've already established that's not something we care about, so... But yeah stuff like this isn't impossible in C, though you'd not have method call syntax, of course. Rust's libraries are just richer here.