【问题标题】:dynamic memory and fgets动态内存和 fget
【发布时间】:2010-11-23 18:26:03
【问题描述】:

向所有 stackoverflow 用户致敬。 我正在尝试构建一个简单的(作为练习)代码,该代码将从文件中读取并将文件中的单词存储在动态分配的数组中。我想我分配错了。有人看到我做错了吗?

#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

【问题讨论】:

  • 你看到了什么行为?

标签: c malloc pipe fgets scanf


【解决方案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;
}

使用这些功能完成原来的任务应该不难。

【讨论】:

  • 感谢 Roland 提供的详细示例。最欣赏。 :)
【解决方案2】:

您没有为字符串分配空间,只是为字符串数组分配空间。 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(如果没有strnlen,则使用strlen)来获取字符串的大小(并且不要忘记为空终止符添加1)。

【讨论】:

  • -1 个大错误。 sscanf 返回的不是字符数(对于您的 malloc)。 sizeof(char) 始终为 1。
  • @user411313:谢谢,我已经习惯了一个确实会返回匹配字符数的库。 sizeof(char) 可能总是 1,但我喜欢明确。很明显,我分配的是字节而不是单词,如果我的 malloc 调用都遵循相同的模式,我会更快地阅读。
【解决方案3】:
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);

【讨论】:

    【解决方案4】:

    如果您只需要处理最多 10 行文本,那么我会这样做:

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

    发生的情况是这段代码一次性分配和复制(使用 strdup,而不是 malloc 后跟 strcpy)。

    【讨论】:

      猜你喜欢
      • 2016-07-19
      • 1970-01-01
      • 2011-05-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多