通过指针C将数组连接到结构

时间:2017-08-27 12:07:35

标签: c arrays pointers struct malloc

我有一个结构:

struct s 
{
    unsigned size;
    char *var;
};

指向结构的指针数组

for(i=0;i<rows;i++)
{
    for(j=0;j<columns;j++)
    {
        array[i][j] = (struct s*)malloc(sizeof(struct s));
        printf("Give the size to structure nr. %d: \n",i*columns+j+1);
        scanf("%d",&(array[i][j]->size));
    }
}   

和一个函数,它返回一个指向随机字符数组的指针,其大小由用户选择:

char* ChainOfCharacters(int liczba)
{
    int i;
    char *tabc = NULL;
    tabc = (char*)malloc(liczba*sizeof(char));
    if(tabc==NULL) exit(-1);

    else
    {
        char *tab=NULL;
        tab=tabc;
        for(tabc;tabc<tab+liczba;tabc++)
        {
            *tabc=rand()%(122-97)+97;
        }
    return tabc;    
    }
}

如何通过使用指向结构的指针数组将这个函数的结果字符数组连接到char *var的指针structure s?我的代码中有错误吗?

我试过这个:array[i][j]->var=ChainOfCharacters(array[i][j]->size);但似乎是错误的,因为我在尝试通过printf检查时遇到了错误的字符。 我甚至不知道如何通过printf在屏幕上编写字符数组。我尝试了这个printf("%c ", *(array[i][j]->var));,但它显示了完全随机的迹象。 我将非常感谢我的问题的答案:)

2 个答案:

答案 0 :(得分:2)

首先,让我们通过发布的代码解决一些问题。 size_t是数组索引和大小的正确类型,因此.size结构的s成员应具有类型size_t。这也意味着ChainOfCharacters()函数应该采用size_t类型的参数,这会对printf()scanf()的调用中的格式字符串说明符产生影响。

用户不能在输入提示下输入数字,在这种情况下不会进行任何分配;但由于发布的代码不检查从scanf()返回的值以验证输入是否正确,因此代码将继续在.size字段中具有不确定的值,从而导致未定义的行为。下面的代码检查这一点,如果用户在这里输入数字失败,则会退出并显示错误消息,但此输入验证可以进一步改进。

请注意,使用EXIT_FAILURE宏比使用-1更好,因为这样更清晰,更便携。

ChainOfCharacters()函数不返回字符串,只返回指向字符数组的指针,因此需要逐个打印字符。

请注意,不需要在C中强制转换malloc()的结果,并且最好使用标识符而不是sizeof运算符的操作数的显式类型:这不容易出错类型改变时更容易维护。

ChainOfCharacters()函数中分配字符的循环是不必要的复杂并且包含错​​误,可能是由于这种复杂性; tabc指针在返回时指向已分配存储结束的一个指针。这可以通过重写循环来使用索引而不是指针算法来解决。在可能的情况下,使用数组索引而不是指针算法通常更清晰,更不容易出错。避免使用幻数:rand() % ('z' - 'a') + 'a'在意图上比rand()%(122-97)+97更清晰(并且不要害怕使用一点空格)。此外,请注意C标准对实现可能使用的字符编码几乎没有限制,特别是这不是ASCII。拉丁字母的字母甚至不需要以连续的顺序编码,就像EBCDIC(在现实世界中仍然存在)的情况一样。这不太可能是一个问题,但知道有可行的方法来处理这个问题。

要从ChainOfCharacters()分配结果,只需将指针指定给相应的array[][]字段:

array[i][j]->var = ChainOfCharacters(array[i][j]->size);

要打印.var字段的内容,遍历数组,并为每个struct循环遍历.var分配的存储的内容,打印字符:< / p>

/* print characters */
for (size_t i = 0; i < rows; i++)
{
    for (size_t j = 0; j < columns; j++)
    {
        printf("array[%zu][%zu]->val: ", i, j);
        for (size_t k = 0; k < array[i][j]->size; k++) {
            putchar(array[i][j]->var[k]);
        }
        putchar('\n');
    }
}

完成所有这些后,您需要记住free()已分配的内存。这是一个实现这些变化的完整程序。

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

struct s 
{
    size_t size;
    char *var;
};

char* ChainOfCharacters(size_t liczba);

int main(void)
{
    size_t rows = 3;
    size_t columns = 3;
    struct s *array[rows][columns];

    for (size_t i = 0; i < rows; i++)
    {
        for (size_t j = 0; j < columns; j++)
        {
            array[i][j] = malloc(sizeof *array[i][j]);
            printf("Give the size to structure nr. %zu: \n",
                   i * columns + j + 1);

            if (scanf("%zu", &(array[i][j]->size)) != 1) {
                fprintf(stderr, "Incorrect input\n");
                exit(EXIT_FAILURE);
            };
            array[i][j]->var = ChainOfCharacters(array[i][j]->size);
        }
    }

    /* print characters */
    for (size_t i = 0; i < rows; i++)
    {
        for (size_t j = 0; j < columns; j++)
        {
            printf("array[%zu][%zu]->val: ", i, j);
            for (size_t k = 0; k < array[i][j]->size; k++) {
                putchar(array[i][j]->var[k]);
            }
            putchar('\n');
        }
    }

    /* free allocated memory */
    for (size_t i = 0; i < rows; i++)
    {
        for (size_t j = 0; j < columns; j++)
        {
            free(array[i][j]->var);
            free(array[i][j]);
        }
    }

    return 0;
}

char* ChainOfCharacters(size_t liczba)
{
    char *tabc = NULL;
    tabc = malloc(sizeof *tabc * liczba);
    if (tabc == NULL) {
        exit(EXIT_FAILURE);
    } else {
        for (size_t i = 0; i < liczba; i++) {
            tabc[i] = rand() % ('z' - 'a') +'a';
        }
        return tabc;
    }
}

示例互动:

Give the size to structure nr. 1: 
1  
Give the size to structure nr. 2: 
2
Give the size to structure nr. 3: 
3
Give the size to structure nr. 4: 
9
Give the size to structure nr. 5: 
8
Give the size to structure nr. 6: 
7
Give the size to structure nr. 7: 
4
Give the size to structure nr. 8: 
5
Give the size to structure nr. 9: 
6
array[0][0]->val: i
array[0][1]->val: lc
array[0][2]->val: psk
array[1][0]->val: lryvmcpjn
array[1][1]->val: bpbwllsr
array[1][2]->val: ehfmxrk
array[2][0]->val: ecwi
array[2][1]->val: trsgl
array[2][2]->val: rexvtj

选择正确的类型

正如我在答案开头所说,size_t是数组索引的正确类型,因为它是unsigned类型,保证能够保存任何数组索引值。但是,unsigned也没问题,但unsigned intsize_t可能没有相同的范围。

OP代码中的一个重要问题是.size字段是unsigned,而在此字段中存储输入的scanf()语句使用d转换说明符,这意味着与int一起使用。根据标准,不匹配的转换说明符和参数会导致未定义的行为,包括在某些情况下似乎可以工作。但是你不能依赖未定义的行为去做你期望的事情。在发布的代码中,%u应该用于在unsigned字段中存储.size值。此外,声明ChainOfCharacters()函数接受int类型的参数,但使用unsigned参数(来自.size)调用。这也可能导致实现定义的行为,因为unsigned中的int值可能无法表示。

可能出现此问题的另一个地方是在打印字符的循环中。例如,考虑:

struct s 
{
    unsigned size;
    char *var;
};

/* ... */

int rows = 3;
int columns = 3;
struct s *array[rows][columns];

/* ... */

/* print characters */
for (int i = 0; i < rows; i++)
{
    for (int j = 0; j < columns; j++)
    {
        printf("array[%d][%d]->val: ", i, j);
        for (int k = 0; k < array[i][j]->size; k++) {
            putchar(array[i][j]->var[k]);
        }
        putchar('\n');
    }
}

此处ksigned int,而array[i][j]->sizeunsigned int类型,因此k的值将转换为{{1}在进行比较之前的值。此转换定义明确,但如果unsigned为负数,则会导致意外。

启用编译器警告将有助于在编译时检测此类问题。我总是至少使用k(和gcc -Wall -Wextra,但你可能没有这个)。启用编译器警告,并注意它们并修复它们。

答案 1 :(得分:0)

ChainOfCharacters()函数中,您应该返回tab,而不是tabctab指向链的开头,tabc指向它的结尾。