Reading arbitrary length strings in C - c

I've attempted to write a C program to read a string and display it back to the user. I've tested it with a lot of input and it seems to work properly. The thing is that I'm not sure whether or not the c != EOF condition is necessary inside the while expression, and since by definition, the size of a char is 1 byte, maybe I can remove the sizeof(char) expressions inside the malloc and realloc statements, but I'm not sure about this.
Here's the program, also, I manually added a null terminating character to the string:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char *str = malloc(sizeof(char));
if (!str)
return 1;
char c;
char *reallocStr;
size_t len = 0;
size_t buf = 1;
printf("Enter some text: ");
while ((c = getchar()) != '\n' && c != EOF) {
if (len == buf) {
buf *= 2;
reallocStr = realloc(str, buf * sizeof(char));
if (!reallocStr)
return 1;
str = reallocStr;
}
str[len++] = c;
}
str[len] = '\0';
printf("You entered: %s\n", str);
free(str);
return 0;
}

As mentioned in the comments, you have a buffer overflow in your code, so you would need to fix that at the very least. To answer your specific questions, sizeof(char) is guaranteed to be 1 (dictated by the c99 spec), so you don't need to multiply by sizeof(char). It's good practice to check for EOF as if your input is coming from an alternate source that has no newline, you don't die (so if someone for example did printf %s hello | yourprogram from a bash prompt, you wouldn't die).

Problems include
Buffer overflow
#HardcoreHenry
Incorrect type
getchar() reruns an int with the values [0..UCHAR_MAX] and the negative: EOF. These 257 different values lose distinctiveness when saved as a char. Possible outcomes: infinite loop or premature loop end. Instead:
// char c;
int c;
Advanced: Arbitrary length
For very long lines buf *= 2; overflows when buf is SIZE_MAX/2 + 1. An alterative to growing in steps of 1, 2, 4, 8, 16,..., consider 1, 3, 7, 15, .... That way code can handle strings up to SIZE_MAX.
Advanced: Reading '\0'
Although uncommon, possible to read in a null character. Then printf("You entered: %s\n", str); will only print to that null character and not to the end of input.
To print all, take advantage that code knows the length.
printf("You entered: ");
fwrite(str, len, 1, stdout);
printf("\n");
To be clear, text input here is not reading of strings, but of reading of lines. That input is saved and converted to a string by appending a null character. Reading a '\0' complicates things, but something robust code handles.

Related

What alternative can I use instead of gets() and puts()?

Code snippet for gets()
int main(int argc, char *argv[])
{
char str[MAX_SIZE]
gets(str);
printf("\n");
Code snippet for puts()
printf("The most probable key is: %d\n", max2);
puts(output);
return 0;
I did not paste my whole code since it seems pretty irrelevant for my question. I just want to know a way I could fix this because when I run my code through GCC, it gives me errors and is not allowing me to use gets(). How would I fix this?
Use fgets and fputs instead. There is - beside removing all the flaws of gets- also a main difference in the usage between gets and fgets: fgets stores a new line character in the buffer (and gets does not).
So an equivalent - i.e. eliminating any new line if not desired - could look as follows. Function call strcspn(buffer,"\n") gives the longest sequence of characters until a new line is encountered (or strlen(buffer), if the string does not contain a new line). By writing a 0 to the index at this position a new line - if any - is eliminated.
char buffer[MAX_SIZE] = "";
if (fgets(buffer, MAX_SIZE ,stdin)) {
buffer[strcspn(buffer,"\n")] = '\0';
}
You should absolutely, positively avoid using gets(), its dangerous and removed from the recent C standard. That's why you see the warning
C11, Foreword, Paragraph 6 mentions
Major changes from the previous edition include:
[....]
removed the gets function (<stdio.h>)
Instead, use fgets().
To add, puts() is just fine, I see no reason for replacing that one.
Never use gets(). Because it is impossible to tell without knowing the data in advance how many characters gets() will read, and because gets() will continue to store characters past the end of the buffer, it is extremely dangerous to use. It has been used to break computer security.
Use fgets() instead
char * fgets ( char * str, int num, FILE * stream );
The following example shows the usage of fgets() function.
#include <stdio.h>
int main () {
FILE *fp;
char str[60];
/* opening file for reading */
fp = fopen("file.txt" , "r");
if(fp == NULL) {
perror("Error opening file");
return(-1);
}
if( fgets (str, 60, fp)!=NULL ) {
/* writing content to stdout */
puts(str);
}
fclose(fp);
return(0);
}
alternative can I use instead of gets()
char str[MAX_SIZE]; gets() has problems when reading a line of N characters. (N also counts the '\n').
When N > MAX_SIZE, the result is undefined behavior (UB). Too much input and no place to go. Often this UB writes into places used by other objects. Bad - very bad.
C11 eliminated gets() and is not a standard function since then.
The usual fgets() solution is well suggested by #Stephan Lechner. fgets() has some short comings listed below.
str[MAX_SIZE] now needs to be str[MAX_SIZE + 1] as fgets() also saves the '\n', unlike gets(). Sometimes adding + 1 is not practical.
fgets() retains the potential '\n'. See Removing trailing newline character from fgets()
When input is excessive, fgets() simply does not read it, unlike gets(). This is well behaved (not UB) yet we are still stuck with that problem: how to detect excessive input and what to do about it?
If code can live with these, use fgets(). Otherwise, read on.
mygets() alternative
This function does not need a +1 to the size of the s buffer.
Excessively long input returns NULL. All the line is read. The s buffer is filled with the initial characters.
char *mygets(char *s, size_t n) {
char *dest = s;
// Pathological case of n==0
char dummy[1];
if (n == 0) {
n = sizeof dummy;
dest = dummy;
}
size_t i = 0;
int ch;
n--;
while ((ch = fgetc(stdin)) != '\n' && ch != EOF) {
if (i < n) {
dest[i++] = (char) ch;
} else {
s = NULL; // Not enough room
}
}
if (ch == EOF) {
if (feof(stdin)) { // end-of-file
if (i == 0) {
s = NULL;
}
} else { // input error
i = 0;
s = NULL;
}
}
dest[i] = '\0';
return s;
}
Subtle bonuses:
s buffer is well defined on rare input error. With gets/fgets buffer contents are then undefined.
Pathological size of 0 is well defined. fgets() is a bit iffy on that.
Buffer size is the idiomatic size_t rather than int as with fgets().
Usage
str[MAX_SIZE];
if (mygets(str, sizeof str)) {
printf("Success <%s>\n", str);
} else {
if (feof(str)) printf("End of file detected. <%s>\n", str);
else if (ferror(str)) printf("End of file detected. <%s>\n", str);
else printf("Input too long <%s>.", str);
}

How To Read String that contains Spaces, in C language

What is the most accurate way to read strings from the keyboard in C, when the string contains spaces in between words? When I use scanf for that purpose then it doesn't read a string with spaces.The second option is to use gets but it is supposed to be harmful(I also want to know why?).Another thing is that I don't want to use any file handling concept like fgets.
These are 2 ways to read strings containing spaces that don't use gets or fgets
You can use getline (POSIX 2008 may not exist in your system) that conveniently manages allocation of the buffer with adequate size to capture the whole line.
char *line = NULL;
size_t bufsize = 0;
size_t n_read; // number of characters read including delimiter
while ((n_read = getline(&line, &bufsize, stdin)) > 1 && line != NULL) {
// do something with line
}
If you absolutely want scanf, in this example it reads to the end of line unless the line has more than the specified number of chars minus 1 for the delimiter. In the later case the line is truncated and you'll get the remaining chars in the next scanf invocation.
char line[1024];
while (scanf("%1023[^\n]\n", line) == 1) {
// do something with line
}
I should also point out that when you read strings from the keyboard with scanf for example, you are actually reading from a file with file pointer stdin. So you can't really avoid "any file handling concept"
#user3623265,
Please find a sample program which Uses fgets to read string from standard input.
Please refer some sample C documents as to how fgets can be used to get strings from a keyboard and what is the purpose of stdin.
#include <stdio.h>
#include <string.h>
int main(void)
{
char str[80];
int i;
printf("Enter a string: ");
fgets(str, sizeof(str), stdin);
i = strlen(str) - 1;
if (str[i] == '\n')
str[i] = '\0';
printf("This is your string: %s", str);
return 0;
}
There is a third option, you can read the raw data from stdin with the read() call:
#include <unistd.h>
int main(void) {
char buf[1024];
ssize_t n_bytes_read;
n_bytes_read = read(STDIN_FILENO, buf, sizeof(buf) - 1);
if (n_bytes_read < 0) {
// error occured
}
buf[n_bytes_read] = '\0'; // terminte string
printf("\'%s\'", buf);
return 0;
}
Please not that every input is copied raw to buf including the trailing return. That is, if you enter Hello World you will get
'Hello World
'
as output. Try online.
If you insist on not having a FILE * in scope, use getchar().
char buff[1024];
int ch;
int i = 0;
while( (ch = getchar()) != '\n' )
if(i < 1023)
buff[i++] = ch;
buff[i] = 0;
/* now move string into a smaller buffer */
Generally however it's accepted that stdout and stdin and FILE * are available. Your requirement is a bit odd and, since you are obviously not an advanced C programmer who has an unusual need to suppress the FILE * symbol, I suspect your understanding of C IO is shaky.

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.

Scanf skipped in loop (Hangman)

This program essentially asks for a secret string, then asks a user to repeatedly guess single chars of that string until he guesses it all. It works however every second time the while loop is run it skips user input for the guessed char. How do I fix this?
int main(){
char guess;
char test2 [50];
char * s = test2;
char output [50];
char * t = output;
printf("Enter the secret string:\n");
fgets(test2, 50, stdin);
for (int i=0;i<49;i++){ //fills ouput with _ spaces
*(output +i)='_';
while(strcmp(s,t) != 0){
printf("Enter a guess:");
scanf("%c",&guess);
printf("You entered: %c\n", guess);
showGuess(guess,s, t ); // makes a string "output" with guesses in it
printf("%s\n",t);
}
printf("Well Done!");
}
For a quick and dirty solution try
// the space in the format string consumes optional spaces, tabs, enters
if (scanf(" %c", &guess) != 1) /* error */;
For a better solution redo your code to use fgets() and then parse the input.
As pointed out in some other answers and comments, you need to "consume" the "newline character" in the input.
The reason for that is that the input from your keyboard to the program is buffered by your shell, and so, the program won't see anything until you actually tell your shell to "pass the content of its buffer to the program". At this point, the program will be able to read the data contained in the previous buffer, e.g. your input, followed by one the character(s) used to validate your input in the shell: the newline. If you don't "consume" the newline before you do another scanf, that second scanf will read the newline character, resulting in the "skipped scanf" you've witnessed. To consume the extra character(s) from the input, the best way is to read them and discard what you read (what the code below does, notice the
while(getc(stdin) != '\n');
line after your scanf. What this line does is: "while the character read from stdin is not '\n', do nothing and loop.").
As an alternative, you could tell your shell to not buffer the input, via the termios(3) functions, or you could use either of the curses/ncurses libraries for the I/O.
So here is what you want:
int main(){
char guess;
char test2 [50];
char * s = test2; // 3. Useless
char output [50];
char * t = output; // 3. Useless
int i; // 8. i shall be declared here.
printf("Enter the secret string:\n");
fgets(test2, 50, stdin);
for (i=0;i<50;i++) if (test2[i] == '\n') test2[i] = '\0'; // 4. Remove the newline char and terminate the string where the newline char is.
for (int i=0;i<49;i++){ // 5. You should use memset here; 8. You should not declare 'i' here.
*(output +i)='_';
} // 1. Either you close the block here, or you don't open one for just one line.
output[49] = '\0'; // 6. You need to terminate your output string.
while(strcmp(s,t) != 0){ // 7. That will never work in the current state.
printf("Enter a guess:");
scanf("%c",&guess);
while(getc(stdin) != '\n');
printf("You entered: %c\n", guess);
showGuess(guess,s, t );
printf("%s\n",t);
}
printf("Well Done!");
return 0; // 2. int main requires that.
}
Other comments on your code:
You opened a block after your for loop and never closed it. That might be causing problems.
You declared your main as a function returning an integer... So you should at least return 0; at the end.
You seem to have understood that char * t = output; copies output's value and uses t as a name for the new copy. This is wrong. You are indeed copying something, but you only copy the address (a.k.a reference) of output in t. As a result, output and t refer to the same data, and if you modify output, t will get modified; and vice versa. Otherwise said, those t and s variables are useless in the current state.
You also need to remove the newline character from your input in the test2 buffer. I have added a line after the fgets for that.
Instead of setting all the bytes of an array "by hand", please consider using the memset function instead.
You need to actually terminate the output string after you "fill" it, so you should allocate a '\0' in last position.
You will never be able to compare the test2 string with the output one, since the output one is filled with underscores, when your test2 is NULL terminated after its meaningful content.
While variables at the loop scope are valid according to C99 and C11, they are not standard in ANSI C; and it is usually better to not declare any variable in a loop.
Also, "_ spaces" are called "underscores" ;)
Here is a code that does what you want:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LEN 50
int main()
{
char phrase[LEN];
char guessed[LEN];
char guess;
int i, tries = 0;
puts("Please enter the secret string:");
if(fgets(phrase, LEN, stdin) == NULL)
return 1;
for(i = 0; i < LEN && phrase[i] != '\n'; i++); // Detect the end of input data.
for(; i < LEN; i++) // For the rest of the input data,
phrase[i] = '_'; // fill with underscores (so it can be compared with 'guessed' in the while loop).
phrase[LEN - 1] = '\0'; // NULL terminate 'phrase'
memset(guessed, '_', LEN); // Fill 'guessed' with underscores.
guessed[LEN - 1] = '\0'; // NULL terminate 'guessed'
while(strcmp(phrase, guessed) != 0) // While 'phrase' and 'guessed' differ
{
puts("Enter a guess (one character only):");
if(scanf("%c", &guess) != 1)
{
puts("Error while parsing stdin.");
continue;
}
if(guess == '\n')
{
puts("Invalid input.");
continue;
}
while(getc(stdin) != '\n'); // "Eat" the extra remaining characters in the input.
printf("You entered: %c\n", guess);
for(i = 0; i < LEN; i++) // For the total size,
if(phrase[i] == guess) // if guess is found in 'phrase'
guessed[i] = guess; // set the same letters in 'guessed'
printf("Guessed so far: %s\n", guessed);
tries++;
}
printf("Well played! (%d tries)\n", tries);
return 0;
}
Feel free to ask questions in the comments, if you are not getting something. :)
Newline character entered in the previous iteration is being read by scanf. You can take in the '\n' by using the getc() as follows:
scanf("%c",&guess);
getc(stdin);
..
This changed worked for me. Though the right explanation and c leaner code is the one given by #7heo.tk
Change
scanf("%c",&guess);
with
scanf(" %c",&guess);
It should ignore '\n'.

C - Malloc issue (maybe something else)

Update edition:
So, I'm trying to get this code to work without using scanf/fgets. Gets chars from the user, puts it into a pointer array using a while loop nested in a for loop.
#define WORDLENGTH 15
#define MAXLINE 1000
int main()
{
char *line[MAXLINE];
int i = 0;
int j;
int n;
char c;
for (n=0; c!=EOF; n){
char *tmp = (char *) malloc(256);
while ((c=getchar())!=' '){
tmp[i]=c; // This is no longer updating for some reason.
i++;
}
line[n++]=tmp; //
i=0;
printf("\n%s\n",line[n]); //Seg fault here
}
for(j = 0; j (lessthan) n; j++){
printf("\n%s\n", line[j]);
free (line[j]);
}
return 0;
So, now I'm getting a seg fault. Not sure why tmp[i] is not updating properly. Still working on it.
I've never learned this much about programming during the entire semester so far. Please keep helping me learn. I'm loving it.
You print line[i] and just before that, you set i to 0. Print line[n] instead.
Also, you forgot the terminating 0 character. And your code will become easier if you make tmp a char array and then strdup before assigning to line[n].
sizeof(WORLDLENGTH), for one, is wrong. malloc takes an integer, and WORLDLENGTH is an integer. sizeof(WORLDLENGTH) will give you the size of an integer, which is 4 if you compile for a 32-bit system, so you're allocating 4 bytes.
Btw - while ((c=getchar())!=' '||c!=EOF) - what's your intent here? A condition like (a!=b || a!=c) will always return true if b!=c because there is no way a can be both b and c.
And, as others pointed out, you're printing out line[i], where i is always 0. You probably meant line[n]. And you don't terminate the tmp string.
And there's no overflow checking, so you'll run into evil bugs if a word is longer than WORDLENGTH.
Others have already told you some specific problems with your code but one thing they seem to have missed is that c should be an int, not a char. Otherwise the comparison to EOF wil not work as expected.
In addition, the segfault you're getting is because of this sequence:
line[n++]=tmp;
printf("\n%s\n",line[n]);
You have already incremented n to the next array element then you try to print it. That second line should be:
printf("\n%s\n",line[n-1]);
If you just want some code that works (with a free "do what you darn well want to" licence), here's a useful snippet from my code library.
I'm not sure why you think fgets is to be avoided, it's actually very handy and very safe. I'm assuming you meant gets which is less handy and totally unsafe. Your code is also prone to buffer overruns as well, since it will happily write beyond the end of your allocated area if it gets a lot of characters that are neither space nor end of file.
By all means, write your own code if you're educating yourself but part of that should be examining production-tested bullet-proof code to see how it can be done. And, if you're not educating yourself, you're doing yourself a disservice by not using freely available code.
The snippet follows:
#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;
}
// Test program for getLine().
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;
}
It's a useful line input function that has the same buffer overflow protection as fgets and can also detect lines entered by the user that are too long. It also throws away the rest of the too-long line so that it doesn't affect the next input operation.
Sample runs with 'hello', CTRLD, and a string that's too big:
pax> ./qq
Enter string> hello
OK [hello]
pax> ./qq
Enter string>
No input
pax> ./qq
Enter string> dfgdfgjdjgdfhggh
Input too long
pax> _
For what it's worth (and don't hand this in as your own work since you'll almost certainly be caught out for plagiarism - any half-decent educator will search for your code on the net as the first thing they do), this is how I'd approach it.
#include <stdio.h>
#include <stdlib.h>
#define WORDLENGTH 15
#define MAXWORDS 1000
int main (void) {
char *line[MAXWORDS];
int numwords = 0; // Use decent variable names.
int chr, i;
// Code to run until end of file.
for (chr = getchar(); chr != EOF;) { // First char.
// This bit gets a word.
char *tmp = malloc(WORDLENGTH + 1); // Allocate space for word/NUL
i = 0;
while ((chr != ' ') && (chr != EOF)) { // Read until space/EOF
if (i < WORDLENGTH) { // If space left in word,
tmp[i++] = chr; // add it
tmp[i] = '\0'; // and null-terminate.
}
chr = getchar(); // Get next character.
}
line[numwords++] = tmp; // Store.
// This bit skips space at end of word.
while ((chr == ' ') && (chr != EOF)) {
chr = getchar();
}
}
// Now we have all our words, print them.
for (i = 0; i < numwords; i++){
printf ("%s\n", line[i]);
free (line[i]);
}
return 0;
}
I suggest you read that and studdy the comments so that you know how it's working. Feel free to ask any questions in the comments section and I'll answer or clarify.
Here's a sample run:
pax$ echo 'hello my name is pax andthisisaverylongword here' | ./testprog
hello
my
name
is
pax
andthisisaveryl
here
Change your printf line - you need to print line[n] rather than line[i].
first your malloc formula is wrong
malloc(sizeof(char)*WORDLENGTH);
you need to allocate the sizeof a char enought times for the lenght of your word (also 15 seems a bit small, your not counting the longest word in the dictionnary or the "iforgettoputspacesinmyphrasestoscrewtheprogrammer" cases lol
don't be shy char is small you can hit 256 or 512 easily ^^
also
printf("\n%s\n",line[i]);
needs to be changed to
int j = 0;
for(j=0;j<i;j++){
printf("\n%s\n",line[j]);
}
your i never changes so you always print the same line

Resources