Using an array with pointers in C - c

Hello i'm practising C and i have a little problem with the following code. First of all, my program just reads the input from the user and if there is memory availble, it stores it, otherwise it makes nothing.
I have an array of pointers to char called "lines" and an array of chars for the temporary storage of the input called "line".
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXWIDTH 81
#define MAXLINES 100
int main ()
{
char* lines [MAXLINES];
char line[MAXWIDTH];
int i ;
int n ;
Then i will check if my array of pointers has space and the input is non-zero. I do it in a for-loop to fill the array and normally the for-loop should stop when i type in nothing and just press enter or when the array is full.
If there is space i will check if there is enough memory in the space where the pointer is pointing to. If that's ok (!= NULL), the program copies the input from gets(line) in the memory.
for (n = 0; n < MAXLINES && gets(line) != NULL; n++)
{
if ((lines[n] = malloc(strlen(line) + 1)) == NULL)
exit (1);
strcpy(lines[n], line);
}
The rest of the code is just for the output and freeing of the memory.
for (i = 0; i < n; i++)
{
puts(lines[n-i-1]);
free(lines[n-i-1]);
}
return 0;
}
Now the problemis , that the program runs without any errors, but it's not working as i want.
It is just performing a infinte loop where i can type in as long as i want, what i want without any reaction.

gets doesn't return NULL when you type an empty line, if that's what you tried to check for. It will still be an empty string. You'll need to check if the first character is a \0 if you want to look for empty lines.
On a side note, gets is extremely unsafe since it will overrun your buffer if your line is too long and cause evil bugs. Use fgets instead, it lets you specify the size of your buffer. (Note that fgets will add a \n to the end of your string, even if it's an empty line.)

Well for a start, I suggest reading the following about why you should avoid using gets(). I suggest using scanf() or fgets() instead...
http://www.gidnetwork.com/b-56.html
then note that you're doing a loop to 100 taking input, and only after all 100 are you outputting. So you'll need to enter 100 lines of input currently before you see anything...

You're not checking for an empty line.
You need something like:
if('\0' == line[0])
{
break;
}
And use fgets() not gets(). It's safer. However you then need to do:
if('\n' == line[0] || '\r' == line[0])
{
break;
}

Well, how do you terminate your input? Entering an empty line won't help because line will be "" not NULL. Have you tried pressing Ctrl+Z in the console (if it's windows)?

Related

C - Buffersize conditional not breaking while loop

UPDATE:
Okay, I'm going about this entirely the wrong way. The reason I'm not geting the result I want is because I'm reading from the terminal and awaiting an enter keypress before the program continues to execute. What I actually need to do is program a "screen" or x11 window to read real-time inputs. Therefore my question is now redundant. Thanks for everyone's suggestions.
Is there a better way to program this which would allow me to capture
keyPress time? And, why is the BUFFERSIZE conditional in the while loop not
breaking out of the loop?
#define BUFFERSIZE 100
int main(void) {
int terminalInput;
int keyPress = 0;
int inputArrayBuffer[BUFFERSIZE];
int bufferExceptionFlag = 0;
printf("\n\t\t\t->"); /* Prompt */
while((terminalInput = getchar()) != '\n' && keyPress < BUFFERSIZE) {
inputArrayBuffer[keyPress] = terminalInput;
++keyPress;
if (keyPress >= BUFFERSIZE) {
bufferExceptionFlag = 1;
}
}
return 0;
}
A few issues. For one, your inputArrayBuffer should be a char array, not an int array. Secondly, there are standard C libraries that include the functionality of what you want to do.
Question 1: "Is there a better way to program this which would allow me to capture keyPress time?"
Yes. For reading stdin until either a newline is encountered or a max length is encountered, the fgets function from stdio.h works nicely (although alternatives may exist). Something like,
fgets(inputArrayBuffer, BUFFERSIZE, stdin)
I understand you want to know the number of keys the user entered, not including the newline key. This is essentially the string length. An easier way to achieve this is to simply determine the length of the string entered by the user. Something like,
keyPress = strlen(inputArrayBuffer) - 1; // -1 because the newline '\n' is included in strlen if you use fgets
If you must capture a single character at a time, then the original code you proposed should work, just be certain to define inputArrayBuffer as char inputArrayBuffer[BUFFERSIZE];
Question 2: "And, why is the BUFFERSIZE conditional in the while loop not breaking out of the loop?"
It definitely should be breaking out of the loop. But don't confuse bufferExceptionFlag equaling the value 1 with signifying that keyPress < BUFFERSIZE didn't cause the loop to break. Clearly, when you ++keyPress inside the loop, if keyPress had the value of 99, it would then become 100, which would cause bufferExceptionFlag to be set. However, on the next loop iteration keyPress < BUFFERSIZE would be false and the loop would break.
Here is a more simple and appropriate solution in my opinion.
#include <stdio.h>
#include <string.h>
#define BUFFERSIZE 100
int main(void) {
char inputArrayBuffer[BUFFERSIZE];
unsigned long keyPress = 0;
printf("\n\t\t\t->"); /* Prompt */
fgets(inputArrayBuffer, BUFFERSIZE, stdin);
keyPress = strlen(inputArrayBuffer) - 1; // -1 because the newline '\n' is included in strlen if you use fgets
printf("User entered: %s\n", inputArrayBuffer);
printf("Input length: %lu\n", keyPress);
return 0;
}
Note that fgets includes the newline character on the string it reads. To remove this character you can do something like inputArrayBuffer[keyPress] = '\0';

How do you prevent buffer overflow using fgets?

So far I have been using if statements to check the size of the user-inputted strings. However, they don't see to be very useful: no matter the size of the input, the while loop ends and it returns the input to the main function, which then just outputs it.
I don't want the user to enter anything greater than 10, but when they do, the additional characters just overflow and are outputted on a newline. The whole point of these if statements is to stop that from happening, but I haven't been having much luck.
#include <stdio.h>
#include <string.h>
#define SIZE 10
char *readLine(char *buf, size_t sz) {
int true = 1;
while(true == 1) {
printf("> ");
fgets(buf, sz, stdin);
buf[strcspn(buf, "\n")] = 0;
if(strlen(buf) < 2 || strlen(buf) > sz) {
printf("Invalid string size\n");
continue;
}
if(strlen(buf) > 2 && strlen(buf) < sz) {
true = 0;
}
}
return buf;
}
int main(int argc, char **argv) {
char buffer[SIZE];
while(1) {
char *input = readLine(buffer, SIZE);
printf("%s\n", input);
}
}
Any help towards preventing buffer overflow would be much appreciated.
When the user enters in a string longer than sz, your program processes the first sz characters, but then when it gets back to the fgets call again, stdin already has input (the rest of the characters from the user's first input). Your program then grabs another up to sz characters to process and so on.
The call to strcspn is also deceiving because if the "\n" is not in the sz chars you grab than it'll just return sz-1, even though there's no newline.
After you've taken input from stdin, you can do a check to see if the last character is a '\n' character. If it's not, it means that the input goes past your allowed size and the rest of stdin needs to be flushed. One way to do that is below. To be clear, you'd do this only when there's been more characters than allowed entered in, or it could cause an infinite loop.
while((c = getchar()) != '\n' && c != EOF)
{}
However, trying not to restructure your code too much how it is, we'll need to know if your buffer contains the newline before you set it to 0. It will be at the end if it exists, so you can use the following to check.
int containsNewline = buf[strlen(buf)-1] == '\n'
Also be careful with your size checks, you currently don't handle the case for a strlen of 2 or sz. I would also never use identifier names like "true", which would be a possible value for a bool variable. It makes things very confusing.
In case that string inside the file is longer that 10 chars, your fgets() reads only the first 10 chars into buf. And, because these chars doesn't contain the trailing \n, function strcspn(buf, "\n") returns 10 - it means, you are trying to set to 0 an buf[10], so it is over buf[] boundaries (max index is 9).
Additionally, never use true or false as the name of variable - it totally diminishes the code. Use something like 'ok' instead.
Finally: please clarify, what output is expected in case the file contains string longer than 10 characters. It should be truncated?

fgets reading more char than it should

I'm developing a code where the user will type several paragraphs and it will stop reading when the user begin a paragraph with "END". The code will manipulate the string by counting each letter and showing a graph and blah blah blah, but this is irrelevant to the question.
The thing is: which paragraph must have no more than 1000 characters.
A smaller version of the code is the following (considering I just want to storage 5-char-string - even though I'll expand that).
#include <stdio.h>
#include <string.h>
int main()
{
char paragraph[5];
for ( ; ; )
{
fgets(paragraph, 5, stdin);
if (paragraph[0]=='E' && paragraph[1]=='N' && paragraph[2]=='D')
{ return 0; }
printf("%s", paragraph);
}
return 0;
My problem is: if I type more than 5 characters, the printf function still prints more than 5 characters, I don't know why. I've already checked everything I could possible check.
Help a beginner like me, please.
fgets() reads in at most one less than size characters from stream and
stores them into the buffer pointed to by s. Reading stops after an
EOF or a newline. If a newline is read, it is stored into the buffer.
A terminating null byte ('\0') is stored after the last character in
the buffer.
So when entering more than 4 characters (newline included) only 4 is read and the rest stays in the buffer ready to be read next fgets.
Your printf will not print any newline in this case and will be called multiple times, making it look like printing more than 4 characters.
As suggested in comments, try printf("[%s]", paragraph); to see the individual printf calls.
You should use strstr in string.h because it's cleaner.
if (strstr(paragraph, "END"))
return 0;
instead of
if (paragraph[0]=='E' && paragraph[1]=='N' && paragraph[2]=='D')
return 0;
Try modifying your code in the following way and you'll immediately see what actually happens with the fgets() function when you enter more characters than the size of your buffer. It doesn't read from the keyboard, but from the stdinbuffer. These SO posts may also be interesting for you to read:(1), (2). Enjoy the demo and be sure to thoroughly read the man pages.
#include <stdio.h>
int main()
{
char paragraph[5];
for ( ; ; )
{
printf("Enter the string: \n\t");
if(fgets(paragraph, 5, stdin) != NULL)
printf("%s\n", paragraph);
if (paragraph[0]=='E' && paragraph[1]=='N' && paragraph[2]=='D')
return 0;
}
return 0;
}

Infinite loop when getting a line with getchar()

I was trying an exercise from K&R (ex 1-17), and I came up with my own solution.
The problem is that my program appears to hang, perhaps in an infinite loop. I omitted the NUL ('\0') character insertion as I find C generally automatically attaches it to the end of a string (Doesn't it?).
Can somebody please help me find out what's wrong?
I'm using the GCC compiler with Cygwin on win8(x64), if that helps..
Question - Print all input lines that are longer than 80 characters
#include<stdio.h>
#define MINLEN 80
#define MAXLEN 1000
/* getlin : inputs the string and returns its length */
int getlin(char line[])
{
int c,index;
for(index = 0 ; (c != '\n') && ((c = getchar()) != EOF) && (index < MAXLEN) ; index++)
line[index] = c;
return (index); // Returns length of the input string
}
main()
{
int len;
char chArr[MAXLEN];
while((len = getlin(chArr))>0)
{
/* A printf here,(which I had originally inserted for debugging purposes) Miraculously solves the problem!!*/
if(len>=MINLEN)
printf("\n%s",chArr);
}
return 0;
}
And I omitted the null('\0') character insertion as I find C generally automatically attaches it to the end of a string (Doesn't it?).
No, it doesn't. You're using getchar() to read input characters one at a time. If you put the chars in an array yourself, you'll have to terminate it yourself.
The C functions that return a string will generally terminate it, but that's not what you're doing here.
Your input loop is a little weird. The logical AND operator only executes the right-hand-side if the left-hand-side evaluates to false (it's called "short-circuiting"). Rearranging the order of the tests in the loop should help.
for(index = 0 ; (index < MAXLEN) && ((c = getchar()) != EOF) && (c != '\n'); index++)
line[index] = c;
This way, c receives a value from getchar() before you perform tests on its contents.
I'm not positive about what's wrong, but you don't provide the input to the program so I'm guessing.
My guess is that in getlin your variable c gets set to '\n' and at that point it never gets another character. It just keeps returning and looping.
You never SET c to anything inside your getlin function before you test it, is the problem.
C does not insert a NUL terminator at the end of strings automatically. Some functions might do so (e.g. snprintf). Consult your documentation. Additionally, take care to initialize all your variables, like c in getlin().
1) C doesn't add a final \0 to your string. You are responsible for using an array of at least 81 chars and puting the final \0 after the last character you write in it.
2) You're testing the value of c before reading it
3) Your program doesn't print anything because printf uses a buffer for I/O which is flushed when you send \n. Modify this statement to print a final \n:
printf("\n%s",chArr);
to become:
printf("%s\n",chArr);
4) To send an EOF to your program you should do a Ctrl+D under unix and I don't know if it's possible for windows. This may be the reason why the program never ends.

c detecting empty input for stdin

This seems like it should be a simple thing but after hours of searching I've found nothing...
I've got a function that reads an input string from stdin and sanitizes it. The problem is that when I hit enter without typing anything in, it apparently just reads in some junk from the input buffer.
In the following examples, the prompt is "input?" and everything that occurs after it on the same line is what I type. The line following the prompt echoes what the function has read.
First, here is what happens when I type something in both times. In this case, the function works exactly as intended.
input? abcd
abcd
input? efgh
efgh
Second, here is what happens when I type something in the first time, but just hit enter the second time:
input? abcd
abcd
input?
cd
And here is what happens when I just hit enter both times:
input?
y
input?
y
It happens to return either 'y' or '#' every time when I run it anew. 'y' is particularly dangerous for obvious reasons.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#define STRLEN 128
int main() {
char str[STRLEN];
promptString("input?", str);
printf("%s\n", str);
promptString("input?", str);
printf("%s\n", str);
return EXIT_SUCCESS;
}
void promptString(const char* _prompt, char* _writeTo) {
printf("%s ", _prompt);
fgets(_writeTo, STRLEN, stdin);
cleanString(_writeTo);
return;
}
void cleanString(char* _str) {
char temp[STRLEN];
int i = 0;
int j = 0;
while (_str[i] < 32 || _str[i] > 126)
i++;
while (_str[i] > 31 && _str[i] < 127) {
temp[j] = _str[i];
i++;
j++;
}
i = 0;
while (i < j) {
_str[i] = temp[i];
i++;
}
_str[i] = '\0';
return;
}
I've tried various methods (even the unsafe ones) of flushing the input buffer (fseek, rewind, fflush). None of it has fixed this.
How can I detect an empty input so that I can re-prompt, instead of this annoying and potentially dangerous behavior?
This part of cleanString
while (_str[i] < 32 || _str[i] > 126)
i++;
jumps over \0 when the string is empty.
You should add _str[i] != '\0' into the loop's condition.
To detect an empty string, simply check it's length just after the input:
do {
printf("%s ", _prompt);
fgets(_writeTo, STRLEN, stdin);
} while (strlen(_writeTo) < 2);
(comparing with two because of '\n' which fgets puts into the end of buffer)
Why do you have a bunch of variable names with leading underscores? That's nasty.
Anyway, the first thing you must do is check the return value of fgets. If it returns NULL, you didn't get any input. (You can then test feof or ferror to find out why you didn't get input.)
Moving on to cleanString, you have a while loop that consumes a sequence of non-printable characters (and you could use isprint for that instead of magic numbers), followed by a while loop that consumes a sequence of printable characters. If the input string doesn't consist of a sequence of non-printables followed by a sequence of printables, you will either consume too much or not enough. Why not use a single loop?
while(str[i]) {
if(isprint(str[i]))
temp[j++] = str[i];
++i;
}
This is guaranteed to consume the whole string until the \0 terminator, and it can't keep going past the terminator, and it copies the "good" characters to temp. I assume that's what you wanted.
You don't even really need to use a temp buffer, you could just copy from str[i] to str[j], since j can never get ahead of i you'll never be overwriting anything that you haven't already processed.

Resources