473,769 Members | 1,618 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Proper way to input a dynamically-allocated string

I know it must sound like a newbie question, but I never really had to
bother with that before, and I didn't even find an answer in the c.l.c
FAQ

I'd like to know what's the really proper way for input a string in an
array of char that's dynamically allocated. I mean, I wish not to see
any such things as char mystring[100]; I don't want to see any number
(if possible) I just want to declare something like char *mystring; and
then I don't know how allocate it with just as many chars (with the
space for the \0 of course) as you get from stdin.

I'd really like to know once for all what's the smartest way of
inputing strings from stdin and storing them in a way so they take just
the needed space and I don't want to see any number such as 100 or
10,000 or even 4,294,967,296 in my code. Any way it can be done?

Dec 9 '05 #1
48 2253
"Michel Rouzic" <Mi********@yah oo.fr> writes:
I'd like to know what's the really proper way for input a string in an
array of char that's dynamically allocated. I mean, I wish not to see
any such things as char mystring[100]; I don't want to see any number
(if possible) I just want to declare something like char *mystring; and
then I don't know how allocate it with just as many chars (with the
space for the \0 of course) as you get from stdin.


One common idiom is the following:

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

void *
frealloc(void *ptr, size_t sz)
{
void *tmp;

if ((tmp = realloc(ptr, sz)) != NULL)
return (tmp);
free(ptr);
return (NULL);
}

char *
getline(FILE *f)
{
char *str = NULL;
size_t sz = 0;
int ch;

for (size_t len = 0; ; ++len) {
ch = fgetc(f);
if (ch == EOF && !len)
return (NULL);
if (len == sz)
str = frealloc(str, sz = sz * 2 + 1);
if (ch == EOF || ch == '\n') {
str[len] = '\0';
return (str);
} else {
str[len] = ch;
}
}
}

However, on average, about 25% of the allocated memory will be wasted.
You can fix that by replacing

return (str);
with
return (frealloc(str, len + 1));

but you may still end up losing quite a bit to heap fragmentation,
depending on how good your system's malloc() implementation is.

DES
--
Dag-Erling Smørgrav - de*@des.no
Dec 9 '05 #2
Michel Rouzic wrote:
I know it must sound like a newbie question, but I never really had to
bother with that before, and I didn't even find an answer in the c.l.c
FAQ

I'd like to know what's the really proper way for input a string in an
array of char that's dynamically allocated. I mean, I wish not to see
any such things as char mystring[100]; I don't want to see any number
(if possible) I just want to declare something like char *mystring; and
then I don't know how allocate it with just as many chars (with the
space for the \0 of course) as you get from stdin.

I'd really like to know once for all what's the smartest way of
inputing strings from stdin and storing them in a way so they take just
the needed space and I don't want to see any number such as 100 or
10,000 or even 4,294,967,296 in my code. Any way it can be done?


Let's suppose you're reading complete '\n'-terminated lines,
the way fgets() does but with no explicit length limit. You
could do something like this (pseudocode, no error checking):

buffer = <empty>
do {
expand buffer with realloc()
append next input character
} while (character wasn't '\n');
expand buffer with realloc()
append '\0'

For efficiency's sake you'd probably want to avoid quite
so many trips in and out of the memory allocator, so a refinement
would be to start with a roomier buffer and expand by more than
one character at a time if necessary. (My own function for doing
this -- everybody writes one eventually -- begins with 100 characters
and adds half the buffer's current size each time it needs to expand:
100, 150, 225, ...)

Once you've read the entire line you can, if you like, realloc()
the buffer one final time to trim it to the exact size. I find
that's seldom worth the bother: your program is probably going to
process the line and free() or re-use the buffer pretty soon.

--
Eric Sosman
es*****@acm-dot-org.invalid

Dec 9 '05 #3
Michel Rouzic wrote:
I know it must sound like a newbie question, but I never really had to
bother with that before, and I didn't even find an answer in the c.l.c
FAQ

I'd like to know what's the really proper way for input a string in an
array of char that's dynamically allocated. I mean, I wish not to see
any such things as char mystring[100]; I don't want to see any number
(if possible) I just want to declare something like char *mystring; and
then I don't know how allocate it with just as many chars (with the
space for the \0 of course) as you get from stdin.

I'd really like to know once for all what's the smartest way of
inputing strings from stdin and storing them in a way so they take just
the needed space and I don't want to see any number such as 100 or
10,000 or even 4,294,967,296 in my code. Any way it can be done? From stdin is a bit of a problem. The usual answer is to use a buffer

to temporarily store the string:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define BUFFER_SIZE 100

int main () {
char buffer[BUFFER_SIZE];
char *inputString = NULL;
size_t inLen = 0;

while (fgets(buffer, BUFFER_SIZE, stdin) != NULL) {
inLen += strlen(buffer);
if (inputString == NULL) {
inputString = malloc(inLen);
inputString[0] = '\0';
} else {
inputString = realloc(inputSt ring, inLen);
}
if (inputString == NULL) {
/* malloc or realloc failed */
exit(-1);
}
strcat(inputStr ing, buffer);
/* check for newline */
if(inputString[inLen-1] == '\n') {

/* process input here */

/* then remember to free inputString */
free(inputStrin g);
inputString = NULL;
}
}
}

Dec 9 '05 #4

Eric Sosman wrote:
Michel Rouzic wrote:
I know it must sound like a newbie question, but I never really had to
bother with that before, and I didn't even find an answer in the c.l.c
FAQ

I'd like to know what's the really proper way for input a string in an
array of char that's dynamically allocated. I mean, I wish not to see
any such things as char mystring[100]; I don't want to see any number
(if possible) I just want to declare something like char *mystring; and
then I don't know how allocate it with just as many chars (with the
space for the \0 of course) as you get from stdin.

I'd really like to know once for all what's the smartest way of
inputing strings from stdin and storing them in a way so they take just
the needed space and I don't want to see any number such as 100 or
10,000 or even 4,294,967,296 in my code. Any way it can be done?


Let's suppose you're reading complete '\n'-terminated lines,
the way fgets() does but with no explicit length limit. You
could do something like this (pseudocode, no error checking):

buffer = <empty>
do {
expand buffer with realloc()
append next input character
} while (character wasn't '\n');
expand buffer with realloc()
append '\0'

For efficiency's sake you'd probably want to avoid quite
so many trips in and out of the memory allocator, so a refinement
would be to start with a roomier buffer and expand by more than
one character at a time if necessary. (My own function for doing
this -- everybody writes one eventually -- begins with 100 characters
and adds half the buffer's current size each time it needs to expand:
100, 150, 225, ...)

Once you've read the entire line you can, if you like, realloc()
the buffer one final time to trim it to the exact size. I find
that's seldom worth the bother: your program is probably going to
process the line and free() or re-use the buffer pretty soon.


That's the method I like the best. I wouldn't bother with make larger
buffers anyways, would make things too complicated, and things don't
have to be sooo efficient when it comes to inputting strings, what
matters the most is the result. i think I made your idea work pretty
good, tell me if you think yous potted anything wrong with it, I GDBed
it and the content of the memory looked fine

int i;
char *mystring;

i=0;
mystring=NULL;
do
{
mystring=reallo c(mystring, i+1);
mystring[i]=getchar();
i++;
}
while (mystring[i-1]!='\n');
mystring[i-1]='\0';

Dec 9 '05 #5
"Michel Rouzic" <Mi********@yah oo.fr> writes:
[snip]
That's the method I like the best. I wouldn't bother with make larger
buffers anyways, would make things too complicated, and things don't
have to be sooo efficient when it comes to inputting strings, what
matters the most is the result. i think I made your idea work pretty
good, tell me if you think yous potted anything wrong with it, I GDBed
it and the content of the memory looked fine

int i;
char *mystring;

i=0;
mystring=NULL;
do
{
mystring=reallo c(mystring, i+1);
mystring[i]=getchar();
i++;
}
while (mystring[i-1]!='\n');
mystring[i-1]='\0';


The speed of that code while reading input probably isn't going to be
much of an issue, but the multiple calls to realloc() might cause
excessive heap fragmentation, which could cause problems elsewhere in
your program. (The standard does use the term "heap", but you get the
idea.)

--
Keith Thompson (The_Other_Keit h) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Dec 9 '05 #6
Michel Rouzic wrote:
Eric Sosman wrote:
Michel Rouzic wrote:

I know it must sound like a newbie question, but I never really had to
bother with that before, and I didn't even find an answer in the c.l.c
FAQ

I'd like to know what's the really proper way for input a string in an
array of char that's dynamically allocated. I mean, I wish not to see
any such things as char mystring[100]; I don't want to see any number
(if possible) I just want to declare something like char *mystring; and
then I don't know how allocate it with just as many chars (with the
space for the \0 of course) as you get from stdin.

I'd really like to know once for all what's the smartest way of
inputing strings from stdin and storing them in a way so they take just
the needed space and I don't want to see any number such as 100 or
10,000 or even 4,294,967,296 in my code. Any way it can be done?


Let's suppose you're reading complete '\n'-terminated lines,
the way fgets() does but with no explicit length limit. You
could do something like this (pseudocode, no error checking):

buffer = <empty>
do {
expand buffer with realloc()
append next input character
} while (character wasn't '\n');
expand buffer with realloc()
append '\0'

For efficiency's sake you'd probably want to avoid quite
so many trips in and out of the memory allocator, so a refinement
would be to start with a roomier buffer and expand by more than
one character at a time if necessary. (My own function for doing
this -- everybody writes one eventually -- begins with 100 characters
and adds half the buffer's current size each time it needs to expand:
100, 150, 225, ...)

Once you've read the entire line you can, if you like, realloc()
the buffer one final time to trim it to the exact size. I find
that's seldom worth the bother: your program is probably going to
process the line and free() or re-use the buffer pretty soon.

That's the method I like the best. I wouldn't bother with make larger
buffers anyways, would make things too complicated, and things don't
have to be sooo efficient when it comes to inputting strings, what
matters the most is the result. i think I made your idea work pretty
good, tell me if you think yous potted anything wrong with it, I GDBed
it and the content of the memory looked fine

int i;
char *mystring;

i=0;
mystring=NULL;
do
{
mystring=reallo c(mystring, i+1);
mystring[i]=getchar();
i++;
}
while (mystring[i-1]!='\n');
mystring[i-1]='\0';


That's the general idea. As written, though, it's not
very robust: it's oblivious to realloc() failures and to
end-of-file or errors on the standard input. Pay attention
to the Sixth Commandment at

http://www.lysator.liu.se/c/ten-commandments.html

Other observations: `int' should probably be `size_t',
and see Keith Thompson's response for one of the reasons a
character-at-a-time expansion may not work well. ("Others
will occur to your thought." -- Gandalf)

--
Eric Sosman
es*****@acm-dot-org.invalid
Dec 9 '05 #7

Keith Thompson wrote:
"Michel Rouzic" <Mi********@yah oo.fr> writes:
[snip]
That's the method I like the best. I wouldn't bother with make larger
buffers anyways, would make things too complicated, and things don't
have to be sooo efficient when it comes to inputting strings, what
matters the most is the result. i think I made your idea work pretty
good, tell me if you think yous potted anything wrong with it, I GDBed
it and the content of the memory looked fine

int i;
char *mystring;

i=0;
mystring=NULL;
do
{
mystring=reallo c(mystring, i+1);
mystring[i]=getchar();
i++;
}
while (mystring[i-1]!='\n');
mystring[i-1]='\0';


The speed of that code while reading input probably isn't going to be
much of an issue, but the multiple calls to realloc() might cause
excessive heap fragmentation, which could cause problems elsewhere in
your program. (The standard does use the term "heap", but you get the
idea.)


does it mean that the elements of my array won't be contigous?

Dec 9 '05 #8

Eric Sosman wrote:
Michel Rouzic wrote:
Eric Sosman wrote:
Michel Rouzic wrote:
I know it must sound like a newbie question, but I never really had to
bother with that before, and I didn't even find an answer in the c.l.c
FAQ

I'd like to know what's the really proper way for input a string in an
array of char that's dynamically allocated. I mean, I wish not to see
any such things as char mystring[100]; I don't want to see any number
(if possible) I just want to declare something like char *mystring; and
then I don't know how allocate it with just as many chars (with the
space for the \0 of course) as you get from stdin.

I'd really like to know once for all what's the smartest way of
inputing strings from stdin and storing them in a way so they take just
the needed space and I don't want to see any number such as 100 or
10,000 or even 4,294,967,296 in my code. Any way it can be done?

Let's suppose you're reading complete '\n'-terminated lines,
the way fgets() does but with no explicit length limit. You
could do something like this (pseudocode, no error checking):

buffer = <empty>
do {
expand buffer with realloc()
append next input character
} while (character wasn't '\n');
expand buffer with realloc()
append '\0'

For efficiency's sake you'd probably want to avoid quite
so many trips in and out of the memory allocator, so a refinement
would be to start with a roomier buffer and expand by more than
one character at a time if necessary. (My own function for doing
this -- everybody writes one eventually -- begins with 100 characters
and adds half the buffer's current size each time it needs to expand:
100, 150, 225, ...)

Once you've read the entire line you can, if you like, realloc()
the buffer one final time to trim it to the exact size. I find
that's seldom worth the bother: your program is probably going to
process the line and free() or re-use the buffer pretty soon.

That's the method I like the best. I wouldn't bother with make larger
buffers anyways, would make things too complicated, and things don't
have to be sooo efficient when it comes to inputting strings, what
matters the most is the result. i think I made your idea work pretty
good, tell me if you think yous potted anything wrong with it, I GDBed
it and the content of the memory looked fine

int i;
char *mystring;

i=0;
mystring=NULL;
do
{
mystring=reallo c(mystring, i+1);
mystring[i]=getchar();
i++;
}
while (mystring[i-1]!='\n');
mystring[i-1]='\0';


That's the general idea. As written, though, it's not
very robust: it's oblivious to realloc() failures and to
end-of-file or errors on the standard input. Pay attention
to the Sixth Commandment

"If a function be advertised to return an error code in the event of
difficulties, thou shalt check for that code, yea, even though the
checks triple the size of thy code..."

ok, I guess I should do that but.... well... as it says, it makes the
code much longer and makes it harder to read and, well, I wouldn't know
what to do with an error anyways, I mean, if the return code ain't
right, i might display something like "the return code ain't right\n"
and don't know what I should do.

realloc() failures? never heard of that (maybe cuz im quite new to all
that), what can happen with it? how can you get an EOF or some error
from stdin?

you know, I care to know about why I should check for errors, and about
what can cause them and what I should do about it, but so far (and you
can understand that) I like to keep my code as simple as possible,
mostly that I consider that my program should work only as far as it is
used correctly (like, if a program is supposed to have a .wav file in
input, and the user put a .mp3 or anything else instead, I don't wanna
bother with doing stuff that will tell him "you need to input a .wav
file", i rather let him have a segmentation fault)

Dec 9 '05 #9

Eric Sosman wrote:
Other observations: `int' should probably be `size_t'


as for the size_t thing, well i could cast it for realloc, like this :
mystring=reallo c(mystring, (size_t) i+1); other than that, I think i
should leave it to int, unless it is ok to do iterations and refer to
some element of an array by a size_t, which i doubt

Dec 9 '05 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
2404
by: Peter Kirk | last post by:
Hi there I have a form which submits a list of data to a web-application (which then saves to a database). The list consists of four input fields per row. Eg. <field_1.1><field_2.1><field_3.1><field_4.1> <field_1.2><field_2.2><field_3.2><field_4.2> <field_1.3><field_2.3><field_3.3><field_4.3> ....
6
3334
by: Thomas | last post by:
Hi, I'm having a problem with the dynamically created inputfields in Internet Explorer. The situation is the following: - I have a dynamically created table with a textbox in each Cell. - It is possible to Add and Delete rows - Some cells have special attributes (readonly and events) Here's a snippet of the code:
5
2101
by: cjl | last post by:
Hey all: This code: if (stealth) { document.searchme.query.type = 'password'; } else {
2
8379
by: crjunk | last post by:
I'm trying to find a way to create input boxes dynamically on the client side but everything that I've come across works with IE, but not FireFox. On my web page, I have the following input boxes: txtAddress1, txtCity1,txtState1, txtZip1 What I'd like to do is to have a button that says "Add Another Location". When the user clicks on the button, then txtAddress2, txtCity2, txtState2, and txtZip2 are created below the first location
1
7495
by: vega80 | last post by:
Hi. I have a problem with assigning an onkeypress-function to dynamically created input-boxes.I want to put the content of an input-field into a tag-list when the user hits enter. This works fine the first time (when the input-field is created in a non-dynamical way). The next input-field is created dynamically by a function that is called when the user hits enter (the previously generated input-field will be hidden). Then I'm trying...
1
1810
by: Steve2007 | last post by:
Hi I have the following form in my html page: <form name="mapserv" method=GET action=""> <input type="hidden" name="timeFiltering"> <input type="hidden" name="filteringType"> <input type="hidden" name="filteringBox"> <input type="hidden" name="Geofence" value="1|Geofence1|-88.19311|30.52311|-87.91011|30.65221|10|3"> <input type="hidden" name="Geofence1" value="1|Geofence1|-88.19311|30.52311|-87.91011|30.65221|10|2">
2
2541
by: Ed Jay | last post by:
I'm dynamically creating several form input elements: mValue = integer constant; for(var j = 0; j < mValue; j++) { target = "imgCn"+ j; eName = "myFile"; eName = eName+jj; document.getElementById(target).innerHTML = "<input type = 'file' name="+eName+" value=''>text"; }
1
1322
by: =?Utf-8?B?QXJuZSBHYXJ2YW5kZXI=?= | last post by:
I am programming input forms in Asp.net 2.0 Some textboxes are static on the form and viewstate works fine. Some textboxes have to be dynamically added to the form at run-time which makes viewstate difficult to maintain. Sometimes I have got viewstate to magically work. Sometime I have to manually restore viewstate. What is the best way to deal with dynamically created input boxes? -- Arne Garvander Certified Geek
4
2975
by: mohaaron | last post by:
I can think of a lot of reasons why this might need to be done but as far as I can tell it's not possible. I've been looking for a way to add HtmlTableRows to a table using a button click for a while and it seems it's not possible because the row that gets added with each click won't get recreated after a post back. After all the reading it seems that any dynamically created controls must be created in the Init event to be recreated after...
0
864
by: davidson1 | last post by:
Hai to Everybody, I am designing a website in ASP.NET , in my project students can view their information such as name,department etc... and many information for students will be displayed... all that information will be taken from database and displayed in ASP.NET so all the tables in asp.net are dynamically created , so i need give good color to dynamically created table in a proper way...... So that it good web design........ if u...
0
10211
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
10045
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
9994
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
8870
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
0
5298
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
5447
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
3958
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
3561
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2815
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.