C Dynamic Array based on input from console - c

I am writing a program that stores input from the console. To simplify it lets say I need to output what was wrote to the console.
So I have something like this:
int main()
{
char* input;
printf("Please write a bunch of stuff"); // More or less.
fgets() // Stores the input to the console in the input char*
printf(input);
}
So that is it in more or less. Just trying to give you the general idea. So what if they input something the size of 999999999999. How can I assign a char* to be that size dynamically.

#include <stdio.h>
int main(void)
{
char input[8192];
printf("Please type a bunch of stuff: ");
if (fgets(input, sizeof(input), fp) != 0)
printf("%s", input);
return(0);
}
That allows for a rather large space. You could check that you actually got a newline in the data.
If that's not sufficient, then investigate the POSIX 2008 function getline(), available in Linux, which dynamically allocates memory as necessary.

Here's an example - you need to validate the input and make sure you don't overflow your buffer. In this example, I discard anything over the max length and instruct the user to try again. Another approach would be allocating a new (larger) buffer when that happened.
fgets() second argument is the maximum number of characters you will read from the input. I'm actually accounting for the \n in this example and getting rid of it, you may not want to do so.
#include <stdio.h>
#include <string.h>
void getInput(char *question, char *inputBuffer, int bufferLength)
{
printf("%s (Max %d characters)\n", question, bufferLength - 1);
fgets(inputBuffer, bufferLength, stdin);
if (inputBuffer[strlen(inputBuffer) -1] != '\n')
{
int dropped = 0;
while (fgetc(stdin) != '\n')
dropped++;
if (dropped > 0) // if they input exactly (bufferLength - 1) characters, there's only the \n to chop off
{
printf("Woah there partner, your input was over the limit by %d characters, try again!\n", dropped );
getInput(question, inputBuffer, bufferLength);
}
}
else
{
inputBuffer[strlen(inputBuffer) -1] = '\0';
}
}
int main()
{
char inputBuffer[10];
getInput("Go ahead and enter some stuff:", inputBuffer, 10);
printf("Okay, I got: %s\n",inputBuffer);
return(0);
}

Related

Extreme troubles with full line input. C Programming Language

I am having the absolute craziest time getting full line input to work. I will explain my problem. I need to get a full line of input, including a space, from the user entered at the keyboard. Simple right? Wrong!
MY GOAL
Store multiple strings, with spaces, into variables. If it makes a difference, I want to make the variables equal to a char pointer. So once I get the input from tempString, I want to set it to a char pointer. Like so:
char *variable1, *variable2;
//get user input
variable1 = tempString;
//get more user input
variable 2 = tempString;
//etc etc etc
Here's what I've tried.
First try
char tempString[100];
scanf("%s", &tempString);
printf("%s", tempString);
Invalid: scanf will stop reading at a white space, so "Example String" would just end up being "Example".
Second try
So I do more research. I thought I found the magic fix.
char tempSTring[100];
fgets(tempString, 100, stdin);
printf("%s", tempString);
Originally this works. However there is a massive problem. I need to get the user to enter about 8 inputs. Meaning I have to use a command like this 8 times. The problem is the program often skips over the fgets command. If I use a scanf previously, somehow the \n character is stuck in the input stream, and automatically feeds into fgets, satisfying its stdin input, and then does not prompt the user for input.
Third try
After thinking fgets was maybe my solution with a work around, I tried some tricks.
char tempSTring[100];
getc(stdin);
fgets(tempString, 100, stdin);
printf("%s", tempString);
I tried adding this getc(stdin) line. It worked for much of my program. It absorbs the \n character left behind in the stream. When it does so, great, it works. But sometimes, for some reason, the \n is NOT left in the stream, and when debugging, it looks like getc(stdin) is requesting input from the user, so it pauses my program to ask for input.
Question
These don't work for me.
How should I be doing this easy task?
To read (up to) 8 lines from a file, you can use either of these solutions. I decline to use variables char *variable1, *variable2, …; — that is an array seeking to escape.
POSIX getline()
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
enum { MAX_LINES = 8 };
char *lines[MAX_LINES];
int index = 0;
char *buffer = 0;
size_t buflen = 0;
while (index < MAX_LINES && getline(&buffer, &buflen, stdin) != -1)
{
lines[index++] = buffer;
buffer = 0;
buflen = 0;
}
free(buffer); // Space may be allocated before EOF is detected
for (int i = 0; i < index; i++)
printf("%d: %s", i, lines[i]);
return 0;
}
If getline() fails to allocate memory, it will report an error, so there is no need to do an explicit error check.
Standard C fgets()
Code using strdup(), another POSIX function. It isn't a part of standard C (though it is widely available). It is trivial to implement.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
enum { MAX_LINES = 8 };
char *lines[MAX_LINES];
int index = 0;
char buffer[4096];
while (index < MAX_LINES && fgets(buffer, sizeof(buffer), stdin) != 0)
{
if ((lines[index] = strdup(buffer)) == 0)
break;
index++;
}
for (int i = 0; i < index; i++)
printf("%d: %s", i, lines[i]);
return 0;
}
The test in the loop allows for the possibility of strdup() failing to allocate memory.
Notes
Both the solutions above keep the newline at the end of the input string. If you don't want that, you can zap it with:
lines[i][strcspn(lines[i], "\r\n")] = '\0';
This overwrites a carriage return or newline with a null byte, transforming DOS or Unix line endings. You then need to adjust the printing which assumes the string includes a newline. Note that the expression shown works correctly even if there is no carriage return or newline in the string.
The fgets() solution will break lines at 4095 characters, leaving the rest to be read as 'the next line'. If that's not acceptable, you have a variety of strategies open to you.
You can detect whether there is a newline and arrange to allocate more memory and read the next section of the line into the extra memory, repeating until you come across a newline or EOF.
You can read the remaining characters up to the newline or EOF:
int c;
while ((c = getchar()) != EOF && c != '\n')
;
Implementing strdup()
If for some reason your system doesn't have an implementation of strdup(), you can create a surrogate with:
#include <assert.h>
#include <stdlib.h>
#include <string.h>
char *strdup(const char *old_str)
{
assert(old_str != 0);
size_t old_len = strlen(old_str) + 1;
char *new_str = malloc(old_len);
if (new_str != 0)
memmove(new_str, old_str, old_len);
return new_str;
}
Here's how we old fart C programmers would do it:
#include <stdio.h>
#define MAX_LEN 100
int main( )
{
int c;
char input[MAX_LEN+1];
int i = 0;
while ( (c=getchar()) != '\n' && c != EOF && i < MAX_LEN)
input[i++] = c;
if (c == EOF || c =='\n') {
/* received input that terminated within buffer limit */
input[i] = '\0';
printf("read in your input string of: %s\n", input);
}
else {
printf("don't buffer overflow me dude!\n");
return -1;
}
return 0;
}
But nowadays people will tell you to use one of the library functions. I'm still an old fart though.
EDIT: Fixed my embarrassing mistakes pointed out by the helpful comments below.
You can take care of '\n' left by previous scanf by writing it like this -
scanf("%d%*c", &x); //<-- example to take int input
%*c will read from stdin and then discard it, thus '\n' would be removed from stdin.
You can achieve with scanf like this (a way for your previous attempt)-
char tempString[100];
/* As suggested by chqrile it is essential to check return of scanf */
if(scanf("%99[^\n]", tempString)!=1){
// ^^ & not required
tempString[0]='\0';
}
%99[^\n] this will read 99 characters and will stop only after encountering '\n' , thus would read input with spaces.

Validating integer of length 11 and starts with 0

I'm trying to make a function to validate mobile entry, the mobile number MUST starts with 0 and is 11 numbers (01281220427 for example.)
I want to make sure that the program gets the right entry.
This is my attempt:
#include <stdio.h>
#include <strings.h>
void integerValidation(char x[15]);
int main(int argc, char **argv)
{
char mobile[15];
integerValidation(mobile);
printf("%s\n\n\n", mobile);
return 0;
}
void integerValidation(char x[15]){
char input[15];
long int num = -1;
char *cp, ch;
int n;
printf("Please enter a valid mobile number:");
while(num<0){
cp = fgets(input, sizeof(input), stdin);
if (cp == input) {
n = sscanf(input, "%ld %c", &num, &ch);
if (n!=1) {printf("ERROR! Please enter a valid mobile number:");
num = -1;
}
else if (num<0)
printf("ERROR! Please enter a valid mobile number:");
else if ((strlen(input)-1)>11 || (strlen(input)-1)<11 || strncmp(&input[0], "0", 1) != 0){
printf("ERROR! Please enter a valid mobile number:");
num = -1;
}
}
}
long int i;
i = strlen(input);
//Because when I try to print it out it prints a line after number.
strcpy(&input[i-1], "");
strcpy(x, input);
}
Now, if I don't use
strcpy(&input[i-1], "");
the array prints a new line after the number, what would be a good fix other than mine? and how can I make this function optimized and shorter?
Thanks in advance!
Edit:
My question is: 1. Why does the input array prints a new line in the end?
2. How can I make this code shorter?
End of edit.
If you insist on using sscanf(), you should change the format this way:
int integerValidation(char x[15]) {
char input[15], c;
printf("Please enter a valid mobile number:");
while (fgets(input, sizeof(input), stdin)) {
if (sscanf(input, "%11[0123456789]%c", x, &c) == 2
&& x[0] == '0' && strlen(x) == 11 && c == '\n') {
// number stored in `x` is correct
return 1;
}
printf("ERROR! Please enter a valid mobile number:");
}
x[0] = '\0'; // no number was input, end of file reached
return 0;
}
%12[0123456789] parses at most 11 characters that must be digits.
%c reads the following character, which should be the trailing '\n'.
I verify that both formats have been matched, and the number starts with 0 (x[0] == '0') and it has exactly 11 digits.
You're seeing the newline, since fgets() reads until an EOF or a newline is received. The newline is stored in the buffer, and after that the string is terminated with '\0'.
An alternative would be to directly overwrite the newline with another null-byte: input[i-1] = '\0' (which basically does the same thing as your solution, but saves a function call).
The same goes for the check with strncmp with length 1, you can directly check input[0] == '0'. Note that you have to compare against '0' (char) here, not "0" (string).
A few other things I'm seeing:
You can also spare the %c in the format string for sscanf (you're never evaluating it anyway, since you're checking for 1 as return value), which also eliminates the need for char ch.
Also, you're passing char x[15] as argument to your function. This is a bit misleading, because what actually gets passed is a pointer to a char array (try using sizeof(x), your compiler will most likely issue a warning about the size of char * being returned by sizeof()).
What you could do is to ditch the char array input, which you're using as temporary buffer, and use the buffer which was handed over as argument. For this to be save, you should use a second funcion parameter to specify the size of the buffer which was handed to the function, which would result in a function header like as follows:
void integerValidation(char *input, size_t len);
With this, you'd have to use len instead of sizeof(input). The following question provides more detail why: C: differences between char pointer and array
Since you're not using a temporary buffer anymore, you can remove the final call to strcpy().
There are also a lot of checks for the number length/format. You can save a few:
If you use %lu instead of %ld no signed numbers are being converted, which saves you the check for num < 0.
You're checking whether the length of the read number is <11 or >11 - why not just check for !=11?
You're calling strlen() three times on the input-buffer (or still twice with the reworked check for lengh 11) - it makes sense to call it once, save the length in a variable and use that variable from then on, since you're not altering the string between the calls.
There is already an accepted answer, but for what it's worth, here is another.
I made several changes to your code, firstly avoiding "magic numbers" by defining the phone number length and an arbitrarily greater string length. Then there is no point passing an array x[15] to a function since it pays no regard to its length, might as well use the simpler *x pointer. Next, I return all reasons for failure back to the caller, that's simpler. And instead of trying to treat the phone number as a numeric entry (note: letters, spaces, hyphens, commas and # can sometimes be a part of phone number too) I stick to a character string. Another reason is that the required leading zero will vanish if you convert the entry to an int of some size. I remove the trailing newline that fgets() reads with the input line, and the result is this.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAXLEN 11
#define STRLEN (MAXLEN+10)
int integerValidation(char *x);
int main(int argc, char **argv)
{
char mobile[STRLEN];
while (!integerValidation(mobile)) // keep trying
printf("Invalid phone number\n");
printf("%s\n\n\n", mobile); // result
return 0;
}
int integerValidation(char *x)
{
int i, len;
printf("Please enter a valid mobile number:");
if(fgets(x, STRLEN, stdin) == NULL) // check bad entry
return 0;
x [ strcspn(x, "\r\n") ] = 0; // remove trailing newline etc
if((len = strlen(x)) != MAXLEN) // check length
return 0;
if(x[0] != '0') // check leading 0
return 0;
for(i=1; i<len; i++) // check all other chars are numbers
if(!isdigit(x[i]))
return 0;
return 1; // success
}

A random text as output

My goal is a function that returns the same text as I wrote in stdin.
As a result of compilation of the code below:
#include <stdio.h>
char chain[990];
int znaki()
{
scanf("%s", chain);
int i=0;
do{
putchar(chain[i]);
i++;
}
while(chain[i]!=10);
return 0;
}
int main(int argc, char **argv)
{
znaki();
return 0;
}
I get:
MyOwnText
MyOwnText
and
many
lines
of
some
random text just like cat /dev/random in linux
The first line is my input.
Why?
do {
putchar(chain[i]);
i++;
} while(chain[i]!=10);
This code prints characters from chain (and further) until finds a char with code 10. As the buffer is uninitialized, it is filled with some random data from other programs. And you see that data.
Probably, you wanted to write something like
do {
putchar(chain[i]);
i++;
} while(i != 10);
which would print first 10 chars from the array.
And by the way, the code seems to be vulnerable to a buffer overflow.
You have an array.
You asked the user for a word, and you stored it in the beginning of that array.
You then printed the array.
It's pretty obvious to me why the input you wrote was printed out.
chain[] does not have the value of 10.
chain is filled with non-white-space characters - that is what "%s" directs scanf() to do: scan and save non-white-space char. 10 is typically '\n', a white-space.
char chain[990];
scanf("%s", chain);
...
while(chain[i]!=10);
Instead use fgets() to read lines.
int znaki(void) {
char chain[990];
while (fgets(chain, sizeof chain, stdin) != NULL) {
int i=0;
while (chain[i] != '\n' && chain[i] != '\0') {
putchar(chain[i]);
i++;
}
return 0;
}

How to input multi-word string in C

I have this program. I want to input multi-word strings in a 2-D array. But instead of input whole string in first array of 2-D array this program inputs the first three words of my String in the first three array each(as I defined the no of rows in my 2-D array). Here is the program:
int main()
{
char title[50];
int track;
int question_no;
printf("\nHow many questions?\t");
scanf("%d",&question_no);
track=0;
char question[question_no][100];
while(track<=question_no)
{
printf("Question no %d is:",track+1);
scanf("%s",question[track]);
printf("Q %d.%s",track,question[track]);
track++;
}
}
Here "question_no" is the no of strings I want to input in my 2-D array- "question". But when I input first string, the string's first three words get inputted in the three arrays of 2-D array. It even doesn't ask me to input 2nd or 3rd strings.
A solution to this problem, as I perceive, should be 3-D array. Because that way 2-D arrays inside the outermost array would print the whole multi-word string (But there too I am bound to the length of each string, I think). If this, 3-D array concept, can solve the problem, then is there some efficient method also? Which is better, faster and less time consuming than 3-D array method.
scanf("%s") will scan a string up to the first piece of white space it finds, hence it's unsuitable for multi-word input.
There are ways to use scanf for line-based input but you're generally better off using methods that are easier to protect from buffer overflow, such as an old favorite of mine:
#include <stdio.h>
#include <string.h>
#define OK 0
#define NO_INPUT 1
#define TOO_LONG 2
static int getLine (char *prmpt, char *buff, size_t sz) {
int ch, extra;
// Get line with buffer overrun protection.
if (prmpt != NULL) {
printf ("%s", prmpt);
fflush (stdout);
}
if (fgets (buff, sz, stdin) == NULL)
return NO_INPUT;
// If it was too long, there'll be no newline. In that case, we flush
// to end of line so that excess doesn't affect the next call.
if (buff[strlen(buff)-1] != '\n') {
extra = 0;
while (((ch = getchar()) != '\n') && (ch != EOF))
extra = 1;
return (extra == 1) ? TOO_LONG : OK;
}
// Otherwise remove newline and give string back to caller.
buff[strlen(buff)-1] = '\0';
return OK;
}
This is a handy routine which provides line-based input, buffer overflow protection, detection of lines that are too long, cleaning up of those lines so that they don't affect the next input operation and prompting.
A test program can be seen below:
int main (void) {
int rc;
char buff[10] = "";
while ( 1) {
rc = getLine ("\nWhat? ", buff, sizeof(buff));
if (rc == NO_INPUT) {
// Extra NL since my system doesn't output that on EOF.
printf ("\nNo input\n");
return 1;
}
if (rc == TOO_LONG) {
printf ("Input too long [%s]\n", buff);
continue;
}
if ( strcmp (buff, "exit") == 0)
break;
printf ("OK [%s]\n", buff);
}
return 0;
}
And a transcript follows:
pax> ./testprog
What? hello
OK [hello]
What? this is way too big for the input buffer
Input too long [this is w]
What?
OK []
What? exit
pax> _
Use gets(), this takes input as one string including white spaces, even the newline. But will take in till the first newline. As opposed to scanf(), which takes upto the first white space.

Handling String input in C

If a char array needs to be declared before it is used, how does one declare one so that is can be used to store input?
e.g. The user enters a sentence or series of words. How is this stored so that it can be manipulated?
What is the correct way rather than just declaring an array which is large enough to handle expected input?
If you are talking about console input, you have no choice but to have a FIXED SIZE buffer and use a secure function not allowing more than FIXED_SIZE to be stored on your buffer.
An example would be:
char buff[1024];
fgets(buff, 1024, stdin); // to read from standard input
You must warn your user that any characters beyond 1023th will be ignored.
If you want to access last character the user entered:
printf("%c", buff[strlen(buff)-1]);
I usually use the following function:
#include <stdio.h>
#include <string.h>
#define OK 0
#define NO_INPUT 1
#define TOO_LONG 2
static int getLine (char *prmpt, char *buff, size_t sz) {
int ch, extra;
// Get line with buffer overrun protection.
if (prmpt != NULL) {
printf ("%s", prmpt);
fflush (stdout);
}
if (fgets (buff, sz, stdin) == NULL)
return NO_INPUT;
// If it was too long, there'll be no newline. In that case, we flush
// to end of line so that excess doesn't affect the next call.
if (buff[strlen(buff)-1] != '\n') {
extra = 0;
while (((ch = getchar()) != '\n') && (ch != EOF))
extra = 1;
return (extra == 1) ? TOO_LONG : OK;
}
// Otherwise remove newline and give string back to caller.
buff[strlen(buff)-1] = '\0';
return OK;
}
It uses the buffer-overflow-safe fgets with some supporting code to figure out if the line you entered was too long.
You can of course, read partial lines and perform memory re-allocations to store an arbitrary sized input string but usually it's more than adequate to just set a large enough upper boundary and allow for that (say 1K for example). If anyone enters more than that for their name or address, they're probably just being silly :-)
I've actually used that trick (partial reads and reallocs) to do user input before but, to be honest, the need for it was so rare that it didn't make it into my "important source code snippets" repository.
The use of fgets prevents the possibility of buffer overflow which is the big danger to user input.
If you want to test that code, try adding:
int main (void) {
int rc;
char buff[10];
rc = getLine ("Enter string> ", buff, sizeof(buff));
if (rc == NO_INPUT) {
printf ("No input\n");
return 1;
}
if (rc == TOO_LONG) {
printf ("Input too long\n");
return 1;
}
printf ("OK [%s]\n", buff);
return 0;
}
and some sample runs:
pax> ./qq
Enter string> hi bob
OK [hi bob]
pax> ./qq
Enter string>
No input
pax> ./qq
Enter string> hi ho the merry oh
Input too long
(that second one was entering CTRLD, an immediate end of file).
Input via buffer ? ( User writes its text to buffer of some size, when buffer is full, programm changes size of target array using realloc )
( you need to use char* instead of char[] )

Resources