C - проблема Malloc (может быть что-то еще) - PullRequest
2 голосов
/ 02 декабря 2010

Обновление издания:

Итак, я пытаюсь заставить этот код работать без использования scanf / fgets. Получает символы от пользователя, помещает его в массив указателей, используя цикл while, вложенный в цикл for.

#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;

Итак, теперь у меня ошибка в сегменте. Не уверен, почему tmp [i] не обновляется должным образом. Все еще работаю над этим.

До сих пор я так много не изучал программирование за весь семестр. Пожалуйста, продолжайте помогать мне учиться. Я люблю это.

Ответы [ 5 ]

4 голосов
/ 02 декабря 2010

Вы печатаете line[i], а перед этим вы устанавливаете i в 0. Вместо этого выведите line[n].

Также вы забыли завершающий символ 0.И ваш код станет проще, если вы сделаете tmp массив символов, а затем strdup перед присвоением line[n].

3 голосов
/ 02 декабря 2010

sizeof(WORLDLENGTH), например, неправильно. malloc принимает целое число, а WORLDLENGTH - целое число. sizeof (WORLDLENGTH) даст вам целое число, равное 4, если вы компилируете для 32-битной системы, поэтому вы выделяете 4 байта.

Кстати - while ((c=getchar())!=' '||c!=EOF) - каково ваше намерение здесь? Условие типа (a!=b || a!=c) всегда будет возвращать true, если b! = C, потому что нет никакого способа, которым a может быть и b, и c.

И, как отмечали другие, вы печатаете line[i], где я всегда равен 0. Вы, вероятно, имели в виду line[n]. И вы не завершаете строку tmp.

И проверки переполнения нет, поэтому вы столкнетесь со злыми ошибками, если слово длиннее WORDLENGTH.

1 голос
/ 02 декабря 2010

Другие уже говорили вам о некоторых специфических проблемах с вашим кодом, но одна вещь, которую они, похоже, упустили, это то, что c должно быть int, а не char. В противном случае сравнение с EOF не будет работать должным образом.

Кроме того, вы получаете segfault из-за этой последовательности:

line[n++]=tmp;
printf("\n%s\n",line[n]);

У вас уже увеличен n до следующего элемента массива, затем вы пытаетесь его распечатать. Эта вторая строка должна быть:

printf("\n%s\n",line[n-1]);

Если вы просто хотите, чтобы какой-то код работал (с бесплатной лицензией «делай, что хочешь, черт побери»), вот полезный фрагмент из моей библиотеки кодов.

Я не уверен, почему вы думаете, что fgets следует избегать, это на самом деле очень удобно и очень безопасно. Я предполагаю, что вы имели в виду gets, который менее удобен и абсолютно небезопасен. Ваш код также подвержен переполнению буфера, так как он будет успешно записывать за пределы вашей выделенной области, если получит много символов, которые не являются ни пробелом, ни концом файла.

Во что бы то ни стало, напишите свой собственный код, если вы обучаетесь, но часть этого должна быть посвящена проверенному на производстве пуленепробиваемому коду, чтобы увидеть, как это можно сделать . И, если вы не обучаете себя, вы оказываете себе медвежью услугу, не используя свободно доступный код.

Ниже приведен фрагмент кода:

#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;
}

Это полезная функция ввода строки, которая имеет такую ​​же защиту от переполнения буфера, что и fgets, и также может обнаруживать слишком длинные строки, введенные пользователем. Он также отбрасывает оставшуюся часть слишком длинной строки, чтобы не влиять на следующую операцию ввода.

Пример запускается с 'hello', CTRL D и слишком большой строкой:

pax> ./qq
Enter string> hello
OK [hello]

pax> ./qq
Enter string>
No input

pax> ./qq
Enter string> dfgdfgjdjgdfhggh
Input too long

pax> _

Для чего это стоит (и не сдавайте это как свою собственную работу, так как вы почти наверняка будете пойманы на плагиат) - любой полу-приличный преподаватель будет искать ваш код в сети как первое, что он делает ), вот как я к этому подхожу.

#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;
}

Я предлагаю вам прочитать это и изучить комментарии, чтобы вы знали, как это работает. Не стесняйтесь задавать любые вопросы в разделе комментариев, и я отвечу или уточню.


Вот пример прогона:

pax$ echo 'hello   my name is pax andthisisaverylongword here' | ./testprog
hello
my
name
is
pax
andthisisaveryl
here
1 голос
/ 02 декабря 2010

сначала ваша неправильная формула malloc

 malloc(sizeof(char)*WORDLENGTH);

вам нужно выделить размер количества символов, умноженных на длину вашего слова (также 15 кажется немного малым, вы не учитываете самое длинное слово всловарь или случаи «iforgettoputspacesinmyphrasestoscrewtheprogrammer» lol не стесняйтесь, маленький символ, который вы можете легко набрать 256 или 512 ^^

также

 printf("\n%s\n",line[i]);

необходимо изменить на

int j = 0;

for(j=0;j<i;j++){
     printf("\n%s\n",line[j]);
}

ваш i никогда не меняется, поэтому вы всегда печатаете одну и ту же строку

1 голос
/ 02 декабря 2010

Измените printf строку - вам нужно напечатать line[n] вместо line[i].

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...