如何使用 realloc 来缩短字符串数组的大小
How to use realloc to shorten a string array size
我尝试获取某个字符串,将字符串设置为特定大小,即 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的指针数组,所以in
names = (char*)malloc(amount * sizeof(char));
你分配的不够多,以后你分配出去的时候行为会不确定
做(演员没用)
names = malloc(amount * sizeof(char*));
正在做
(*names)[i] = (char*)realloc((*names)[i], strlen(names[i]) * sizeof(char));
是无效的,因为 (*names)[i]
是一个字符,不要忘记结束字符串的空字符的位置,所以你想要:
names[i] = realloc(names[i], strlen(names[i]) + 1);
请注意,根据定义 sizeof(char)
是 1
不检查 malloc
和 realloc
的结果你 suppose/hope 有足够的内存,但这可能是错误的,在那种情况下这些函数 returns NULL,检查这种情况更安全。这意味着 realloc
首先保存在辅助 char*
中不丢失 names[i]
的当前值你可以继续使用 if realloc
returns NULL
要做
scanf("%d", &amount);
是危险的,当输入无效时你不知道并且 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]
中,您可能需要将其删除。在这种情况下,您必须在打印名称时进行调整以在名称之间引入分隔符,space 或换行符。
另一种阅读但没有换行的方法是:
scanf(" 49%[^\n]", names[i]);
49 允许限制写入数组的字符数(我删除了 1 让 space 用于空字符),而之前的 spaces 允许绕过 spaces 在输入的开头(这里 spaces 表示 ' ',但也表示制表符、换行符等)。使用这种方式,名称可以包含 spaces,而格式 "%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);
所以你没有释放其他数组
#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);
}
How to use realloc to shorten a string array size
分配错误
// 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));
在输入中留下\n
fgets(names[i], MAX_CHARS - 1, stdin);
// add
names[i][strcspn(names[i], "\n")] = '[=12=]'; // 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")] = '[=15=]'; // 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);
我尝试获取某个字符串,将字符串设置为特定大小,即 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的指针数组,所以in
names = (char*)malloc(amount * sizeof(char));
你分配的不够多,以后你分配出去的时候行为会不确定
做(演员没用)
names = malloc(amount * sizeof(char*));
正在做
(*names)[i] = (char*)realloc((*names)[i], strlen(names[i]) * sizeof(char));
是无效的,因为 (*names)[i]
是一个字符,不要忘记结束字符串的空字符的位置,所以你想要:
names[i] = realloc(names[i], strlen(names[i]) + 1);
请注意,根据定义 sizeof(char)
是 1
不检查 malloc
和 realloc
的结果你 suppose/hope 有足够的内存,但这可能是错误的,在那种情况下这些函数 returns NULL,检查这种情况更安全。这意味着 realloc
首先保存在辅助 char*
中不丢失 names[i]
的当前值你可以继续使用 if realloc
returns NULL
要做
scanf("%d", &amount);
是危险的,当输入无效时你不知道并且 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]
中,您可能需要将其删除。在这种情况下,您必须在打印名称时进行调整以在名称之间引入分隔符,space 或换行符。
另一种阅读但没有换行的方法是:
scanf(" 49%[^\n]", names[i]);
49 允许限制写入数组的字符数(我删除了 1 让 space 用于空字符),而之前的 spaces 允许绕过 spaces 在输入的开头(这里 spaces 表示 ' ',但也表示制表符、换行符等)。使用这种方式,名称可以包含 spaces,而格式 "%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);
所以你没有释放其他数组
#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);
}
How to use realloc to shorten a string array size
分配错误
// 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));
在输入中留下\n
fgets(names[i], MAX_CHARS - 1, stdin);
// add
names[i][strcspn(names[i], "\n")] = '[=12=]'; // 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")] = '[=15=]'; // 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);