[英]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.