返回指向字符串数组C的指针

时间:2018-08-02 19:46:54

标签: c pointers

我试图返回从文件中获取的字符串数组。文件看起来像这样(第一行是单词数,每行都是单词)。当函数结束时,我会在主要部分得到一些奇怪的输出。我想返回指向字符串数组的指针。请注意,使用打印的部分代码用于检查我的程序。

这是分配内存的函数:

char *generisiProstor(int n) {
    return (char*)malloc(n*sizeof(char[20])); 
}

此函数用于从rijeci.txt提取单词,并且应返回指向包含单词的字符串数组的指针:

char* ucitajRijeci(int n) {

    char  i;
    char *rijeci;

    static const char filename[] = "rijeci.txt";
    FILE *file;
    file = fopen(filename, "r");
    if (file != NULL)
    {
        char line[20];
        int n;
        fscanf(file, "%d", &n);
        rijeci = generisiProstor(n);
        if (rijeci == NULL) { 
            return NULL;
        }
        int i = -1;

        fgets(line, 20, file);        //skipping first line witch is integer and not needed
        while (fgets(line, 20, file) != NULL) 
        {
            printf("%s\n", line);            //normal output
            i++;
            strcpy(rijeci + i, line);
            printf("%s\n", rijeci + i);     //normal expected output
        }
        for (i = 0; i < n; i++) {
            printf("%s\n", rijeci + i);   //wrong output
        }
    }
    return rijeci;
}

主要

int main()
{
    static const char filename[] = "rijeci.txt";
    FILE *file;
    file = fopen(filename, "r");
    char *rijeci;
    int i;
    if (file != NULL)
    {
        char line[20];
        int n;
        fscanf(file, "%d", &n);
        rijeci = ucitajRijeci(n);
        printf("Here is the array: ");
        for (i = 0; i < n; i++) {
            printf("%s ", rijeci+i);  //wrong output
        }
    }
    return 0;
}

5 个答案:

答案 0 :(得分:2)

在这里,您必须使用二维数组(char **而不是char *)。由于您要返回二维数组,因此必须将rijeci声明为char **rijeci;

  1. 两个函数的返回类型也应为char **
  2. rijeci + i更改为rijeci[i]
  3. 正确的代码缩进。

尝试此修改后的代码。这将起作用:-

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

/* generisiProstor */

char **generisiProstor(int n)
{
    char **c; // making 2-d array
    c = (char **)malloc(n * sizeof(char *));
    for (int i = 0; i < n; i++)
    {
        c[i] = (char *)malloc(20 * sizeof(char));
    }
    return c;
}

/*  ucitajRijeci  */

char **ucitajRijeci(int n)
{

    char **rijeci; // change to char **

    static const char filename[] = "rijeci.txt";
    FILE *file;
    file = fopen(filename, "r");
    if (file != NULL)
    {
        char line[20];
        int n;
        fscanf(file, "%d", &n);
        rijeci = generisiProstor(n);
        if (rijeci == NULL)
        {
            return NULL;
        }
        int i = -1;

        fgets(line, 20, file); //skipping first line witch is integer and not needed
        while (fgets(line, 20, file) != NULL)
        {
            printf("%s\n", line); //normal output
            i++;
            strcpy(rijeci[i], line);
            printf("%s\n", rijeci[i]); //changed to rijeci[i]
        }
        for (i = 0; i < n; i++)
        {
            printf("%s\n", rijeci[i]); //changed to rijeci[i]
        }
    }
    return rijeci;
}

/*  main()  */

int main()

{

    static const char filename[] = "rijeci.txt";
    FILE *file;
    file = fopen(filename, "r");
    char **rijeci; // change to char **
    int i;
    if (file != NULL)
    {
        char line[20];
        int n;
        fscanf(file, "%d", &n);
        rijeci = ucitajRijeci(n);
        printf("Here is the array: ");
        for (i = 0; i < n; i++)
        {
            printf("%s ", rijeci[i]); //changed to rijeci[i]
        }
    }
    return 0;
}

答案 1 :(得分:1)

您知道 array string 的定义吗?

我会按照2011年C标准的要求将它们提供给您

  

数组类型描述具有特定成员对象类型(称为元素类型)的连续分配的非空对象集。 […]

     

string 是连续的字符序列,以第一个空字符结尾并包括第一个空字符。 […]

因此, array 是从完整对象类型派生的类型,但是 string 不是类型,而是数据结构。


你非常高兴。您确定要强迫编译器无理由地相信您是一个好习惯吗?与sizeof expr相比,sizeof (TYPE)也更受欢迎,因为在以后重构时更容易出错或不同步。
考虑阅读“ Do I cast the result of malloc? ”。

答案 2 :(得分:0)

您遇到的第一个问题在这里:

char *generisiProstor(int n) {

return (char*)malloc(n*sizeof(char[20])); 
}

您需要一个char指针数组,但是返回一个char指针或char数组。

这部分应该是:

char **generisiProstor(int n) {

return (char**)malloc(n*sizeof(char[20])); 
}

char *rijeci遇到相同的问题,您将其声明为字符串或char指针。
您应该像这样char **rijeci声明它(在这种情况下,您可能希望它是char *(rigeci[20])),这样它将是一个字符串数组。

如果我的代码正确无误,则此部分可能会出现另一个问题:

while (fgets(line, 20, file) != NULL) 
    {
        printf("%s\n", line);            //normal output
        i++;
        strcpy(rijeci + i, line);
        printf("%s\n", rijeci + i);     //normal expected output
    }

在代码的早期,您为n个单词分配了内存。在这里,您正在阅读该行,并将其放入line中。因此,当您读取第一行时,i0,但是在复制前先增加它,因此数组未设置其第一次出现的位置,并且将最后一个字写入未分配的内存中。

这部分应该是:

while (fgets(line, 20, file) != NULL) 
    {
        printf("%s\n", line);            //normal output
        strcpy(rijeci + i, line);
        i++
        printf("%s\n", rijeci + i);     //normal expected output
    }

答案 3 :(得分:0)

如果要返回大小为20的char数组的指针,则必须声明该函数,如下所示:

char (*generisiProstor(int n))[20]
{
    return malloc(n*sizeof(char[20]));
}

保存指向数组的指针的变量声明为:

char (*rijeci)[20];

rijeci[i]类型为char[20],您可以在此处编写字符串。

答案 4 :(得分:0)

您正在分配正确的内存量,但是您需要更改使用方式。 malloc()只能返回一个“平面”字符数组,因此,generisiProstor()的返回值是指向整个数组中第一个字符的简单指针。

最初起作用的原因是每个字符串都会覆盖前一个字符串的尾端,因此当您在读入循环中执行打印输出时,它们将正确显示。但是,即使这样,rijeci数组的有效负载也会在您完成读取时完全损坏。

一种可能的解决方案是使用一个结构来保存您的单词:

struct Rijec
{
    char rijec[20];
};

,然后将generisiProstor(int n)更改为:

struct Rijeci *generisiProstor(int n)
{
    return malloc(n * sizeof(struct Rijec)); 
}

请注意,C语言并不需要should be avoided强制转换。

然后,您需要将ucitajRijeci()的顶部更改为这样:

struct Rijec *ucitajRijeci(int n)
{
    struct Rijec *rijeci;
    ...

,并且在所有使用rijeci + i的情况下,都将其更改为rijeci[i].rijec

其最终结果是,当您使用irijeci数组中的单词建立索引时,偏移量现在将是正确的。