printCat1(Cat* cat) Vs. printCat2(Cat cat) & More Pointers' Questions - arrays

The following questions might have been asked already. In addition, I am aware of the fact that there are a lot of posts that discuss the topic. However, after searching, I couldn't find answers to those specific questions.
Note: the questions appear below the code.
The code:
#include <stdio.h>
#define ARRAY_SIZE 3
typedef struct
{
const char* name;
const char* color;
int age;
}Cat;
void printCat1(Cat* cat)
{
printf("\n%s\n", cat->name);
printf("%s\n", cat->color);
printf("%d\n", cat->age);
printf("\n");
}
void printCat2(Cat cat)
{
printf("\n%s\n", cat.name);
printf("%s\n", cat.color);
printf("%d\n", cat.age);
printf("\n");
}
void printCatArray(Cat catArr[])
{
int i = 0;
for (i = 0; i < ARRAY_SIZE; i++)
{
//WHICH OPTION IS BETTER? (printCat1 OR printCat2)
//CALLING TO PRINTING FUNCTION.
}
}
void swap(_____ cat1, _____ cat2)
{
Cat temp = //cat1 or *cat1 ?
//cat1 = cat2 or *cat1 = *cat2?
cat2 = temp;
}
void sortbyage(Cat catarr[])
{
int i, j;
for (i = 0; i < ARRAY_SIZE - 1; i++)
for (j = 1; j < ARRAY_SIZE; j++)
if (catarr[i].age > catarr[j].age)
swap(______, ______]);
}
int main() {
Cat catArray[ARRAY_SIZE] =
{ {"cat1", "white", 1},
{"cat2", "black", 2},
{"cat3", "gray", 3} };
printCatArray(catArray);
return 0;
}
The questions:
1. What is the difference between both functions that print the data of a single cat structure?
2. Which printing function is better to use and why? it will be essential and meaningful if you would like to explain.
3. What is better to write and why? void swap(Cat cat1, Cat cat2) OR void swap(Cat* cat1, Cat* cat2)
4. Is the calling to swap function from the function soryByAge, swap(&catArr[i], &catArr[j]), correct? Would you write it differently?
5. The following line of code is correct: catArray[2] = catArray[1];
It will be great to get an explanation about what it actually does.
If one or more of the questions are not clear enough, I will be glad to clarify them.
Thank you very much beforehand!

printCat1 uses a pointer, it's more efficient because it doesn't make a temporary duplicate.
printCat2 passes the value, it makes a duplicate of cat, it's less efficient.
swap function has to use pointers. If it doesn't, it will simply swap copied values. The original array will be unchanged.
void swap(Cat *cat1, Cat* cat2)
{
Cat temp = *cat1;
*cat1 = *cat2;
*cat2 = temp;
}
When passing parameter to swap, use the address of the variable. For example,
swap(&arr[i], &arr[j]);
printCat1(&arr[i]);
The structure:
typedef struct
{
const char* name;
const char* color;
int age;
}Cat;
...
Cat catArray[ARRAY_SIZE] =
{ {"cat1", "white", 1},
{"cat2", "black", 2},
{"cat3", "gray", 3} };
You want to declare strings as character arrays.
typedef struct
{ char name[50]; char color[50]; int age; }Cat;
Or declare as pointers and allocated dynamically.

I would not declare cat name and colour as const. If they are defined as const you will not be able to change it runtime, for example to get it from the user or read the file with your database.
foo(cat cats[]) and foo(cat *cats) are exactly the same as arrays are passed as pointers. It is good to pass the size too as in real life you do not know big the array is.
void swap(Cat cat1, Cat cat2) OR void swap(Cat* cat1, Cat* cat2) - the fist one will work on local copies of the structures. It will not affect the original array. So only the second version will do something meangfull.
It is the correct way of doing it. You can also swap structs from the different arrays. You can also add index to the pointer (as in the example below)
It copies the whole structure from the index 1 to the structure at index 2. After that you will have identical elements at indexes 1 and 2
typedef struct
{
char* name;
char* color;
int age;
}Cat;
void printCat1(const Cat* cat)
{
printf("\n%s\n", cat->name);
printf("%s\n", cat->color);
printf("%d\n", cat->age);
printf("\n");
}
void printCat2(Cat cat)
{
printf("\n%s\n", cat.name);
printf("%s\n", cat.color);
printf("%d\n", cat.age);
printf("\n");
}
void printCatArray(const Cat *catArr, size_t size)
{
for (size_t i = 0; i < size; i++)
{
printCat1(catArr + i);
/* or */
printCat2(catArr[i]); // in this case the whole structure will passed to the function
}
}
void swap(Cat *cat1, Cat *cat2)
{
Cat temp = *cat1;
*cat1 = *cat2;
*cat2 = temp;
}
void sortbyage(Cat *catarr, size_t size)
{
size_t i, j;
for (i = 0; i < size - 1; i++)
for (j = 1; j < size; j++)
if (catarr[i].age > catarr[j].age)
swap(catarr + i, catarr + j);
}
int main() {
Cat catArray[] =
{ {"cat1", "white", 1},
{"cat2", "black", 2},
{"cat3", "gray", 3} };
printCatArray(catArray, sizeof(catArray) / sizeof(catArray[0]));
}
https://godbolt.org/z/xodsToqxa

Related

Is it possible to print a structure randomly?

My project is simple. It is just a quiz game with user input. As for the questions and answers I used a file to keep them as a data base.
I also defined a structure:
typedef struct QUESTION
{
char question[MAXCARACTERES];
char answer1[MAXCARACTERES];
char answer2[MAXCARACTERES];
char answer3[MAXCARACTERES];
char answer4[MAXCARACTERES];
} QUESTION;
What I wish to know if there is a possible way to print the answers randomly. Otherwise, the right one stays always in the same place.
Thanks in advance!
I turned William Pursell's comment into an answer. You can't run the code because is missing the answers and some other stuff, but it should work.
typedef struct QUESTION
{
char question[MAXCARACTERES];
char answer[4][MAXCARACTERES];
} QUESTAO;
void randPerm( int *surp );
int main() {
int surprise[4] = {0, 1, 2, 3};
randPerm( surprise );
for(int i = 0; i < 4; i++) {
printf("%s\n", QUESTAO.answer[surprise[i]])
}
return 0;
}
void randPerm( int *surp )
{
for(int i = 4; i > 1; i--) {
int luck = rand() % i;
int hold = surp[luck];
surp[luck] = surp[i-1];
surp[i-1] = hold;
}
}

I cant assign an array to a array inside of my structure

I was doing my Huffman homework and I got stumble on a tiny thing that I cant understand why it happens.
So I created a structure that has an int array a char and an int that holds the size of the array.
struct kodlar{
char karakter;
int* code;
int codesize;
};
typedef struct kodlar kodlar;
kodlar* yenikod(char karakter, int* code,int codesize){
kodlar* yenikod = (kodlar*)malloc(sizeof(kodlar));
if(yenikod){
yenikod->karakter = karakter;
yenikod->code = code;
yenikod->codesize = codesize;
}
return yenikod;
}
Then inside of my main, I created an array that holds these structures:
kodlar* K[taille];
taille is the number of char that it is going to store.
In order to put the characters and codes correspondence, I created the function
printCodes(HuffTree,arr,top,&p,K);
and it works like this:
void printCodes(node* root, int arr[], int top,int* i,kodlar** K)
{
if (root->left) {
arr[top] = 0;
printCodes(root->left, arr, top + 1,i,K);
//printf("%c\n",'l');
}
if (root->right) {
arr[top] = 1;
printCodes(root->right, arr, top + 1,i,K);
//printf("%c\n",'r');
}
if (isLeaf(root)) {
printArr(arr,top);
K[*i]=yenikod((root->lettre),arr,top);
*i = *i + 1;
//printArr(K[*i]->code,K[*i]->codesize);
//printf("%i en son if te i \n",*i );
}
}
But it seems like I cant store arrays inside of my array of kodlar structure. if I commented out the parties //printArr(K[*i]->code,K[*i]->codesize); it gives me a segmentation fault and if I try to print like this:
for (int i = 0; i < taille; ++i){
printf("%c :", K[i]->karakter);
printf(" ");
printArr(K[i]->code,K[i]->codesize);
printf("\n");
}
it gives me codes but only with 1's. I got stuck on this it has been 2 days I would appreciate it if somebody can help me.
struct kodlar{
char karakter;
int codesize;
int code[50];
};
typedef struct kodlar kodlar;
kodlar* yenikod(char karakter, int* code,int codesize){
kodlar* yenikod = (kodlar*)malloc(sizeof(kodlar));
if(yenikod){
yenikod->karakter = karakter;
yenikod->codesize = codesize;
for (int i = 0; i < codesize; ++i)
{
yenikod->code[i] = code[i];
}
}
return yenikod;
}
So thanks to #wcochran I understood that the problem was in my struct but memcpy did not work on my code and I was already giving an array that has been already allocated before entering to yenikod. And I gave a size to my code array in the kodlar struct and my problem was solved.

C- Iterating over an array of structs passed through a void*

I have a function
struct Analysis reduce (int n, void* results)
Where n is the number of files to be analyzed, and I'm passing an array of Analysis structs to results.
The Analysis struct is defined as follows:
struct Analysis {
int ascii[128]; //frequency of ascii characters in the file
int lineLength; //longest line in the file
int lineNum; //line number of longest line
char* filename;
}
I've cast the void * as such,
struct Analysis resArray[n];
struct Analysis* ptr = results;
resArray[0] = ptr[0];
but I can't figure out how to iterate through the resArray properly. I've tried
for (i = 0; i < n; i++){
printf("lineLength: %d\n", resArray[i].lineLength);
}
with n = 3, and I'm getting garbage values. resArray[0] is correct, but resArray[1] is an insanely high number and resArray[2] is just 0. Why wouldn't resArray[1] or resArray[2] give the correct values? If I was incrementing the address incorrectly then it would make sense but I'm just accessing the array at a certain index. Pretty lost here!
resArray[0] is correct because there is "something":
resArray[0] = ptr[0];
Other elements are garbage because you didn't set there any values. If you want to copy entire array you need to change copying method to:
for (i = 0; i < n; i++)
{
resArray[i] = ptr[i];
}
You can't assign a pointer to an array directly because they are different typessince array[n] is type struct analysis(*)[n] and ptr is type struct analysis(*). Check here for more info.
Hopefully this code will help you.
#include <stdio.h>
#define d 3
struct Analysis {
int ascii[128];
int lineLength;
int lineNum;
char *filename;
};
struct Analysis Analyses[d];
struct Analysis reduce(int n, void *results) {
struct Analysis resArray[n];
struct Analysis *ptr = results;
for (int i = 0; i < n; i++) {
resArray[i] = ptr[i];
}
for (int i = 0; i < n; i++) {
printf("lineLength: %d\n", ptr[i].lineLength);
}
return *ptr;
}
int main(void) {
struct Analysis a = {{5}, 2, 2, "George"};
struct Analysis b = {{6}, 3, 3, "Peter"};
struct Analysis c = {{7}, 4, 4, "Jane"};
Analyses[0] = a;
Analyses[1] = b;
Analyses[2] = c;
reduce(d, &Analyses);
return 0;
}
You can try it online.

Trying to sort highest grade to lowest with entire struct

I made a typdef struct of students it features: student ID , ClassId, currentGrade , and lettergrade.
Now I want to sort highest to lowest grade. I already done that but the other parts of struct are not sorted with it. How do I go about making the struct stay together with the sorting?
#include <stdio.h>
#include <stdlib.h>
typedef struct {
short id;
short enrolledClassID;
float currentGrade;
char letterGrade;
} Student;
void printStudentInfo(Student student);
void printStudentArray(Student* student,int sizeOfArray);
void sortByGrade(Student* student,int sizeOfArray);
int main()
{
Student studentArray[5] = {
{25,278,95,'A'},
{ 27,278,56,'F' },
{ 29,321,74,'C' },
{ 31,321,63,'D' },
{ 15,278,81,'B' }
};
Student* pStudents = &studentArray;
printStudentArray(pStudents,5);
sortByGrade(pStudents, 5);
printStudentArray(pStudents, 5);
//studentArray[0].currentGrade;
system("Pause");
}
void sortByGrade(Student* student, int sizeOfArray) {
int min, i;
Student temp;
while (sizeOfArray > 0)
{
min = 0;
for (i = 1; i < sizeOfArray; i++)
if (student[i].currentGrade < student[min].currentGrade)
min = i;
temp.currentGrade = student[sizeOfArray - 1].currentGrade;
student[sizeOfArray - 1].currentGrade = student[min].currentGrade;
student[min].currentGrade = temp.currentGrade;
sizeOfArray--;
}
}
void printStudentInfo(Student student) {
printf("The student ID is %i, class ID is %i, current grade in class is %0.2f\n, and letter grade is %c\n", student.id, student.enrolledClassID,student.currentGrade,student.letterGrade);
}
void printStudentArray(Student* student,int sizeOfArray) {
for (int i = 0; i < sizeOfArray; i++) {
printStudentInfo(student[i]);
}
}
You're only moving around the current grade, not the entire structure. So instead of this:
temp.currentGrade = student[sizeOfArray - 1].currentGrade;
student[sizeOfArray - 1].currentGrade = student[min].currentGrade;
student[min].currentGrade = temp.currentGrade;
Do this:
temp= student[sizeOfArray - 1];
student[sizeOfArray - 1] = student[min];
student[min] = temp;
Using qsort() to sort your array is not difficult. The first argument is the array itself, the second is the number of elements in the array, the third is the size of each array element (sizeof (Student)), and the fourth is a function pointer that returns -1 if the compared to elements are in the correct order, 0 if equal, and +1 if in the wrong order.
So:
int compareByGrade(const void *ptr1, const void *ptr2)
{
const Student *const s1 = ptr1;
const Student *const s2 = ptr2;
if (s1->currentGrade > s2->currentGrade)
return -1; /* Correct order */
else
if (s1->currentGrade < s2->currentGrade)
return +1; /* Wrong order */
else
return 0; /* Same grade */
}
although I personally like to rewrite that as
int compareByGrade(const void *ptr1, const void *ptr2)
{
const float val1 = ((const Student *)ptr1)->currentGrade;
const float val2 = ((const Student *)ptr2)->currentGrade;
return (val1 > val2) ? -1 : (val1 < val2) ? +1 : 0;
}
which does the exact same thing, but with more concise expressions. Use the one you find easier to read, understand, and maintain (in the long term).
In both cases, the sortByGrade() function is just
void sortByGrade(Student *const array, const size_t elements)
{
if (array != NULL && elements > 1)
qsort(array, elements, sizeof array[0], compareByGrade);
}
Note that you should use size_t type for nonnegative memory sizes -- size_t is usually unsigned (cannot represent negative values) --, things like number of elements in array, array indices, string lengths, and so on. It is the purpose of the type.
On current 64-bit architectures, int is only 32-bit, so if you get into the habit of using int for memory sizes, your code will only be able to reference just 2 GB of memory. This is a real problem with old programs, because their programmers didn't think it'd ever be a problem. (It is so bad, actually, that the Linux kernel had to restrict writes to files to less than 2GB at a time.)
So, please, become better than those problematic old-timey programmers, and learn how to use size_t instead of unsigned int or int.

How can I use strcpy to store string arrays into a struct?

I am making a small ANSI C application using GCC in Ubuntu, which requires the use of strcpy().
My header file:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define DECKSZ 52
typedef struct card {
enum {ACE=1, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING} pips;
enum {SPADES, CLUBS, HEARTS, DIAMONDS} suit;
char cardName[20];
} card;
extern card deck[];
void initDeck(card[]);
void labelCards();
void shuffleDeck(card[]);
void swap(card*,card*);
My main file:
#include "CardOps.h"
card deck[DECKSZ];
void initDeck(card deck[]) {
int counter;
for (counter = 0; counter < DECKSZ; counter++) {
deck[counter].pips = (const)((counter % 13) + 1);
deck[counter].suit = (const)(counter / 13);
}
}
void labelCards(card deck[]) {
static const char *pipNames[] = {"Ace","Two","Three","Four","Five","Six","Seven","Eight","Nine","Ten","Jack","Queen","King"};
static const char *suitNames[] = {"Spades","Hearts","Diamonds","Clubs"};
int i;
for (i = 0; i < DECKSZ; i++) {
strcpy(deck[i].cardName, pipNames[i]);
/*strcpy(cardName, suits[i]);*/
}
}
int displayCards(card deck[], int numCards) {
int i, countCards;
if (numCards > 52)
countCards = 52;
else
countCards = numCards;
for (i = 0; i < countCards; i++) {
printf(deck[i].cardName);
}
return countCards;
}
void shuffleDeck(card deck[]) {
int i, j;
for (i = 0; i < DECKSZ; i++) {
j = rand() % DECKSZ;
swap(&deck[i], &deck[j]);
}
}
void SortCards() {
}
void swap(card *c1, card *c2) {
card temp;
temp = *c1;
*c1 = *c2;
*c2 = temp;
}
int main(void) {
initDeck(deck);
/*labelCards(deck);*/
displayCards(deck,52);
shuffleDeck(deck);
return EXIT_SUCCESS;
}
I am having trouble with getting strcpy() working within my labelCards() function. Would somebody please help me with strcpy()? Thanks!
I think you'd be better off using sprintf than strcpy. This is because sprintf returns an integer that tells you how many chars you wrote to the destination buffer. With that knowledge you know where to start writing when you want to write the suit.
//copy the name into the buffer at cardname
int written = sprintf(deck[i].cardName, "%s" pipNames[i%13]);
//copy the suit name into the same buffer, but advanced by however many chars we just wrote
sprintf(deck[i].cardName + written, "%s", suits[i/13]);
Now it will say things like FiveHearts, and AceClubs.... not optimal, but you can work from here.
Edit: user3386109 suggests an approach much smarter than mine:
sprintf(deck[i].cardName, "%s of %s", pipNames[i%13], suits[i/13] );
One sprintf is definitely better than the two I was doing. There are some cases where knowing how to continue writing where you left off with sprintf is valuable, but this is not one of them. I've also corrected the logic for the indices in pipNames and suits according to user3386109's amendments.
In:
void labelCards(card deck[]) {
static const char *pipNames[] = {"Ace","Two","Three","Four","Five","Six","Seven","Eight","Nine","Ten","Jack","Queen","King"};
static const char *suitNames[] = {"Spades","Hearts","Diamonds","Clubs"};
int i;
for (i = 0; i < DECKSZ; i++) {
strcpy(deck[i].cardName, pipNames[i]);
/*strcpy(cardName, suits[i]);*/
}
}
pipNames[i] accesses a non-existing array element when i > 12.
You need to do pipNames[i % 13] as you do in initDeck. It feels like the labeling should be in initDeck function.

Resources