我尝试采用某个字符串,将字符串设置为特定大小,50 个字符,然后在输入所有字符串后,它将对它们进行排序,然后将大小从 50 个字符重新分配到用户编写的字符串长度,如果一开始我给了它 50 个字节,有人输入"hi",它将更改为所需的字节数。
#include <stdio.h>
#define MAX_CHARS 50
int main(void)
{
int i = 0, j = 0;
char* temp = 0;
char** names = 0;
int amount = 0;
// Getting number of friends from user
printf("Enter number of friends: ");
scanf("%d", &amount);
getchar();
// Allocating space for the names.
temp = (char*)malloc(MAX_CHARS * sizeof(char));
names = (char*)malloc(amount * sizeof(char));
for (i = 0; i < amount; i++)
{
names[i] = (char*)malloc((MAX_CHARS + 1) * sizeof(char));
}
// Getting the names from the user
for (i = 0; i < amount; i++)
{
printf("Enter name of friend %d: ", i + 1);
fgets(names[i], MAX_CHARS - 1, stdin);
}
for (i = 0; i < amount; i++)
{
for (j = i + 1; j < amount; j++)
{
if (strcmp(names[j], names[i]) < 0)
{
strcpy(temp, names[j]);
strcpy(names[j], names[i]);
strcpy(names[i], temp);
}
}
// Reallocating the 50 bytes space to only the space needed.
printf("%d", strlen(names[i]));
(*names)[i] = (char*)realloc((*names)[i], strlen(names[i]) * sizeof(char));
}
for (i = 0; i < amount; i++)
{
printf("%s", names[i]);
}
free(names);
getchar();
return 0;
}
名称是指向字符的指针数组,因此在
names = (char*)malloc(amount * sizeof(char));
您没有分配足够的内容,以后当您将其分配出去时,行为将未定义
做(演员表没用)
names = malloc(amount * sizeof(char*));
行为
(*names)[i] = (char*)realloc((*names)[i], strlen(names[i]) * sizeof(char));
无效,因为(*names)[i]
是字符,也不要忘记 null 字符结束字符串的位置,所以你需要:
names[i] = realloc(names[i], strlen(names[i]) + 1);
请注意,根据定义,sizeof(char)
是 1
如果不检查malloc
的结果,realloc
您假设/希望有足够的内存,但这可能是错误的,在这种情况下,这些函数返回 NULL,检查这种情况更安全。这意味着realloc
首先保存在辅助char*
中,以免丢失当前值names[i]
如果返回 NULL 可以继续使用realloc
待办事项
scanf("%d", &amount);
是危险的,当输入无效时,您不知道,并且在使用它时不会使用未定义的行为初始化金额,例如
if (scanf("%d", &amount) != 1)
{
puts("invalid value");
return -1;
}
考虑你如何使用names[i]
当你这样做时
names[i] = (char*)malloc((MAX_CHARS + 1) * sizeof(char));
分配的 1 个字节过多,您可以
names[i] = malloc(MAX_CHARS);
警告做:
fgets(names[i], MAX_CHARS - 1, stdin);
输入结尾的可能换行符保存在names[i]
中,您可能需要将其删除。在这种情况下,您必须在打印名称时进行调整,以便在名称、空格或换行符之间引入分隔符。
另一种阅读但不获取换行符的方法是:
scanf(" 49%[^n]", names[i]);
49 允许限制数组中写入的字符数(我删除了 1 以留出空字符的空间),并且前面的空格允许绕过输入开头的空格(这里的空格表示 ' ',但也表示制表符、换行符等)。使用这种方式,名称可以包含空格,而格式"%49s"
则不是这种情况。
无论如何,无论您使用什么,您都需要检查输入是否完成,否则您不会设置数组,并且稍后使用它时,行为将是未定义的。
当您对数组进行排序时,您会执行以下操作:
strcpy(temp, names[j]); strcpy(names[j], names[i]); strcpy(names[i], temp);
但你不需要深复制,只需交换指针它:
char * aux = names[j];
names[j] = names[i];
names[i] = aux;
最后,您希望释放资源,但您只释放free(names);
,因此您不释放其他数组
如何使用 realloc 缩短字符串数组大小
分配错误
// v----------v s/b the size of a pointer
// names = (char*)malloc(amount * sizeof(char));
names = malloc(sizeof *names * amount);
// ^-----------^ Much easier to code right
偏差 1(或 2)错误
// fgets(names[i], MAX_CHARS - 1, stdin);
fgets(names[i], MAX_CHARS + 1, stdin);
// realloc((*names)[i], strlen(names[i]) * sizeof(char));
realloc((*names)[i], (strlen(names[i]) + 1)* sizeof(char));
在输入中保留
fgets(names[i], MAX_CHARS - 1, stdin);
// add
names[i][strcspn(names[i], "n")] = ' '; // to lop off potential n
具有不匹配的 printf 说明符的潜在 UB。
// printf("%d", strlen(names[i]));
printf("%zu", strlen(names[i]));
未能释放分配
// add before `free(names);`
for (i=0; i<amount; i++) free(names[i]);
排序效率低下
当只有指向名称的指针需要交换时,代码会交换名称。 还要考虑qsort()
建议的中间代码,省略了排序详细信息。 建议在所有输入的名称后进行排序。
// Allocating space for the names.
// No need to allocate, a simple array will do.
// Let us double it size to help detect and consume long-ish names
char temp[MAX_CHARS * 2];
names = malloc(sizeof *names * amount);
if (names == NULL) Handle_OutOfMemory();
// Getting the names from the user
for (i = 0; i < amount; i++) {
printf("Enter name of friend %d: ", i + 1);
if (fgets(temp, sizeof temp, stdin)) {
Handle_Unexpected_Eary_EOF();
}
temp[strcspn(temp, "n")] = ' '; // lop off potential n
size_t len = strlen(temp);
if (len > MAX_CHARS) Handle_LongLine();
names[i] = malloc(len + 1); // only allocated what is needed
if (names[i] == NULL) Handle_OutOfMemory();
strcpy(name[i], temp);
}
for (i = 0; i < amount; i++) {
printf("<%s>n", names[i]);
}
// Sort by your own code or take time to learn `qsort()`
qsort(names, amount, sizeof names[0], TBD_compare_function);
for (i = 0; i < amount; i++) {
printf("<%s>n", names[i]);
free(names[i]);
}
free(names);
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#define SIZE 50
#define NEWSIZE 25
int main(void)
{
char *str = malloc(SIZE);
/* now there are 25 bytes
* allocated for str, unless
* an error occurs
*/
void *tmp = realloc(str, NEWSIZE);
if (!tmp) {
perror("ERROR");
exit(EXIT_FAILURE);
}
str = tmp;
exit(EXIT_SUCCESS);
}