How to input strings of any lengths into arrays of type: char *array[SIZE] ?

A

arkobose

hey everyone!
i have this little problem. consider the following declaration:

char *array[4] = {"wilson", "string of any size", "etc", "input"};

this is a common data structure used to store strings of any lengths
into an array of pointers to char type variable.

my problem is: given the declaration

char *array[SIZE];
how to store strings of any length into this array from the user input
using functions like "scanf", "gets" etc. ?

let me know if you get it!

-thanks,
arko
 
M

Michael Mair

hey everyone!
i have this little problem. consider the following declaration:

char *array[4] = {"wilson", "string of any size", "etc", "input"};

this is a common data structure used to store strings of any lengths
into an array of pointers to char type variable.

Nope. You do not store strings but pointers to the respective first
character of these strings.
Consider the difference between.
char *cannot_be_modified = "foo";
and
char just_an_array[] = "foo";

my problem is: given the declaration

char *array[SIZE];
how to store strings of any length into this array from the user input
using functions like "scanf", "gets" etc. ?

Make array point to the buffer in which you want to store/have
stored the "i"th string.

let me know if you get it!

This I hereby do.

Give us your best shot at it in the form of a compilable program
and you will get more feedback.
Otherwise, there is always the ring of homework with certain
questions...


Cheers
Michael
 
W

Walter Roberson

my problem is: given the declaration
char *array[SIZE];
how to store strings of any length into this array from the user input
using functions like "scanf", "gets" etc. ?

You don't. Functions "like" scanf() and gets() are functions
that may return strings of indefinite length into the user buffer
which is *assumed* to be "big enough". Clearly any assumption of
"big enough" is going to be violated in the face of your
requirement to be able to store strings of "any length" -- if
the user provided a 7.2 exabyte long buffer, the program would
fail the first time the input was 7.3 exabytes long.

If you use fgets() instead of "functions like" scanf and gets,
then you have the ability to specify a maximum input size that
will not be exceeded. That gives you a chance to read a block
of input at a time into a fixed-length buffer, then allocate
dynamic memory to hold the contents. You could either create a
linked-list of these dynamic buffers and then at the end create
a single dynamic buffer long enough to hold the end result,
or you could use realloc() as you went along -- simpler logic
but much less efficient.

Naturally, if your system only -has- 512 Mb of available memory,
then you aren't going to be able to deal with the 7.3 exabyte long
input, but at least you will be able to handle the situation
smoothly whereas if you use functions "like" scanf and gets
you would almost certainly crash in the attempt.

Handling input of "any length" is a mugs game -- no matter how
sophisticated your buffering, you are never going to be able to
read "all" of /dev/zero or /dev/random (on Unix systems).
 
M

Michael Mair

Walter said:
my problem is: given the declaration
char *array[SIZE];
how to store strings of any length into this array from the user input
using functions like "scanf", "gets" etc. ?

You don't. Functions "like" scanf() and gets() are functions
that may return strings of indefinite length into the user buffer
which is *assumed* to be "big enough". Clearly any assumption of
"big enough" is going to be violated in the face of your
requirement to be able to store strings of "any length" -- if
the user provided a 7.2 exabyte long buffer, the program would
fail the first time the input was 7.3 exabytes long.

If you use fgets() instead of "functions like" scanf and gets,
then you have the ability to specify a maximum input size that
will not be exceeded.

When using scanf(), one certainly can restrict the number of
characters read.
That gives you a chance to read a block
of input at a time into a fixed-length buffer, then allocate
dynamic memory to hold the contents. You could either create a
linked-list of these dynamic buffers and then at the end create
a single dynamic buffer long enough to hold the end result,
or you could use realloc() as you went along -- simpler logic
but much less efficient.

This point certainly can be debated. Increasing the buffer size
by a factor instead of a fixed amount (maybe with a final
realloc()ation in order to reduce the amount needed to the
minimum may be more efficient).
Naturally, if your system only -has- 512 Mb of available memory,
then you aren't going to be able to deal with the 7.3 exabyte long
input, but at least you will be able to handle the situation
smoothly whereas if you use functions "like" scanf and gets
you would almost certainly crash in the attempt.

Handling input of "any length" is a mugs game -- no matter how
sophisticated your buffering, you are never going to be able to
read "all" of /dev/zero or /dev/random (on Unix systems).

Unless the system dies at a convenient moment... ;-)


Cheers
Michael
 
C

CBFalconer

.... snip ...

my problem is: given the declaration

char *array[SIZE];
how to store strings of any length into this array from the user
input using functions like "scanf", "gets" etc. ?

You can't. Obviously, once you define a SIZE that is a limit.
However there is a solution: store pointers to strings of varying
size. You can form those strings in malloced memory, which can be
adjusted to the actual string size. How do I do that, you ask?
Simple - just download ggets.zip from my site, and compile and use
it.

<http://cbfalconer.home.att.net/download/ggets.zip>

--
Some informative links:
http://www.geocities.com/nnqweb/
http://www.catb.org/~esr/faqs/smart-questions.html
http://www.caliburn.nl/topposting.html
http://www.netmeister.org/news/learn2quote.html
 
A

arkobose

Walter said:
my problem is: given the declaration
char *array[SIZE];
how to store strings of any length into this array from the user input
using functions like "scanf", "gets" etc. ?

You don't. Functions "like" scanf() and gets() are functions
that may return strings of indefinite length into the user buffer
which is *assumed* to be "big enough". Clearly any assumption of
"big enough" is going to be violated in the face of your
requirement to be able to store strings of "any length" -- if
the user provided a 7.2 exabyte long buffer, the program would
fail the first time the input was 7.3 exabytes long.

If you use fgets() instead of "functions like" scanf and gets,
then you have the ability to specify a maximum input size that
will not be exceeded. That gives you a chance to read a block
of input at a time into a fixed-length buffer, then allocate
dynamic memory to hold the contents. You could either create a
linked-list of these dynamic buffers and then at the end create
a single dynamic buffer long enough to hold the end result,
or you could use realloc() as you went along -- simpler logic
but much less efficient.

Naturally, if your system only -has- 512 Mb of available memory,
then you aren't going to be able to deal with the 7.3 exabyte long
input, but at least you will be able to handle the situation
smoothly whereas if you use functions "like" scanf and gets
you would almost certainly crash in the attempt.

Handling input of "any length" is a mugs game -- no matter how
sophisticated your buffering, you are never going to be able to
read "all" of /dev/zero or /dev/random (on Unix systems).

dear Walter,
consider the following program:

#include<stdio.h>
#define SIZE 1
int main()
{
char *array[SIZE];
scanf("%s", array[0]); // type a string of any length whatsoever.
for(int i = 0; *(array[0] + i) != '\0'; i++)
printf("%c", *(array[0] + i));

return 0;
}
when you run this program, you will find that the "printf" outputs the
whole string which you entered through "scanf", no matter how long your
string was.
now suppose you change the constant SIZE to some bigger value, 4, for
example, and then modify the program to this:

#include<stdio.h>
#define SIZE 4

int main()
{
char *array[SIZE] = {"string of any size", "type",
"praetertranssubstantiationalistically", "another string"};

for(int i = 0; i < SIZE; i++){
for(int j = 0; *(array + j) != '\0'; j++){
printf("%c", *(array + j));
}
printf("\n");
}
return 0;
}

then this program will output the strings with which the array has been
initialized exactly.
but if you want that the strings be entered at run time by user, rather
than be given at initialization as above, then how do you do this?
that is, during execution you type your strings one by one and they get
stored exactly as in the above program.

any ideas?

-arko
 
A

Artie Gold

Walter said:
my problem is: given the declaration
char *array[SIZE];
how to store strings of any length into this array from the user
input
using functions like "scanf", "gets" etc. ?

You don't. Functions "like" scanf() and gets() are functions
that may return strings of indefinite length into the user buffer
which is *assumed* to be "big enough". Clearly any assumption of
"big enough" is going to be violated in the face of your
requirement to be able to store strings of "any length" -- if
the user provided a 7.2 exabyte long buffer, the program would
fail the first time the input was 7.3 exabytes long.

If you use fgets() instead of "functions like" scanf and gets,
then you have the ability to specify a maximum input size that
will not be exceeded. That gives you a chance to read a block
of input at a time into a fixed-length buffer, then allocate
dynamic memory to hold the contents. You could either create a
linked-list of these dynamic buffers and then at the end create
a single dynamic buffer long enough to hold the end result,
or you could use realloc() as you went along -- simpler logic
but much less efficient.

Naturally, if your system only -has- 512 Mb of available memory,
then you aren't going to be able to deal with the 7.3 exabyte long
input, but at least you will be able to handle the situation
smoothly whereas if you use functions "like" scanf and gets
you would almost certainly crash in the attempt.

Handling input of "any length" is a mugs game -- no matter how
sophisticated your buffering, you are never going to be able to
read "all" of /dev/zero or /dev/random (on Unix systems).


dear Walter,
consider the following program:

#include<stdio.h>
#define SIZE 1
int main()
{
char *array[SIZE];
scanf("%s", array[0]); // type a string of any length whatsoever.

Undefined behavior -- array[0] is an uninitialized pointer. In this case
it just *happened* to *seem* to work. Basically, you got unlucky.
for(int i = 0; *(array[0] + i) != '\0'; i++)
printf("%c", *(array[0] + i));

return 0;
}
when you run this program, you will find that the "printf" outputs the
whole string which you entered through "scanf", no matter how long your
string was.

Dumb luck (or lack of same).
now suppose you change the constant SIZE to some bigger value, 4, for
example, and then modify the program to this:

#include<stdio.h>
#define SIZE 4

int main()
{
char *array[SIZE] = {"string of any size", "type",
"praetertranssubstantiationalistically", "another string"};

for(int i = 0; i < SIZE; i++){
for(int j = 0; *(array + j) != '\0'; j++){
printf("%c", *(array + j));
}
printf("\n");
}
return 0;
}

then this program will output the strings with which the array has been
initialized exactly.
but if you want that the strings be entered at run time by user, rather
than be given at initialization as above, then how do you do this?
that is, during execution you type your strings one by one and they get
stored exactly as in the above program.

any ideas?


Sure. See the following for a thorough discussion of the subject:

http://users.powernet.co.uk/eton/c/fgetdata.html

HTH,
--ag
 
M

Malcolm

char *array[SIZE];
how to store strings of any length into this array from the user input
using functions like "scanf", "gets" etc. ?
char *array[SIZE];
char buff[1024];

for(i=0;i<SIZE;i++)
{
fgets(buff, 1024, stdin);
ptr = strchr(buff, '\n');
/* this is absolutely vital. fgets() is no improvement whatsoever over
gets() unless
you handle buffer overflow correctly. Wrong results are often worse than a
crash which is the most likely result of gets() being fed an over-long
line. */
if(ptr == 0)
{
printf("Your line was over 1024 characters long. I will have to look
up realloc"
"and do a bit more work to solve this problem. For now let's quit\n");
exit(EXIT_FAILURE);
}
*ptr = 0;
array = mystrdup(buff);
if(!array)
{
printf("Out of memory\n");
exit(EXIT_FAILURE);
}
}

char *mystrdup(const char *str)
{
char *answer = malloc(strlen(str) + 1);
if(answer)
strcpy(answer, str);
return answer;
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top