2

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.

5 Answers 5

4

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].

Sign up to request clarification or add additional context in comments.

2 Comments

Terminating 0 character? You mean \0?
Since '\0' == 0, I normally use the latter :)
3

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.

8 Comments

Ahhhh, I had totally forgotten about that, but I won't again! Still getting the same issue though =\
yep need to do malloc(sizeof(char)*WORDLENGTH);
Yep, malloc(WORDLENGTH) is sufficient. Btw, I edited my answer to add a few more issues.
well if the standard sizeof(char) == 1, then it would work but my memory of C is that each compiler does as it feels on a lot of things lol + it is good practice to avoid the problem when you change to a list of floats, or double and you forget.
Defensive programming - be sure to protect yourself against any possible issue that could crash your app, especially when dealing with user input.
|
3

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 

5 Comments

I don't want to use fgets in an assignment where we aren't supposed to have used that because teachers for some reason don't like it when you get help and people offer you answers that are more useful than what they're currently teaching you. Why they do this I have no idea. I really appreciate this example! So much better than the one I have, yet, I must force on through this scenario. I guess it's good programming practice to be stuck in a box as well =\
Then, I'll offer one piece of invaluable advice. Know how much memory you've allocated and know how much of it you've already written to. Never let the latter exceed the former :-) In any case, I would applaud a student doing their own research. Look into fgets and understand it. If you're called on it, you will be able to defend your choice in that case. If an educator marked me down for knowing more than them, I'd take that up with the educational institution. YMMV.
Maybe that's why I'm getting a segmentation fault right now? =\ It was so close to working and then I change the code: Seg fault. Change it back? Seg fault. Whyyyyyyyyyyy
Post the current code, exactly as is, in another question along the lines of "why is this code giving a segmentation violation". Then relax for about 2 minutes for the swarm to attack it :-)
Thanks so much for the update! I'll make sure your work does not go to waste!
1

Change your printf line - you need to print line[n] rather than line[i].

Comments

1

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

1 Comment

I wasn't sure! I'm afraid to allocate too much memory potentially? I'll make sure I fix that.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.