gpt4 book ai didi

c - 如何正确地将数组指针传递给 C 中的函数

转载 作者:太空宇宙 更新时间:2023-11-04 04:37:00 25 4
gpt4 key购买 nike

关于这个程序可能有人问过不同的问题,但是在这个 C 代码中我有三个函数:一个打印记录,一个添加记录,一个删除记录。

我不明白的是为什么(添加)和(删除)不在主函数中进行更改,所以当我使用打印所有记录它打印更改的功能,但不显示更改,有什么问题吗?

详细信息在评论中,请随时运行代码以可视化问题。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*The program is to store student record (firstname,lastname and score), it should not be more
than 15 records and the names should not be more than 20 chars, array pointersnare being used
instead of arrays, the (add_record) and (delete_record) functions must
do thsi change in the main function, so when you print all records, the changes are shown*/

void print_records(char **firstname,char **lastname,float *score,int *the_size)
{
int i;
printf("Printing All record(s)...\n");

for (i=0;i<*the_size;i++) /*loop to print records of all arrays in correct format*/
{
printf("Firstname : %s, Lastname : %s, Score : %f\n",firstname[i],lastname[i],score[i]);

}
}
void add_new_record (char **firstname,char **lastname,float *score,int the_size)
{
printf("Add new record in the format :\nFirstname Lastname Score\n");
/*the strategy here is to check if all 15 elemts are used, if they are, use realloc
to add one more, if not add the record after the last record*/
if (the_size == 15)
{
firstname=realloc(firstname,16*sizeof(char*));
firstname[15]=malloc((20+1)*sizeof(char));
lastname=realloc(lastname,16*sizeof(char*));
lastname[15]=malloc((20+1)*sizeof(char));
score=realloc(score,16*sizeof(float));
scanf("%s %s %f",firstname[15],lastname[15],&score[15]);
printf("New Record Added Successfully !\n");
printf("Firstname : %s, Lastname : %s, Score : %f\n",firstname[15],lastname[15],score[15]);
}
else if (the_size<15)
{
scanf("%s %s %f",firstname[the_size],lastname[the_size],&score[the_size]);
printf("New Record Added Successfully !\n");
printf("Firstname : %s, Lastname : %s, Score : %f\n",firstname[the_size],lastname[the_size],score[the_size]);
}
}
void delete_record (char **firstname,char **lastname,float *score,int the_size)
{
char *str=malloc(20*sizeof(char)); /*String entered by user must be 20 or less chars*/
int i,ctr=0;
char *temp_first=malloc(20*sizeof(char));/*temp array to swap firstname must be 20 or less chars*/
char *temp_last=malloc(20*sizeof(char)); /*temp array to swap lastname must be 20 or less chars*/
float temp_score;/*ctr is the counter used to check if there are no matchs in the end*/
printf("Enter the lastname of record(s) to delete : ");
scanf("%s",str);
/* the strategy here is to move the element to be deleted to the last index and use
relloc to shrink the size by 1 (-1) */
for (i=0;i< the_size;i++)
{
if (strcmp(str,lastname[i])==0)
{
printf("Deleting Record for %s %s...\n",firstname[i],lastname[i]);
temp_score=score[i];
score[i]=score[the_size-1];
score[the_size-1]=temp_score;
strcpy(temp_first, firstname[i]); /*using strcpy function to swap strings*/
strcpy(firstname[i], firstname[the_size-1]);
strcpy(firstname[the_size-1], temp_first);
strcpy(temp_last, lastname[i]);
strcpy(lastname[i], lastname[the_size-1]);
strcpy(lastname[the_size-1], temp_last);
score=realloc(score,(the_size-1)*sizeof(float));
firstname=realloc(firstname,(the_size-1)*sizeof(char*));
lastname=realloc(lastname,(the_size-1)*sizeof(char*));
ctr++;
the_size--;


}

}
if (!ctr) /*if ctr=0 (no increment), then print,there is no match*/
{
printf ("Sorry, no available record for %s",str);
}
free(temp_first);
free(temp_last);
free(str);
}
void main()
{
char **firstname;
char **lastname;
float *score;
int number_of_records,i,j=-1,ctr=1,row=15,col=20;
/*ctr is to keep track of the student's number (makes it easier to
the user), it starts with (1)*/

firstname=malloc(row*sizeof(char*));
for(i=0;i<row;i++)
{
firstname[i]=malloc((col+1)*sizeof(char));
}
lastname=malloc(row*sizeof(char*));
for(i=0;i<row;i++)
{
lastname[i]=malloc((col+1)*sizeof(char));
}
printf("\nPlease indicate number of records you want to enter (min 2, max 15): ");
scanf("%d",&number_of_records);
score=malloc(row*sizeof(float));

printf("\nPlease input records of students\n(enter a new line after"
"each record), with following format:\nfirst name last name score ");
for (i=0;i<number_of_records;i++)
{
printf("\nEnter record for student %d : ",ctr);
scanf("%s %s %f",firstname[i],lastname[i],&score[i]);

ctr++; /*ctr is to keep track of student number
(makes it easy to the user) */

}


while (j!=0) /*Main menu will keep looping after using a function as long as j is not 0
When the user enters 0 (zero) the loop will stop and therefore the program will terminate*/
{
printf("\nSelect desired function by pressing the corresponding key number\n");

printf("\n********** Main Menu **********\n");

printf("\n>>> Print records (press 1)\n");

printf("\n>>> Add a new Record (press 2 )\n");

printf("\n>>> delete record (press 3)\n");


printf("\n>>> Exit the program (press 0)\n");

scanf("%d",&j); /*getting j from the user (j is used for selection and for the while loop)*/
if (j==1)
{
print_records(firstname,lastname,score,&number_of_records);
}
else if (j==2)
{
add_new_record(firstname,lastname,score,number_of_records);
}
else if (j==3)
{
delete_record(firstname,lastname,score,number_of_records);
}
else if (j==0)
{
printf("Exitting program ...\n");
}
}
}

最佳答案

正如其他答案所观察到的,在 C 中,所有参数都是按值传递的。这意味着该函数获取调用者值的副本,因此对该值的更改对调用者不可见。换句话说,给定

void f(any_type arg) {
arg = any_value;
}

无论any_type 是什么类型或any_value 是什么值,调用者永远不会检测到任何变化。但是,请仔细注意那个和这个之间的区别:

void f(any_type *arg) {
*arg = any_value;
}

在那种情况下,被修改的不是函数参数(指针),而是指向的东西。参数是调用者值的副本,因此两者指向同一事物。调用者无法检测到参数的变化,但在调用之后,它可以检测到它所指向的事物的变化。

您的代码出现了一些此类问题,其中一些问题导致了您的主要问题。最重要的是,这些与您对列表中元素数量的记录有关(main() 中的变量 number_of_records)。您的添加和删除功能或多或少可以正常工作,除了它们无法将修改后的列表大小传回 main。

当已经有 15 条记录时,add_new_record() 中还有其他问题;如果可以的话,我会拒绝这种情况。如果你必须支持它,那么你有很多事情需要清理。其中一些与按值传递问题有关,另一些与您的代码在列表最初包含 16 或更多记录时应该执行的操作有关。

更新:由于您在解决这个问题时遇到了很多麻烦,这里是 delete_record() 的修订版本。它实现的不仅仅是删除记录时获得所需输出所需的最小更改,因为实际上还有很多其他问题,只要我遇到麻烦,我也可以提出来。查看新评论和修改后的评论。

/*
* Can realloc() *firstname, *lastname, and *score and return the updated
* values to the caller. Most importantly, can update *the_size and have
* the caller see the result.
*/
void delete_record (char ***firstname, char ***lastname, float **score, int *the_size)
{
int i;
int initial_size = *the_size;
char str[21]; /* no need to malloc a fixed-length local array */

printf("Enter the lastname of record(s) to delete : ");
fflush(stdout); /* The prompt might not appear if you don't flush */
/*
* Note the field width in the format below. Without it, a user can
* easily cause a buffer overflow.
*/
scanf("%20s", str);

/*
* The strategy for each element to delete (there may be more than one)
* is to free the element's name components (else their allocated memory
* leaks), copy the last (at that time) element's components into
* place (for the name components, just the pointers), and later
* realloc to shrink the overall size to exactly fit the remaining
* elements (once we know how many that is).
*/
for (i = 0; i < *the_size; )
{
if (strcmp(str, (*lastname)[i]) == 0)
{
printf("Deleting Record for %s %s...\n", (*firstname)[i], (*lastname)[i]);
free((*firstname)[i]);
free((*lastname)[i]);
(*firstname)[i] = (*firstname)[*the_size - 1];
(*lastname)[i] = (*lastname)[*the_size - 1];
(*score)[i] = (*score)[*the_size - 1];
*the_size -= 1; /* not the same as *the_size-- */
/* don't increment i, else we miss testing the new i'th element */
} else {
i += 1;
}
}
if (*the_size != initial_size)
{
void *temp;

/*
* Always check the return value of realloc(), even when you're
* shrinking the allocation. Usually, though, you'd want at least
* some kind of diagnostic in the event of failure.
*/
temp = realloc(*firstname, sizeof(char *) * (*the_size));
if (temp)
{
*firstname = temp;
}
temp = realloc(*lastname, sizeof(char *) * (*the_size));
if (temp)
{
*lastname = temp;
}
temp = realloc(*score, sizeof(float) * (*the_size));
if (temp)
{
*score = temp;
}
}
else /* there is no match */
{
printf ("Sorry, no available record for %s",str);
}
}

您的 main() 会这样调用:

delete_record(&firstname, &lastname, &score, &number_of_records);

需要对 add_record() 进行类似的更改,尽管您确实遇到了我已经指出的单独问题,即条目数增加到 16 以上。

此外,您通过使用单独的名字、姓氏和分数数组为自己做额外的工作。定义一个包含所有这三个结构的 struct 并只使用一个其元素是该 struct 实例的动态数组会容易得多。

关于c - 如何正确地将数组指针传递给 C 中的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29834822/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com