简体   繁体   English

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

[英]Connecting array to a structure by a pointer C

I have a structure: 我有一个结构:

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

And an array of pointers to structures 以及指向结构的指针数组

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));
    }
}   

and a function which returns a pointer to an array of random characters with a size chosen by user: 以及一个返回指向随机字符数组的指针的函数,该数组的大小由用户选择:

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;    
    }
}

How to connect an array of characters which is a result of this function to pointer char *var of the structure s by using an array of pointers to structures? 如何通过使用指向结构的指针数组将作为此函数结果的字符数组连接到structure s的指针char *var Is there any mistake in my code? 我的代码有什么错误吗?

I tried this: array[i][j]->var=ChainOfCharacters(array[i][j]->size); 我试过了: array[i][j]->var=ChainOfCharacters(array[i][j]->size); but it seems to be wrong because i have wrong characters while trying to check this by printf. 但这似乎是错误的,因为在尝试通过printf检查此字符时我输入了错误的字符。 I don't even know how to write the array of characters on the screen by printf. 我什至不知道如何通过printf在屏幕上写入字符数组。 I tried this printf("%c ", *(array[i][j]->var)); 我尝试了这个printf("%c ", *(array[i][j]->var)); but it shows totaly random signs. 但显示完全随机的迹象。 I will be very thankful for answers for my questions :) 我将非常感谢您对我的问题的回答:)

First, let's straighten out a few issues with the posted code. 首先,让我们理顺所发布代码的一些问题。 size_t is the correct type for array indices and sizes, so the .size member of the s structure should have type size_t . size_t是数组索引和大小的正确类型,因此s结构的.size成员应具有size_t类型。 This also means that the ChainOfCharacters() function should take an argument of type size_t , and this has ramifications for the format string specifiers in the calls to printf() and scanf() . 这也意味着ChainOfCharacters()函数应采用size_t类型的参数,这对printf()scanf()的调用中的格式字符串说明符有影响。

A user may not enter a number at the input prompt, in which case no assignment would be made; 用户可能不会在输入提示下输入数字,在这种情况下,将不会进行分配。 but since the posted code does not check the value returned from scanf() to verify that a correct input was made, the code would continue with an indeterminate value in that .size field, leading to undefined behavior. 但是由于发布的代码没有检查从scanf()返回的值来验证是否进行了正确的输入,因此代码将在该.size字段中继续使用不确定的值,从而导致未定义的行为。 The code below checks for this, and exits with an error message if the user fails to input a number here, though this input validation could be further improved. 下面的代码对此进行了检查,如果用户未能在此处输入数字,则退出并显示一条错误消息,尽管可以进一步改进此输入验证。

Note that it is better to use the EXIT_FAILURE macro than to use -1 , as this is clearer and more portable. 请注意,使用EXIT_FAILURE宏比使用-1更好,因为它更清晰,更可移植。

The ChainOfCharacters() function does not return a string, but only a pointer to an array of characters, so the characters will need to be printed one-by-one. ChainOfCharacters()函数不会返回字符串,而只会返回指向字符数组的指针,因此,这些字符需要一张一张地打印出来。

Note that there is no need to cast the result of malloc() in C, and it is better to use identifers rather than explicit types for operands of the sizeof operator: this is less error-prone and easier to maintain when types change. 请注意,无需在C中malloc()的结果,最好将identifers而不是显式类型用于sizeof运算符的操作数:这更容易出错,并且在类型更改时更易于维护。

The loop that assigns characters in the ChainOfCharacters() function is needlessly complex and contains an error, possibly as a result of this complexity; ChainOfCharacters()函数中分配字符的循环不必要地复杂,并且可能由于这种复杂性而包含错误。 the tabc pointer points to one past the end of the allocated storage when it is returned. 当返回时, tabc指针指向已分配存储区末尾的1。 This can be resolved by rewriting the loop to use an index instead of pointer arithmetic. 这可以通过重写循环以使用索引而不是指针算术来解决。 It is generally clearer and less error-prone to use array indexing instead of pointer arithmetic when possible. 通常,在可能的情况下使用数组索引而不是指针算术更清晰,更不易出错。 Avoid using magic numbers: rand() % ('z' - 'a') + 'a' is much clearer in intent than rand()%(122-97)+97 (and don't be afraid to use a little whitespace). 避免使用幻数: rand() % ('z' - 'a') + 'a'意图要比rand()%(122-97)+97清晰得多(不要害怕使用一点空格)。 Further, note that the C Standard makes few restrictions on the character encodings that may be used by an implementation, and in particular this is not required to be ASCII. 此外,请注意,C标准对实现可能使用的字符编码进行了很少的限制,尤其是不需要将其限制为ASCII。 The letters of the Latin alphabet need not even be encoded in a contiguous sequence, as is the case with EBCDIC (which still exists in the real world). 甚至不需要像EBCDIC (仍然存在于现实世界中)那样以连续的顺序对拉丁字母进行编码。 This is unlikely to be a problem here, but know that there are portable ways to handle this issue. 在这里这不太可能成为问题,但是知道有一些可移植的方法来处理此问题。

To assign the result from ChainOfCharacters() , simply assign the pointer to the appropriate array[][] field: 要分配ChainOfCharacters()的结果,只需将指针分配给适当的array[][]字段即可:

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

To print the contents of the .var fields, iterate over the array, and for each struct , loop over the contents of the allocated storage for .var , printing the characters: 要打印的内容.var字段,迭代在阵列上,并且对于每个struct ,在循环对所分配的存储的内容.var ,打印字符:

/* 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');
    }
}

After all of this, you will need remember to free() the allocated memory. 完成所有这些操作后,您将需要记住free()分配的内存。 Here is a complete program that implements these changes. 这是实现这些更改的完整程序。

#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;
    }
}

Sample interaction: 样本互动:

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

On choosing correct types 选择正确的类型

As I said at the beginning of the answer, size_t is the correct type for array indices, as it is an unsigned type that is guaranteed to be able to hold any array index value. 正如我在答案开头所说的那样, size_t是数组索引的正确类型,因为它是unsigned类型,可以保证能够保存任何数组索引值。 But, unsigned is also fine, though unsigned int and size_t may not have the same ranges. 但是, unsigned也可以,尽管unsigned intsize_t可能没有相同的范围。

A significant problem in the OP code is that the .size field is unsigned , while the scanf() statement that stores input in this field uses the d conversion specifier, which is meant to be used with int s. OP代码中的一个重要问题是.size字段是unsigned ,而在此字段中存储输入的scanf()语句使用d转换说明符,该说明符应与int s一起使用。 According to the Standard, mismatched conversion specifiers and arguments lead to undefined behavior, which includes appearing to work in some instances. 根据该标准,不匹配的转换说明符和参数会导致未定义的行为,包括在某些情况下似乎起作用。 But you can't rely on undefined behavior doing what you expect. 但是您不能依靠未定义的行为来完成您的期望。 In the posted code, %u should have been used to store an unsigned value in the .size field. 在发布的代码中,应该使用%u.size字段中存储unsigned值。 Further, the ChainOfCharacters() function was declared to accept an argument of type int , but was called with an unsigned argument (from .size ). 此外, ChainOfCharacters()函数被声明为接受int类型的参数,但使用unsigned参数(来自.size )调用。 This may also lead to implementation-defined behavior, since an unsigned value may not be representable in an int . 这也可能导致实现定义的行为,因为在int unsigned值可能无法表示。

Another place that this problem could arise is in the loop that prints the characters. 可能出现此问题的另一个地方是在打印字符的循环中。 For example, consider: 例如,考虑:

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');
    }
}

Here, k is a signed int , while array[i][j]->size is an unsigned int type, so the value of k will be converted to an unsigned value before the comparison is made. 这里, k是有signed int ,而array[i][j]->sizeunsigned int类型,因此在进行比较之前, k的值将转换为unsigned值。 This conversion is well-defined, but can lead to surprises if k is negative. 此转换定义明确,但如果k为负数,可能会导致意外。

Enabling compiler warnings will help to detect issues like this at compile time. 启用编译器警告将有助于在编译时检测到此类问题。 I always use at least gcc -Wall -Wextra (and -Wpedantic too, but you can probably do without this). 我总是至少使用gcc -Wall -Wextra (也使用-Wpedantic ,但是您可以不用它)。 Enable compiler warnings, and pay attention to them, and fix them. 启用编译器警告,并注意并修复它们。

In your ChainOfCharacters() function, you should be returning tab , not tabc . ChainOfCharacters()函数中,您应该返回tab ,而不是tabc tab is pointing to the beginning of your chain, tabc is pointing to the end of it. tab指向链的开头, tabc指向链的结尾。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM