Read string of any length in CRemoving any duplicate characters in a stringRead file directly -...

Would it be unbalanced to increase Wild Shape uses based on level?

Asked to Not Use Transactions and to Use A Workaround to Simulate One

Should you only use colons and periods in dialogues?

Does my opponent need to prove his creature has morph?

How does a linear operator act on a bra?

I was promised a work PC but still awaiting approval 3 months later so using my own laptop - Is it fair to ask employer for laptop insurance?

How to be sure services and researches offered by the University are not becoming cases of unfair competition?

How do I create indestructible terrain?

Consonance v. Dissonance

What is a "major country" as named in Bernie Sanders' Healthcare debate answers?

Reading double values from a text file

What made 4/4 time the most common time signature?

Is there a tool to measure the "maturity" of a code in Git?

If the gambler's fallacy is false, how do notions of "expected number" of events work?

A Mainer Expression

Can derivatives be defined as anti-integrals?

How do certain apps show new notifications when internet access is restricted to them?

Why is the Digital 0 not 0V in computer systems?

Is there any reason to concentrate on the Thunderous Smite spell after using its effects?

What makes a smart phone "kosher"?

Can I conceal an antihero's insanity - and should I?

The Planck constant for mathematicians

Fasteners for securing cabinets together

Where is it? - The Google Earth Challenge Ep. 2



Read string of any length in C


Removing any duplicate characters in a stringRead file directly - simplifiedCheck for whether a string contains any duplicate charactersAlgorithm for Run Length Encoding - String CompressionReading file into structureRead file contents to string safelystring-length, structs, pointers in cFind string length using pointersRead a palindrome of unknown lengthstrReadLine function (read line by line from a string)






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ margin-bottom:0;
}







3












$begingroup$


I've written code in C for reading a string of any length, and printing the string. It's one of my first C programs. I posted the program as part of a Stack Overflow question, and received a comment:




... there are many things wrong with your C version.




I'd really like to know what is wrong with the function I have written. Suspects: EOF handling, calling dynamic memory allocation functions too many times.



#include <stdlib.h>
#include <stdio.h>

/* Asks the user for string input.
* Returns a pointer to the string entered by the user.
* The pointer must be freed.
*/
char* input()
{
char *s = malloc(sizeof(char)); /* For the null character */
if (s == NULL) {
fprintf(stderr, "Error: mallocn");
exit(1);
}
s[0] = '';

/* Read characters one by one */
char ch;
size_t s_len = 0;
while((ch = (char) getchar()) != 'n') {
if (ch == EOF) {
exit(0);
}
s_len++;
s = realloc(s, (s_len * sizeof(char)) + sizeof(char));
if (s == NULL) {
fprintf(stderr, "Error: reallocn");
exit(1);
}
s[s_len - 1] = ch;
s[s_len] = '';
}
return s;
}

int main()
{
printf("Name: ");
char *s = input();
printf("%sn", s);
free(s);
return 0;
}









share|improve this question









New contributor



Flux is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






$endgroup$














  • $begingroup$
    Does the code work, to the best of your knowledge?
    $endgroup$
    – Null
    10 hours ago






  • 1




    $begingroup$
    @Null Yes it works.
    $endgroup$
    – Flux
    10 hours ago










  • $begingroup$
    You can simplify sizeof(char) to 1. You should also use an int to get the return value from getchar(). You also shouldn't cast. You should also use perror instead of fprintf(stderr, "Error: .
    $endgroup$
    – JL2210
    10 hours ago








  • 2




    $begingroup$
    Please see What to do when someone answers. I have rolled back Rev 2 → 1.
    $endgroup$
    – 200_success
    9 hours ago


















3












$begingroup$


I've written code in C for reading a string of any length, and printing the string. It's one of my first C programs. I posted the program as part of a Stack Overflow question, and received a comment:




... there are many things wrong with your C version.




I'd really like to know what is wrong with the function I have written. Suspects: EOF handling, calling dynamic memory allocation functions too many times.



#include <stdlib.h>
#include <stdio.h>

/* Asks the user for string input.
* Returns a pointer to the string entered by the user.
* The pointer must be freed.
*/
char* input()
{
char *s = malloc(sizeof(char)); /* For the null character */
if (s == NULL) {
fprintf(stderr, "Error: mallocn");
exit(1);
}
s[0] = '';

/* Read characters one by one */
char ch;
size_t s_len = 0;
while((ch = (char) getchar()) != 'n') {
if (ch == EOF) {
exit(0);
}
s_len++;
s = realloc(s, (s_len * sizeof(char)) + sizeof(char));
if (s == NULL) {
fprintf(stderr, "Error: reallocn");
exit(1);
}
s[s_len - 1] = ch;
s[s_len] = '';
}
return s;
}

int main()
{
printf("Name: ");
char *s = input();
printf("%sn", s);
free(s);
return 0;
}









share|improve this question









New contributor



Flux is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






$endgroup$














  • $begingroup$
    Does the code work, to the best of your knowledge?
    $endgroup$
    – Null
    10 hours ago






  • 1




    $begingroup$
    @Null Yes it works.
    $endgroup$
    – Flux
    10 hours ago










  • $begingroup$
    You can simplify sizeof(char) to 1. You should also use an int to get the return value from getchar(). You also shouldn't cast. You should also use perror instead of fprintf(stderr, "Error: .
    $endgroup$
    – JL2210
    10 hours ago








  • 2




    $begingroup$
    Please see What to do when someone answers. I have rolled back Rev 2 → 1.
    $endgroup$
    – 200_success
    9 hours ago














3












3








3





$begingroup$


I've written code in C for reading a string of any length, and printing the string. It's one of my first C programs. I posted the program as part of a Stack Overflow question, and received a comment:




... there are many things wrong with your C version.




I'd really like to know what is wrong with the function I have written. Suspects: EOF handling, calling dynamic memory allocation functions too many times.



#include <stdlib.h>
#include <stdio.h>

/* Asks the user for string input.
* Returns a pointer to the string entered by the user.
* The pointer must be freed.
*/
char* input()
{
char *s = malloc(sizeof(char)); /* For the null character */
if (s == NULL) {
fprintf(stderr, "Error: mallocn");
exit(1);
}
s[0] = '';

/* Read characters one by one */
char ch;
size_t s_len = 0;
while((ch = (char) getchar()) != 'n') {
if (ch == EOF) {
exit(0);
}
s_len++;
s = realloc(s, (s_len * sizeof(char)) + sizeof(char));
if (s == NULL) {
fprintf(stderr, "Error: reallocn");
exit(1);
}
s[s_len - 1] = ch;
s[s_len] = '';
}
return s;
}

int main()
{
printf("Name: ");
char *s = input();
printf("%sn", s);
free(s);
return 0;
}









share|improve this question









New contributor



Flux is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






$endgroup$




I've written code in C for reading a string of any length, and printing the string. It's one of my first C programs. I posted the program as part of a Stack Overflow question, and received a comment:




... there are many things wrong with your C version.




I'd really like to know what is wrong with the function I have written. Suspects: EOF handling, calling dynamic memory allocation functions too many times.



#include <stdlib.h>
#include <stdio.h>

/* Asks the user for string input.
* Returns a pointer to the string entered by the user.
* The pointer must be freed.
*/
char* input()
{
char *s = malloc(sizeof(char)); /* For the null character */
if (s == NULL) {
fprintf(stderr, "Error: mallocn");
exit(1);
}
s[0] = '';

/* Read characters one by one */
char ch;
size_t s_len = 0;
while((ch = (char) getchar()) != 'n') {
if (ch == EOF) {
exit(0);
}
s_len++;
s = realloc(s, (s_len * sizeof(char)) + sizeof(char));
if (s == NULL) {
fprintf(stderr, "Error: reallocn");
exit(1);
}
s[s_len - 1] = ch;
s[s_len] = '';
}
return s;
}

int main()
{
printf("Name: ");
char *s = input();
printf("%sn", s);
free(s);
return 0;
}






beginner c strings io






share|improve this question









New contributor



Flux is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.










share|improve this question









New contributor



Flux is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.








share|improve this question




share|improve this question








edited 9 hours ago









200_success

136k21 gold badges175 silver badges445 bronze badges




136k21 gold badges175 silver badges445 bronze badges






New contributor



Flux is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.








asked 10 hours ago









FluxFlux

1193 bronze badges




1193 bronze badges




New contributor



Flux is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.




New contributor




Flux is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

















  • $begingroup$
    Does the code work, to the best of your knowledge?
    $endgroup$
    – Null
    10 hours ago






  • 1




    $begingroup$
    @Null Yes it works.
    $endgroup$
    – Flux
    10 hours ago










  • $begingroup$
    You can simplify sizeof(char) to 1. You should also use an int to get the return value from getchar(). You also shouldn't cast. You should also use perror instead of fprintf(stderr, "Error: .
    $endgroup$
    – JL2210
    10 hours ago








  • 2




    $begingroup$
    Please see What to do when someone answers. I have rolled back Rev 2 → 1.
    $endgroup$
    – 200_success
    9 hours ago


















  • $begingroup$
    Does the code work, to the best of your knowledge?
    $endgroup$
    – Null
    10 hours ago






  • 1




    $begingroup$
    @Null Yes it works.
    $endgroup$
    – Flux
    10 hours ago










  • $begingroup$
    You can simplify sizeof(char) to 1. You should also use an int to get the return value from getchar(). You also shouldn't cast. You should also use perror instead of fprintf(stderr, "Error: .
    $endgroup$
    – JL2210
    10 hours ago








  • 2




    $begingroup$
    Please see What to do when someone answers. I have rolled back Rev 2 → 1.
    $endgroup$
    – 200_success
    9 hours ago
















$begingroup$
Does the code work, to the best of your knowledge?
$endgroup$
– Null
10 hours ago




$begingroup$
Does the code work, to the best of your knowledge?
$endgroup$
– Null
10 hours ago




1




1




$begingroup$
@Null Yes it works.
$endgroup$
– Flux
10 hours ago




$begingroup$
@Null Yes it works.
$endgroup$
– Flux
10 hours ago












$begingroup$
You can simplify sizeof(char) to 1. You should also use an int to get the return value from getchar(). You also shouldn't cast. You should also use perror instead of fprintf(stderr, "Error: .
$endgroup$
– JL2210
10 hours ago






$begingroup$
You can simplify sizeof(char) to 1. You should also use an int to get the return value from getchar(). You also shouldn't cast. You should also use perror instead of fprintf(stderr, "Error: .
$endgroup$
– JL2210
10 hours ago






2




2




$begingroup$
Please see What to do when someone answers. I have rolled back Rev 2 → 1.
$endgroup$
– 200_success
9 hours ago




$begingroup$
Please see What to do when someone answers. I have rolled back Rev 2 → 1.
$endgroup$
– 200_success
9 hours ago










2 Answers
2






active

oldest

votes


















7














$begingroup$


/* Asks the user for string input.
* Returns a pointer to the string entered by the user.
* The pointer must be freed.
*/



Slightly misleading in that this function doesn't ask for input. (As written it is not responsible for printing the prompt.)



Perhaps also should clarify the intended behavior:




  • If there is input that is not terminated by a newline, is that string returned?

  • When input is terminated with a newline, is the newline preserved in the returned string?



char* input()
{
char *s = malloc(sizeof(char)); /* For the null character */



In C, char by definition is 1 byte. sizeof (char) is unnecessary and adds visual noise.




    if (s == NULL) {
fprintf(stderr, "Error: mallocn");
exit(1);



It's usually considered poor behavior if calling a library function causes the entire program to terminate. You should return an error value (e.g. NULL) and leave that decision up to the caller.




    }
s[0] = '';

/* Read characters one by one */
char ch;



ch must be an int. getchar returns an int precisely so that it can return a value outside the range of char to indicate failure (i.e., the EOF value). Otherwise you would not be able to distinguish EOF from a legitimate byte value.




    size_t s_len = 0;
while((ch = (char) getchar()) != 'n') {
if (ch == EOF) {



It's more idiomatic to check for EOF in the loop condition and then check for character values inside the loop body:



int ch;
while ((ch = getchar()) != EOF) {
if (ch == 'n') {
...


Checking for EOF in the loop condition allows you to safely truncate ch to char throughout the entire loop body, which makes it a bit easier to reason about.




            exit(0);



Same thing here about terminating the program. It's especially weird here since this exits with a success code and doesn't return the string to the caller.




        }
s_len++;
s = realloc(s, (s_len * sizeof(char)) + sizeof(char));



Never do x = realloc(x, ...). If realloc fails and returns NULL, you will have lost the old value of x and will be unable to free it, resulting in a memory leak. You instead should use a temporary variable:



char* newBuffer = realloc(s, ...);
if (newBuffer == NULL) {
...
}
s = newBuffer;


Again, sizeof (char) is noise. You additionally should generally avoid sizeof (Type); it's not robust if the types change since you would need to edit more places (and neglecting to do so could lead to silent buffer overflows and introduce security vulnerabilities). It's better to use sizeof expression where expression is based on the corresponding variable. For example, if you want the code to be robust if the type of s changes (e.g. if you wanted to adapt the code to support wchar_t), you should do:



char* newBuffer = realloc(s, (s_len + 1 /* NUL */) * sizeof *s);
...


Finally, calling realloc for every byte read is grossly inefficient. A better approach is to maintain a buffer where you keep track of its allocated size and to grow it exponentially (e.g. doubling in size) whenever you need more space.




        if (s == NULL) {
fprintf(stderr, "Error: reallocn");
exit(1);



Same thing about terminating the program. Also should do free(s); along this path.




int main()
{
printf("Name: ");



I/O is normally buffered. You should call fflush(stdout) afterward to ensure that the prompt is printed to the screen before waiting for input.






share|improve this answer










New contributor



jamesdlin is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





$endgroup$















  • $begingroup$
    Regarding getchar(): after checking that the character is not n or EOF, can I safely cast the int to a char? I mean at some point I would have to place chars into the char array that will be returned.
    $endgroup$
    – Flux
    9 hours ago












  • $begingroup$
    Thank you so much! I've written an improved version based on your advice: gist.github.com/flux77/9892a7dfb930935168059abe624aeae7
    $endgroup$
    – Flux
    9 hours ago










  • $begingroup$
    @Flux Yes, after checking that the character is not EOF, you can safely cast it to a char. (That is also why checking for EOF in the loop condition is more idiomatic. I've updated my answer to mention this.)
    $endgroup$
    – jamesdlin
    8 hours ago





















0














$begingroup$

Realistically, you would want to check that the input characters are acceptable to your program.






share|improve this answer








New contributor



Cplugs is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





$endgroup$


















    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "196"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: false,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/4.0/"u003ecc by-sa 4.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });







    Flux is a new contributor. Be nice, and check out our Code of Conduct.










    draft saved

    draft discarded
















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f228979%2fread-string-of-any-length-in-c%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    7














    $begingroup$


    /* Asks the user for string input.
    * Returns a pointer to the string entered by the user.
    * The pointer must be freed.
    */



    Slightly misleading in that this function doesn't ask for input. (As written it is not responsible for printing the prompt.)



    Perhaps also should clarify the intended behavior:




    • If there is input that is not terminated by a newline, is that string returned?

    • When input is terminated with a newline, is the newline preserved in the returned string?



    char* input()
    {
    char *s = malloc(sizeof(char)); /* For the null character */



    In C, char by definition is 1 byte. sizeof (char) is unnecessary and adds visual noise.




        if (s == NULL) {
    fprintf(stderr, "Error: mallocn");
    exit(1);



    It's usually considered poor behavior if calling a library function causes the entire program to terminate. You should return an error value (e.g. NULL) and leave that decision up to the caller.




        }
    s[0] = '';

    /* Read characters one by one */
    char ch;



    ch must be an int. getchar returns an int precisely so that it can return a value outside the range of char to indicate failure (i.e., the EOF value). Otherwise you would not be able to distinguish EOF from a legitimate byte value.




        size_t s_len = 0;
    while((ch = (char) getchar()) != 'n') {
    if (ch == EOF) {



    It's more idiomatic to check for EOF in the loop condition and then check for character values inside the loop body:



    int ch;
    while ((ch = getchar()) != EOF) {
    if (ch == 'n') {
    ...


    Checking for EOF in the loop condition allows you to safely truncate ch to char throughout the entire loop body, which makes it a bit easier to reason about.




                exit(0);



    Same thing here about terminating the program. It's especially weird here since this exits with a success code and doesn't return the string to the caller.




            }
    s_len++;
    s = realloc(s, (s_len * sizeof(char)) + sizeof(char));



    Never do x = realloc(x, ...). If realloc fails and returns NULL, you will have lost the old value of x and will be unable to free it, resulting in a memory leak. You instead should use a temporary variable:



    char* newBuffer = realloc(s, ...);
    if (newBuffer == NULL) {
    ...
    }
    s = newBuffer;


    Again, sizeof (char) is noise. You additionally should generally avoid sizeof (Type); it's not robust if the types change since you would need to edit more places (and neglecting to do so could lead to silent buffer overflows and introduce security vulnerabilities). It's better to use sizeof expression where expression is based on the corresponding variable. For example, if you want the code to be robust if the type of s changes (e.g. if you wanted to adapt the code to support wchar_t), you should do:



    char* newBuffer = realloc(s, (s_len + 1 /* NUL */) * sizeof *s);
    ...


    Finally, calling realloc for every byte read is grossly inefficient. A better approach is to maintain a buffer where you keep track of its allocated size and to grow it exponentially (e.g. doubling in size) whenever you need more space.




            if (s == NULL) {
    fprintf(stderr, "Error: reallocn");
    exit(1);



    Same thing about terminating the program. Also should do free(s); along this path.




    int main()
    {
    printf("Name: ");



    I/O is normally buffered. You should call fflush(stdout) afterward to ensure that the prompt is printed to the screen before waiting for input.






    share|improve this answer










    New contributor



    jamesdlin is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.





    $endgroup$















    • $begingroup$
      Regarding getchar(): after checking that the character is not n or EOF, can I safely cast the int to a char? I mean at some point I would have to place chars into the char array that will be returned.
      $endgroup$
      – Flux
      9 hours ago












    • $begingroup$
      Thank you so much! I've written an improved version based on your advice: gist.github.com/flux77/9892a7dfb930935168059abe624aeae7
      $endgroup$
      – Flux
      9 hours ago










    • $begingroup$
      @Flux Yes, after checking that the character is not EOF, you can safely cast it to a char. (That is also why checking for EOF in the loop condition is more idiomatic. I've updated my answer to mention this.)
      $endgroup$
      – jamesdlin
      8 hours ago


















    7














    $begingroup$


    /* Asks the user for string input.
    * Returns a pointer to the string entered by the user.
    * The pointer must be freed.
    */



    Slightly misleading in that this function doesn't ask for input. (As written it is not responsible for printing the prompt.)



    Perhaps also should clarify the intended behavior:




    • If there is input that is not terminated by a newline, is that string returned?

    • When input is terminated with a newline, is the newline preserved in the returned string?



    char* input()
    {
    char *s = malloc(sizeof(char)); /* For the null character */



    In C, char by definition is 1 byte. sizeof (char) is unnecessary and adds visual noise.




        if (s == NULL) {
    fprintf(stderr, "Error: mallocn");
    exit(1);



    It's usually considered poor behavior if calling a library function causes the entire program to terminate. You should return an error value (e.g. NULL) and leave that decision up to the caller.




        }
    s[0] = '';

    /* Read characters one by one */
    char ch;



    ch must be an int. getchar returns an int precisely so that it can return a value outside the range of char to indicate failure (i.e., the EOF value). Otherwise you would not be able to distinguish EOF from a legitimate byte value.




        size_t s_len = 0;
    while((ch = (char) getchar()) != 'n') {
    if (ch == EOF) {



    It's more idiomatic to check for EOF in the loop condition and then check for character values inside the loop body:



    int ch;
    while ((ch = getchar()) != EOF) {
    if (ch == 'n') {
    ...


    Checking for EOF in the loop condition allows you to safely truncate ch to char throughout the entire loop body, which makes it a bit easier to reason about.




                exit(0);



    Same thing here about terminating the program. It's especially weird here since this exits with a success code and doesn't return the string to the caller.




            }
    s_len++;
    s = realloc(s, (s_len * sizeof(char)) + sizeof(char));



    Never do x = realloc(x, ...). If realloc fails and returns NULL, you will have lost the old value of x and will be unable to free it, resulting in a memory leak. You instead should use a temporary variable:



    char* newBuffer = realloc(s, ...);
    if (newBuffer == NULL) {
    ...
    }
    s = newBuffer;


    Again, sizeof (char) is noise. You additionally should generally avoid sizeof (Type); it's not robust if the types change since you would need to edit more places (and neglecting to do so could lead to silent buffer overflows and introduce security vulnerabilities). It's better to use sizeof expression where expression is based on the corresponding variable. For example, if you want the code to be robust if the type of s changes (e.g. if you wanted to adapt the code to support wchar_t), you should do:



    char* newBuffer = realloc(s, (s_len + 1 /* NUL */) * sizeof *s);
    ...


    Finally, calling realloc for every byte read is grossly inefficient. A better approach is to maintain a buffer where you keep track of its allocated size and to grow it exponentially (e.g. doubling in size) whenever you need more space.




            if (s == NULL) {
    fprintf(stderr, "Error: reallocn");
    exit(1);



    Same thing about terminating the program. Also should do free(s); along this path.




    int main()
    {
    printf("Name: ");



    I/O is normally buffered. You should call fflush(stdout) afterward to ensure that the prompt is printed to the screen before waiting for input.






    share|improve this answer










    New contributor



    jamesdlin is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.





    $endgroup$















    • $begingroup$
      Regarding getchar(): after checking that the character is not n or EOF, can I safely cast the int to a char? I mean at some point I would have to place chars into the char array that will be returned.
      $endgroup$
      – Flux
      9 hours ago












    • $begingroup$
      Thank you so much! I've written an improved version based on your advice: gist.github.com/flux77/9892a7dfb930935168059abe624aeae7
      $endgroup$
      – Flux
      9 hours ago










    • $begingroup$
      @Flux Yes, after checking that the character is not EOF, you can safely cast it to a char. (That is also why checking for EOF in the loop condition is more idiomatic. I've updated my answer to mention this.)
      $endgroup$
      – jamesdlin
      8 hours ago
















    7














    7










    7







    $begingroup$


    /* Asks the user for string input.
    * Returns a pointer to the string entered by the user.
    * The pointer must be freed.
    */



    Slightly misleading in that this function doesn't ask for input. (As written it is not responsible for printing the prompt.)



    Perhaps also should clarify the intended behavior:




    • If there is input that is not terminated by a newline, is that string returned?

    • When input is terminated with a newline, is the newline preserved in the returned string?



    char* input()
    {
    char *s = malloc(sizeof(char)); /* For the null character */



    In C, char by definition is 1 byte. sizeof (char) is unnecessary and adds visual noise.




        if (s == NULL) {
    fprintf(stderr, "Error: mallocn");
    exit(1);



    It's usually considered poor behavior if calling a library function causes the entire program to terminate. You should return an error value (e.g. NULL) and leave that decision up to the caller.




        }
    s[0] = '';

    /* Read characters one by one */
    char ch;



    ch must be an int. getchar returns an int precisely so that it can return a value outside the range of char to indicate failure (i.e., the EOF value). Otherwise you would not be able to distinguish EOF from a legitimate byte value.




        size_t s_len = 0;
    while((ch = (char) getchar()) != 'n') {
    if (ch == EOF) {



    It's more idiomatic to check for EOF in the loop condition and then check for character values inside the loop body:



    int ch;
    while ((ch = getchar()) != EOF) {
    if (ch == 'n') {
    ...


    Checking for EOF in the loop condition allows you to safely truncate ch to char throughout the entire loop body, which makes it a bit easier to reason about.




                exit(0);



    Same thing here about terminating the program. It's especially weird here since this exits with a success code and doesn't return the string to the caller.




            }
    s_len++;
    s = realloc(s, (s_len * sizeof(char)) + sizeof(char));



    Never do x = realloc(x, ...). If realloc fails and returns NULL, you will have lost the old value of x and will be unable to free it, resulting in a memory leak. You instead should use a temporary variable:



    char* newBuffer = realloc(s, ...);
    if (newBuffer == NULL) {
    ...
    }
    s = newBuffer;


    Again, sizeof (char) is noise. You additionally should generally avoid sizeof (Type); it's not robust if the types change since you would need to edit more places (and neglecting to do so could lead to silent buffer overflows and introduce security vulnerabilities). It's better to use sizeof expression where expression is based on the corresponding variable. For example, if you want the code to be robust if the type of s changes (e.g. if you wanted to adapt the code to support wchar_t), you should do:



    char* newBuffer = realloc(s, (s_len + 1 /* NUL */) * sizeof *s);
    ...


    Finally, calling realloc for every byte read is grossly inefficient. A better approach is to maintain a buffer where you keep track of its allocated size and to grow it exponentially (e.g. doubling in size) whenever you need more space.




            if (s == NULL) {
    fprintf(stderr, "Error: reallocn");
    exit(1);



    Same thing about terminating the program. Also should do free(s); along this path.




    int main()
    {
    printf("Name: ");



    I/O is normally buffered. You should call fflush(stdout) afterward to ensure that the prompt is printed to the screen before waiting for input.






    share|improve this answer










    New contributor



    jamesdlin is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.





    $endgroup$




    /* Asks the user for string input.
    * Returns a pointer to the string entered by the user.
    * The pointer must be freed.
    */



    Slightly misleading in that this function doesn't ask for input. (As written it is not responsible for printing the prompt.)



    Perhaps also should clarify the intended behavior:




    • If there is input that is not terminated by a newline, is that string returned?

    • When input is terminated with a newline, is the newline preserved in the returned string?



    char* input()
    {
    char *s = malloc(sizeof(char)); /* For the null character */



    In C, char by definition is 1 byte. sizeof (char) is unnecessary and adds visual noise.




        if (s == NULL) {
    fprintf(stderr, "Error: mallocn");
    exit(1);



    It's usually considered poor behavior if calling a library function causes the entire program to terminate. You should return an error value (e.g. NULL) and leave that decision up to the caller.




        }
    s[0] = '';

    /* Read characters one by one */
    char ch;



    ch must be an int. getchar returns an int precisely so that it can return a value outside the range of char to indicate failure (i.e., the EOF value). Otherwise you would not be able to distinguish EOF from a legitimate byte value.




        size_t s_len = 0;
    while((ch = (char) getchar()) != 'n') {
    if (ch == EOF) {



    It's more idiomatic to check for EOF in the loop condition and then check for character values inside the loop body:



    int ch;
    while ((ch = getchar()) != EOF) {
    if (ch == 'n') {
    ...


    Checking for EOF in the loop condition allows you to safely truncate ch to char throughout the entire loop body, which makes it a bit easier to reason about.




                exit(0);



    Same thing here about terminating the program. It's especially weird here since this exits with a success code and doesn't return the string to the caller.




            }
    s_len++;
    s = realloc(s, (s_len * sizeof(char)) + sizeof(char));



    Never do x = realloc(x, ...). If realloc fails and returns NULL, you will have lost the old value of x and will be unable to free it, resulting in a memory leak. You instead should use a temporary variable:



    char* newBuffer = realloc(s, ...);
    if (newBuffer == NULL) {
    ...
    }
    s = newBuffer;


    Again, sizeof (char) is noise. You additionally should generally avoid sizeof (Type); it's not robust if the types change since you would need to edit more places (and neglecting to do so could lead to silent buffer overflows and introduce security vulnerabilities). It's better to use sizeof expression where expression is based on the corresponding variable. For example, if you want the code to be robust if the type of s changes (e.g. if you wanted to adapt the code to support wchar_t), you should do:



    char* newBuffer = realloc(s, (s_len + 1 /* NUL */) * sizeof *s);
    ...


    Finally, calling realloc for every byte read is grossly inefficient. A better approach is to maintain a buffer where you keep track of its allocated size and to grow it exponentially (e.g. doubling in size) whenever you need more space.




            if (s == NULL) {
    fprintf(stderr, "Error: reallocn");
    exit(1);



    Same thing about terminating the program. Also should do free(s); along this path.




    int main()
    {
    printf("Name: ");



    I/O is normally buffered. You should call fflush(stdout) afterward to ensure that the prompt is printed to the screen before waiting for input.







    share|improve this answer










    New contributor



    jamesdlin is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.








    share|improve this answer



    share|improve this answer








    edited 8 hours ago





















    New contributor



    jamesdlin is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.








    answered 10 hours ago









    jamesdlinjamesdlin

    1714 bronze badges




    1714 bronze badges




    New contributor



    jamesdlin is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.




    New contributor




    jamesdlin is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.

















    • $begingroup$
      Regarding getchar(): after checking that the character is not n or EOF, can I safely cast the int to a char? I mean at some point I would have to place chars into the char array that will be returned.
      $endgroup$
      – Flux
      9 hours ago












    • $begingroup$
      Thank you so much! I've written an improved version based on your advice: gist.github.com/flux77/9892a7dfb930935168059abe624aeae7
      $endgroup$
      – Flux
      9 hours ago










    • $begingroup$
      @Flux Yes, after checking that the character is not EOF, you can safely cast it to a char. (That is also why checking for EOF in the loop condition is more idiomatic. I've updated my answer to mention this.)
      $endgroup$
      – jamesdlin
      8 hours ago




















    • $begingroup$
      Regarding getchar(): after checking that the character is not n or EOF, can I safely cast the int to a char? I mean at some point I would have to place chars into the char array that will be returned.
      $endgroup$
      – Flux
      9 hours ago












    • $begingroup$
      Thank you so much! I've written an improved version based on your advice: gist.github.com/flux77/9892a7dfb930935168059abe624aeae7
      $endgroup$
      – Flux
      9 hours ago










    • $begingroup$
      @Flux Yes, after checking that the character is not EOF, you can safely cast it to a char. (That is also why checking for EOF in the loop condition is more idiomatic. I've updated my answer to mention this.)
      $endgroup$
      – jamesdlin
      8 hours ago


















    $begingroup$
    Regarding getchar(): after checking that the character is not n or EOF, can I safely cast the int to a char? I mean at some point I would have to place chars into the char array that will be returned.
    $endgroup$
    – Flux
    9 hours ago






    $begingroup$
    Regarding getchar(): after checking that the character is not n or EOF, can I safely cast the int to a char? I mean at some point I would have to place chars into the char array that will be returned.
    $endgroup$
    – Flux
    9 hours ago














    $begingroup$
    Thank you so much! I've written an improved version based on your advice: gist.github.com/flux77/9892a7dfb930935168059abe624aeae7
    $endgroup$
    – Flux
    9 hours ago




    $begingroup$
    Thank you so much! I've written an improved version based on your advice: gist.github.com/flux77/9892a7dfb930935168059abe624aeae7
    $endgroup$
    – Flux
    9 hours ago












    $begingroup$
    @Flux Yes, after checking that the character is not EOF, you can safely cast it to a char. (That is also why checking for EOF in the loop condition is more idiomatic. I've updated my answer to mention this.)
    $endgroup$
    – jamesdlin
    8 hours ago






    $begingroup$
    @Flux Yes, after checking that the character is not EOF, you can safely cast it to a char. (That is also why checking for EOF in the loop condition is more idiomatic. I've updated my answer to mention this.)
    $endgroup$
    – jamesdlin
    8 hours ago















    0














    $begingroup$

    Realistically, you would want to check that the input characters are acceptable to your program.






    share|improve this answer








    New contributor



    Cplugs is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.





    $endgroup$




















      0














      $begingroup$

      Realistically, you would want to check that the input characters are acceptable to your program.






      share|improve this answer








      New contributor



      Cplugs is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.





      $endgroup$


















        0














        0










        0







        $begingroup$

        Realistically, you would want to check that the input characters are acceptable to your program.






        share|improve this answer








        New contributor



        Cplugs is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.





        $endgroup$



        Realistically, you would want to check that the input characters are acceptable to your program.







        share|improve this answer








        New contributor



        Cplugs is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.








        share|improve this answer



        share|improve this answer






        New contributor



        Cplugs is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.








        answered 1 hour ago









        CplugsCplugs

        1




        1




        New contributor



        Cplugs is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.




        New contributor




        Cplugs is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.




























            Flux is a new contributor. Be nice, and check out our Code of Conduct.










            draft saved

            draft discarded

















            Flux is a new contributor. Be nice, and check out our Code of Conduct.













            Flux is a new contributor. Be nice, and check out our Code of Conduct.












            Flux is a new contributor. Be nice, and check out our Code of Conduct.
















            Thanks for contributing an answer to Code Review Stack Exchange!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            Use MathJax to format equations. MathJax reference.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f228979%2fread-string-of-any-length-in-c%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Hudson River Historic District Contents Geography History The district today Aesthetics Cultural...

            The number designs the writing. Feandra Aversely Definition: The act of ingrafting a sprig or shoot of one...

            Ayherre Geografie Demografie Externe links Navigatiemenu43° 23′ NB, 1° 15′ WL43° 23′ NB, 1°...