简体   繁体   中英

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.

更改printf行 - 您需要打印line[n]而不是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

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', CTRL D , 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM