[英]Connecting array to a structure by a pointer C
我有一个结构:
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;
}
}
如何通过使用指向结构的指针数组将作为此函数结果的字符数组连接到structure s
的指针char *var
? 我的代码有什么错误吗?
我试过了: array[i][j]->var=ChainOfCharacters(array[i][j]->size);
但这似乎是错误的,因为在尝试通过printf检查此字符时我输入了错误的字符。 我什至不知道如何通过printf在屏幕上写入字符数组。 我尝试了这个printf("%c ", *(array[i][j]->var));
但显示完全随机的迹象。 我将非常感谢您对我的问题的回答:)
首先,让我们理顺所发布代码的一些问题。 size_t
是数组索引和大小的正确类型,因此s
结构的.size
成员应具有size_t
类型。 这也意味着ChainOfCharacters()
函数应采用size_t
类型的参数,这对printf()
和scanf()
的调用中的格式字符串说明符有影响。
用户可能不会在输入提示下输入数字,在这种情况下,将不会进行分配。 但是由于发布的代码没有检查从scanf()
返回的值来验证是否进行了正确的输入,因此代码将在该.size
字段中继续使用不确定的值,从而导致未定义的行为。 下面的代码对此进行了检查,如果用户未能在此处输入数字,则退出并显示一条错误消息,尽管可以进一步改进此输入验证。
请注意,使用EXIT_FAILURE
宏比使用-1
更好,因为它更清晰,更可移植。
ChainOfCharacters()
函数不会返回字符串,而只会返回指向字符数组的指针,因此,这些字符需要一张一张地打印出来。
请注意,无需在C中malloc()
的结果,最好将identifers而不是显式类型用于sizeof
运算符的操作数:这更容易出错,并且在类型更改时更易于维护。
在ChainOfCharacters()
函数中分配字符的循环不必要地复杂,并且可能由于这种复杂性而包含错误。 当返回时, tabc
指针指向已分配存储区末尾的1。 这可以通过重写循环以使用索引而不是指针算术来解决。 通常,在可能的情况下使用数组索引而不是指针算术更清晰,更不易出错。 避免使用幻数: 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
,打印字符:
/* 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 int
和size_t
可能没有相同的范围。
OP代码中的一个重要问题是.size
字段是unsigned
,而在此字段中存储输入的scanf()
语句使用d
转换说明符,该说明符应与int
s一起使用。 根据该标准,不匹配的转换说明符和参数会导致未定义的行为,包括在某些情况下似乎起作用。 但是您不能依靠未定义的行为来完成您的期望。 在发布的代码中,应该使用%u
在.size
字段中存储unsigned
值。 此外, ChainOfCharacters()
函数被声明为接受int
类型的参数,但使用unsigned
参数(来自.size
)调用。 这也可能导致实现定义的行为,因为在int
unsigned
值可能无法表示。
可能出现此问题的另一个地方是在打印字符的循环中。 例如,考虑:
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');
}
}
这里, k
是有signed int
,而array[i][j]->size
是unsigned int
类型,因此在进行比较之前, k
的值将转换为unsigned
值。 此转换定义明确,但如果k
为负数,可能会导致意外。
启用编译器警告将有助于在编译时检测到此类问题。 我总是至少使用gcc -Wall -Wextra
(也使用-Wpedantic
,但是您可以不用它)。 启用编译器警告,并注意并修复它们。
在ChainOfCharacters()
函数中,您应该返回tab
,而不是tabc
。 tab
指向链的开头, tabc
指向链的结尾。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.