سؤال

مرحبًا لجميع مستخدمي Stackoverflow. أحاول إنشاء رمز بسيط (كتمرين) سيقرأ من ملف وسيقوم بتخزين الكلمات من ملف في صفيف مخصص ديناميكيًا. أعتقد أنني أخطأ في Mallocing. هل يرى أي شخص ما أفعله خطأ؟

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>

#define ARRSIZE 10

int main(){
    char * myArray = malloc(ARRSIZE*sizeof(char*));
    FILE * p1File;
    char mystring1 [100];
    char word [100];
    int j = 0;
    p1File = fopen ("my1file.txt","r");
    if (p1File == NULL) perror ("Error opening file");
    else{
        while(fgets(mystring1, 100, p1File)){
            int nuRead = sscanf(mystring1, "%s", word);\
            printf("lepo ani magia\n\n");
            if (nuRead > 0){
                strncpy (*myArray[j], mystring1, 100);
                //*myArray[j] = mystring1;
            }
            j += 1;
        } 
    }
}

///////////////////////////////////

my text file is

this
will
probably
work
but
I
am
هل كانت مفيدة؟

المحلول

أنت لا تخصص مساحة لخيوطك ، بل مجرد مجموعة من الأوتار. myArray[j] هو مجرد مؤشر غير ضروري. بدلاً من ذلك ، تخصيص مساحة لكل سلسلة في myArray مثل ذلك:

char *myArray[ARRSIZE]; // No reason for this to be dynamic.
// ...
if (nuRead > 0)
{
    myArray[j] = malloc((strnlen(mystring, 100) + 1) * sizeof(char));
    strncpy (myArray[j], mystring1, nuRead + 1);
}

كما أشار user411313 ، فإن SSCANF لا يعيد عدد الأحرف المتطابقة ، ولكن عدد عناصر الإدخال المتطابقة. يستخدم strnlen (أو strlen إذا لم يكن لديك strnlen) للحصول على حجم السلسلة (ولا تنس إضافة 1 لمقدمة الفارغ).

نصائح أخرى

بالنسبة لهذه المهمة ، سأقوم أولاً بتحديد بنية بيانات تحمل الكلمات ، مثل هذا:

struct wordlist {
    char **words; /* the actual words */
    size_t size; /* the number of words in the list */
    size_t capacity; /* the number of words that would fit in the list */
};
typedef struct wordlist wordlist;

ثم أود تحديد بعض الوظائف للعمل عليها. هذا للحفاظ على الكود في main قصيرة وقابلة للقراءة. الوظائف هي:

void *
malloc_or_fail(size_t size)
{
  void *result = malloc(size);
  if (result == NULL) {
    perror("malloc");
    exit(EXIT_FAILURE);
  }
  return result;
}

/* Creates a newly allocated copy of the given string. Later changes
 * to the given string will not have any effect on the returned string.
 */
char *
str_new(const char *str) {
  size_t len = strlen(str);
  char *result = malloc_or_fail(len + 1);
  memcpy(result, str, len + 1);
  return result;
}

/* Adds a copy of the given string to the word list. Later changes
 * to the given string have no effect on the word in the word list.
 */
void
wordlist_add(wordlist *wl, const char *word)
{
  if (wl->size == wl->capacity) {
    /* TODO: resize the wordlist */
  }
  assert(wl->size < wl->capacity);
  wl->words[wl->size++] = str_new(word);
}

/* Creates a new word list that can hold 10 words before it will be
 * resized for the first time.
 */
wordlist *
wordlist_new(void)
{
  wordlist *result = malloc_or_fail(sizeof wordlist);
  result->size = 0;
  result->capacity = 10;
  result->words = malloc_or_fail(result->capacity * sizeof result->words[0]);
  return result;
}

باستخدام هذه الوظائف ، لا ينبغي أن يكون من الصعب إكمال المهمة الأصلية.

char * myArray = malloc(ARRSIZE*sizeof(char*));

لقد خصصت مكانًا لتخزين عشرة مؤشرات سلسلة. لكنك لم تخصص أي مساحة لنسخ الأحرف إلى سلاسل مستمرة.

إذا كنت ترغب في إعداد هذا التخزين في البداية ، فيمكنك القيام بذلك

#define MAX_STR_SIZE 100

char * myArray = malloc(ARRSIZE*sizeof(char*));
if (!myArray) exit(1);
for (j=0; j<ARRSIZE; j++) {
    myArray[j] = malloc(MAX_STR_SIZE);
    if (!myArray[j]) exit(1);
}

أو ، ربما أفضل ، يمكنك تخصيص كل سلسلة حسب الحاجة. بدلاً من strncpy, ، استعمال strdup (وهو مثل القيام malloc ثم strcpy):

    myArray[j] = strdup(mystring1);

إذا كنت بحاجة فقط إلى التعامل مع ما يصل إلى 10 أسطر من النص ، فسأفعل ذلك أكثر مثل هذا:

char *myArray[ARRSIZE];
...
if (nuRead > 0) {
  myArray[j++] = strdup(mystring1);
}
...

ما يحدث هو أن هذا الرمز يخصص ونسخ في واحدة (باستخدام Strdup, ، عوضا عن مالوك تليها strcpy).

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top