2015-09-28 14 views
-2

Я пытаюсь изучить C. Я хочу заполнить 2D-массив из 1D-массива, который я получил из файла.Заполнение 2D-массива из массива 1D в C

Теперь я пытаюсь взять элементы указателя массива (вывод: Hello, My, name, is, Ram.) В двумерный массив, называемый словами. цель состоит в том, чтобы удалить запятые и выделить каждое слово в другой строке. Я тоже этого добился. Тем не менее, я получаю какую-то тарабарщину вместе с моей работой. Я проверил свои записи один за другим и обнаружил, что первая строка (Hello, My, name, is, Ram.) Хранится в строке от 1 до 5 в слове []. Однако следующая строка (I, own, 20, тыс., Баксов) начинается со строки [10] слова, что я не понимаю почему? плюс мой вывод выглядит странно с некоторыми неизвестными значениями. Пожалуйста, сообщите мне, что я должен сделать, чтобы исправить свою мощность и размер 2 D массива равно значению оно содержит

Вот мой код:

int main(int argc, const char * argv[]) { 
    // insert code here... 
    FILE *fp; 
    char (*points)[50]; 
    char *array; 
    int width=20,height=50; 
    char *word; 
    char words [width][height]; 
    int counter=0; // To traverse through array and tracks the current position in array. 
    points = malloc(sizeof(*points) * 2); 

    word=malloc(width*height*sizeof(char)); 
    if (points == NULL) { 
     perror("malloc"); 
     exit(0); 
    } 
    fp = fopen("/Users/shubhamsharma/Desktop/data.txt", "r"); 
    if (fp == NULL) { 
     perror("fopen"); 
     exit(EXIT_FAILURE); 
    } 
    fgets(points[0], sizeof(*points), fp); 
    fgets(points[1], sizeof(*points), fp); 
    array=points[0]; 
    printf("%s", points[0]); 
    printf("%s", points[1]); 

    for(int i=0;i<width;i++) 
    { 
     for(int j=0,p=counter;j<height;j++,p++) 
     { 
      if(array[p]==','||array[p]=='\0') 
      { 
       words[i][j]='\n'; 
       counter=++p; 
       break; 
      } 
      else 
       words[i][j]=array[p]; 

     }} 

    printf("\n%c",words[16][0]); 
    for (int i=0; i<width; i++) { 
     for (int j=0; j<height; j++) { 

      if(words[i][j]=='\n') 
      { 
       break; 
      } 
      printf("\nPrinting element in word\n"); 
      printf("%c",words[i][j]); 

     } 
    } 

    printf("\n"); 
    fclose(fp); 

    free(points); 
    return 0; 
    return 0; 
    } 

Выход:

> Hello,My,name,is,Ram. I,own,20,thousand,bucks. Printing element in word 
> HelloMynameisRam.+̮\213\377\310`\267t\377̮\213\377Iown20thousandbucks. 
> Program ended with exit code: 0 

Линии в моей файл выглядит примерно так .-

Hello,My,name,is,Ram. 
I,own,20,thousand,bucks. 
+0

Знаете ли вы, что C и C++ - разные языки? – Olaf

+0

Олаф может спрашивать из-за 'char words [width] [height];' или какой-либо другой конструкции, которая не будет компилироваться. Нам нужно знать, какой компилятор вы используете, и строите ли вы C или C++. – JVene

+0

Я строю с помощью C с помощью XCODE. Извините, я думал, что логика может быть одинаковой в C и C++. –

ответ

-1

Ваш код не имеет #include <stdio.h> и #include <stdlib.h>.

После этого ваш код правильно распределяет память; но вы никогда не используете word, чтобы его можно было удалить.

Ваш код правильно считывает первую строку. Однако, после условия array[p] == '\0', при следующем вводе цикла j он просто продолжает читать хлам от points[0], после окончания данных, прочитанных fgets. Это приводит к неопределенному поведению, вам повезло, что результаты были такими же согласованными, как и они.

Вам необходимо иметь дополнительный код для случая array[p] == '\0' для перемещения array на чтение следующей строки, например. array = points[1]; p = counter = 0; break;. (На самом деле p избыточна в этом цикле, вы могли бы просто использовать counter непосредственно)

Это будет включать дополнительную переменную для отслеживания индекс points вы до, и гарантировать, что Вы не идут с конца.

Лучше было бы только для чтения каждой строки, как вы обрабатываете его: избавиться от array, имеют один буфер char line[50]; и вызвать fgets в начале, а затем каждый раз, когда вы достигли '\0' по обработке этой линии ,

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

И, наконец, ваш код для отображения строк неверен. words[16][0] может быть в конце того, что вы читаете, в зависимости от входного файла, и в настоящее время вы печатаете Printing element in word до каждый символ. Ваш образец вывода, который вы опубликовали в своем вопросе, не показывает этого, поэтому, я думаю, код, который вы опубликовали, не соответствует коду, который вы тестировали.

Вместо этого я хотел бы предложить вам обновить «чтение» кода на нуль-прекратить строки (используйте words[i][j]='\0'; вместо words[i][j]='\n';), а затем вы можете использовать стандартные функции для их печати:

for (int n = 0; n < i; n++) 
    printf("%s\n", words[n]); 

Here Ваш код работает с минимальными изменениями, которые я предложил.Я вложил некоторые строки отладки printf, которые можно отменить, чтобы посмотреть, как он работает, и я меняю использование stdin вместо открытия файла, чтобы его можно было увидеть в онлайн-компиляторе. Вы все еще можете многое сделать, чтобы улучшить свой код! (для начала, пообщайтесь с дополнительным \n, который fgets оставляет в буфере).

0

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

char words[width][height];

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

Это отличается от C++, чем в C, поэтому критически важно точно определить, что вы используете для компиляции, и если вы намереваетесь писать на C, а не на C++.

Предполагая, что C, вам нужно будет иметь некоторые средства определения этих двух. Возможно:

#define WIDTH 20 
#define HEIGHT 50 

Хотя я уже давно оставил позади C для C++, я не вижу никакого другого пути в C компилятором.

Затем

int width = WIDTH, height = HEIGHT; 

Это просто чтобы быть уверенным, что есть только одно место, чтобы получить эти значения из. В настоящее время

char words[WIDTH][HEIGHT]; 

Скомпилирует. Это объявляет массив из 20 массивов символов, каждый длиной 50 байтов. Это будет соответствовать его использованию в остальной части вашего кода. Два выбранных слова кажутся меняющимися по смыслу значениям, потому что мы обычно думаем о строках как о высоте, в то время как строки в каждой строке кажутся длиной (или шириной), но это не имеет особого значения. В противном случае это нормально.

Однако, это приводит нас к

points = malloc(sizeof(*points) * 2); 

Это не имеет смысла, после этого заявления по пунктам:

char (*points)[50]; 

Я не могу вполне предположить, что это намерено.Компилятор, похоже, считает, что это char[50] *, указатель на массив из 50 байтов, но это из-за скобки вокруг *points. Похоже, вы, возможно, разместили там, чтобы остановить жалобу компилятора, когда она отсутствует.

Это объявление будет массивом из 50 указателей на символ (или 50 символов * в строке);

char * points[50]; 

Это означает, что компилятор не будет принимать:

points = malloc(sizeof(*points) * 2); 

Однако то, что это позволило бы это:

points[0] = malloc(sizeof(*points) * 2); 

Что, как вы используете это позже в коде. Это не делало то, что вы ожидали. То, что вы выделяете, составляет 100 байтов (на большинстве компиляторов), что в два раза больше размера *points, указывая на то, что вам нужно место для двух массивов символов по 50 байт каждый. Однако у вас есть один массив символов размером 100 байт.

Это важно, потому что в коде вы используете его:

fgets(points[0], sizeof(*points), fp); 
fgets(points[1], sizeof(*points), fp); 
array=points[0]; 
printf("%s", points[0]); 
printf("%s", points[1]); 

Это ВЫПОЛНЯЮЩЕМУ points[1], но нет ничего выделено в точках [1]. Фактически, я не уверен, что сгенерирован компилятор, код в его исходной форме не будет компилироваться, но для точек, которые будут использоваться таким образом, требуется два назначения указателя, а не один.

points[0] = malloc(sizeof(*points)); 
points[1] = malloc(sizeof(*points)); 

может сделать использование выше в силе, хотя и не ясно, почему размер основан на массиве точек, возможно, это немного более логичным сказать

points[0] = malloc(HEIGHT); 
points[1] = malloc(HEIGHT); 

Так что точки могут быть более разумно объявлено

char * points[2]; 

Это как оно было использовано.

Чтобы было ясно, в представленном коде нет четкого способа использования смысла points[0] и points[1]. Использование char * array; позже указывает, что вы ожидаете, что две операции fgets будут размещать контент в непрерывном блоке ОЗУ, который может быть организован, но не надежно в том порядке, который был построен здесь.

Это может показаться на работу, когда вы напечатали две строки

printf("%s", points[0]); 
printf("%s", points[1]); 

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

На основании вашего использования массива в следующем:

for(int i=0;i<width;i++) 
{ 
    for(int j=0,p=counter;j<height;j++,p++) 
    { 
     if(array[p]==','||array[p]=='\0') 
     { 
      words[i][j]='\n'; 
      counter=++p; 
      break; 
     } 
     else 
      words[i][j]=array[p]; 

    } 
} 

Похоже, что вы хотели что-то подобное:

array = malloc(HEIGHT * 2); 

После чего это могло бы сделать то, что вы ожидали.

fgets(array, HEIGHT * 2, fp); 

, из которого вы МОГ (почему я не уверен) выравнивания точек с

points[0] = array; 
points[1] = array + HEIGHT; 

Я должен отметить также, что он не появляется в цикле выше, что вы имеете дело с нуля завершение строк.

Это означает, что слова могут содержать мусор, если каждое слово не равно 19 символам с завершающим \n и без нулевого окончания.

Рассмотрите эти вопросы, и, возможно, мы можем отредактировать это, чтобы продвигать ваш план в коде.

+0

Это почти все неправильно. Размеры массива не обязательно должны быть постоянными. 'points = malloc (sizeof (* points) * 2);' правильно. Если вы не признаете основные объявления, такие как 'char (* points) [50];' Я предлагаю воздержаться от ответов на вопросы об этом. –

+0

M.M вы должны избегать быть грубым и презумптивным. 'char (* points) [50];' будет генерировать ошибку компилятора, за которой следует 'points = malloc (sizeof (* points) * 2);' в VS2015. Попробуйте и узнайте. Кроме того, VS2015 отказывается от 'char words [width] [height]; ожидаются постоянные жалобы. Кто-нибудь указывал, какой компилятор? № – JVene

+0

VS хорошо известен тем, что не выполняет C должным образом. Если вы даете VS-специфический ответ, вы должны это сказать. OP сказал в комментариях, что он не использует VS, и вы это подтвердили, а затем написал: «Я не вижу, как это будет скомпилировано для вас», поэтому ваша «защита», которая не работает в VS, явно подделана. BTW, ответное голосование против политики SO. –