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;
}
$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;
}
beginner c strings io
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$
add a comment
|
$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;
}
beginner c strings io
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 simplifysizeof(char)to1. You should also use anintto get the return value fromgetchar(). You also shouldn't cast. You should also useperrorinstead offprintf(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
add a comment
|
$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;
}
beginner c strings io
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
beginner c strings io
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.
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 simplifysizeof(char)to1. You should also use anintto get the return value fromgetchar(). You also shouldn't cast. You should also useperrorinstead offprintf(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
add a comment
|
$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 simplifysizeof(char)to1. You should also use anintto get the return value fromgetchar(). You also shouldn't cast. You should also useperrorinstead offprintf(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
add a comment
|
2 Answers
2
active
oldest
votes
$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.
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$
Regardinggetchar(): after checking that the character is notnorEOF, 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 notEOF, you can safely cast it to achar. (That is also why checking forEOFin the loop condition is more idiomatic. I've updated my answer to mention this.)
$endgroup$
– jamesdlin
8 hours ago
add a comment
|
$begingroup$
Realistically, you would want to check that the input characters are acceptable to your program.
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$
add a comment
|
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
$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.
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$
Regardinggetchar(): after checking that the character is notnorEOF, 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 notEOF, you can safely cast it to achar. (That is also why checking forEOFin the loop condition is more idiomatic. I've updated my answer to mention this.)
$endgroup$
– jamesdlin
8 hours ago
add a comment
|
$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.
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$
Regardinggetchar(): after checking that the character is notnorEOF, 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 notEOF, you can safely cast it to achar. (That is also why checking forEOFin the loop condition is more idiomatic. I've updated my answer to mention this.)
$endgroup$
– jamesdlin
8 hours ago
add a comment
|
$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.
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.
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.
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$
Regardinggetchar(): after checking that the character is notnorEOF, 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 notEOF, you can safely cast it to achar. (That is also why checking forEOFin the loop condition is more idiomatic. I've updated my answer to mention this.)
$endgroup$
– jamesdlin
8 hours ago
add a comment
|
$begingroup$
Regardinggetchar(): after checking that the character is notnorEOF, 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 notEOF, you can safely cast it to achar. (That is also why checking forEOFin 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
add a comment
|
$begingroup$
Realistically, you would want to check that the input characters are acceptable to your program.
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$
add a comment
|
$begingroup$
Realistically, you would want to check that the input characters are acceptable to your program.
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$
add a comment
|
$begingroup$
Realistically, you would want to check that the input characters are acceptable to your program.
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.
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.
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.
add a comment
|
add a comment
|
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.
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
$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)to1. You should also use anintto get the return value fromgetchar(). You also shouldn't cast. You should also useperrorinstead offprintf(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