Custom structure type and implementation of telephone address book

Keywords: C

  CSDN's friends, Happy Mid Autumn Festival!

  I've sorted out what I learned today and shared it with you. It's regarded as a mid autumn festival gift.

1, Structure

struct Node{
    int data;
    Struct Node n;
}//The defect of this definition is that there is a node in each node, which recurses to infinity continuously, and the required memory space cannot be determined.
struct Node{
    int data;
    struct Node* next;
}//The size of the pointer is four bytes or eight bytes, which avoids the problem that the memory space size cannot be determined above.
//Structure self reference: this structure can find structures of the same type
1.0 structure creation and initialization
struct Point{
    int x;
    int y;
}p3={1,2},p4={5,6};
struct Point p2={7,8};
int main()
{
    struct Point p1={10,12};
    
    return 0;
}
1.1 structure memory alignment
#include <stdio.h>
struct S1{
    char c1;//1
    int data;//4
    char c2;//1
}s={'c',100,'f'};
struct S2{
    char c1;
    char c2;
    int a;
}
int main()
{
    printf("%d\n",sizeof(s));
    printf("%d\n",sizeof(struct S2));
}
It turned out to be
12
8

The reason for the difference is the memory alignment (which is very obvious in the structure).

Rules for structure memory alignment:

1. The first member of the structure is always placed at the position where the offset of the starting position of the structure is 0.

2. Starting from the second structure member, it is always placed at an offset of an integer multiple of the alignment number.

Alignment number = the compiler's default alignment number and the smaller value of the variable's own size.

Linux does not have a default alignment number.

The default alignment number under VS is 8.

3. The total size of the structure must be an integer multiple of the largest alignment number of each member.

4. If a structure is nested, the nested structure is aligned to an integer multiple of the maximum alignment number of its members, and the overall size of the structure is an integer multiple of all the maximum alignment numbers (including the alignment number of nested structures).

Reasons for memory alignment:

1. Platform reason (migration reason):

Not all hardware platforms can access any data at any address. Some hardware platforms can only get a specific type of data at some address, otherwise hardware exceptions will be thrown.

2. Performance reasons

The data structure (especially the stack) should be on the natural boundary as much as possible. The reason is that in order to access the misaligned memory, the processor needs to access the memory twice, while the aligned memory only needs to be accessed once.

Generally speaking, the memory alignment of structures is the practice of trading space for time.

12
struct S1{
    char c1;//1
    int data;//4
    char c2;//1
}s={'c',100,'f'};
8
struct S2{
    char c1;
    char c2;
    int a;
}

Through comparison, we find that if we use our brains a little when designing structures, can we save some space.

Comparing s1 and s2, we suggest that objects with small space should be placed together as much as possible to reduce space waste.

Can you modify the default alignment number under VS? Of course.

Modify the default alignment number: use the compile preprocessing instruction #pragma

#pragma pack(1) / / set the default number of alignments to 1, so that they are all stacked together
struct S1{
    char a;
    int i;
    char c;
};
#pragma pack() / / unset the default number of alignments
#pragma pack(8)
struct S2 {
	char a;
	int b;
	char c;
};
int main()
{
	printf("%d", sizeof(struct S1));
	printf("%d", sizeof(struct S2));
	return 0;
}
The output value is 6 12	

Comparing S1 and S2, we conclude that when the alignment of the structure is inappropriate, we can also change the default alignment number ourselves.

However, it should be noted that in order to ensure efficiency, since the 32-bit machine register reads 4 bits at a time and the 64 bit machine register reads 8 bits at a time, if the default alignment number is set to odd, it will affect the reading efficiency, it is better to modify the default alignment number to even.

1.2 offsetof function

Can we use a function to directly return the offset of a structure member from the first address of the structure? The answer is yes -- the offsetof function.

offsetof(struct,struct.member)
Returns the offset of the member from the first address of the structure.
This is a macro that requires a header file<stddef.h>
1.3 structural transmission parameters:
#include <stdio.h>
struct S {
	int data[100];
	int number;
};
void print1(struct S a)
{
	for (int i = 0; i < 9; i++)
	{
		printf("%d ", a.data[i]);
	}
	printf("\n%d\n", a.number);
}
void print2(struct S* p)
{
	for (int i = 0; i < 9; i++)
	{
		printf("%d ", p->data[i]);
	}
	printf("\n%d\n", p->number);
}
int main()
{
	struct S s1 = { {1,2,3,4,5,6,9,8,10},10 };
	print1(s1);
	print2(&s1);
	return 0;
}

Which of the print1 and print2 functions above?

print2 function preferred

Reason: when the function passes parameters, the parameters need to be pressed on the stack, which will have time and space overhead

If the structure is too large when passing a structure object, the system overhead of parameter stack pressing is relatively large, which will lead to performance degradation.

K & R mentioned in the original C language user manual that if you want to pass a structure as a parameter into a function, the best way is to pass in a pointer to the structure.

2, Bit segment

2.0 what is a bit segment?

The declaration of a bit segment is similar to a structure, but there are two differences.

  • The member of the bit field must be int, unsigned int or signed int (in fact, char can also be used, and it seems that all of the integer family can be used)
  • The member name of a bit segment is at least followed by a colon and a number. We do not require that the member name of each bit segment be followed by a colon and a number.

Bit segments can save space, but it doesn't mean there's no waste at all.

The bit value here is binary.

#include <stdio.h>
struct A {
	int a : 2;
	int b : 5;
	int c : 10;
	int d : 30;
};
int main()
{
	printf("%d", sizeof(struct A));
	return 0;
}

Output: 16
Why? This involves the memory allocation of bit segment structure.

2.1 memory allocation of bit segment

The space of the bit segment is opened up by 4 bytes (int) or one byte (char) as required. If it is not enough, open up another 4 bytes or one byte. As for how to use the given space (start from the left or start from the right), how to put the bit segment members that lead to insufficient space (whether to put it directly into the newly opened space or use both the original space and the newly opened space), the standard of C is not given, so it is uncertain.

The bit segment involves the above uncertain factors, so the bit segment is not cross platform. Pay attention to portable programs and avoid using bit segments.

It can be verified by an experiment

struct S {
	char a : 3;
	char b : 4;
	char c : 5;
	char d : 4;
};
int main()
{
	struct S s = { 0 };
	s.a = 10;
	s.b = 12;
	s.c = 3;
	s.d = 4;

	return 0;
}

If you use this space from the right and apply for a new space, the applied things will be directly put into the new space. Let's expand each number in binary below.

At the beginning, I'll give you a byte of 8bit,0000 0000.

After a=10=0000 1010 comes over, take three bits to become 010 and put them in to become 0000 0010

b=12=0000 1100, take 4 bits to become 1100, and then put them in to become 0110 0010

c. if it's not enough, apply for another $0000

c=3=0000 0110 takes 5 bits and becomes 00110

Put it in and become 0000 0110

d it's not enough to open up another piece of 0000

d=4=0000 0100 take 4 bits 0100

Put in 0000 0100

In this way, when the machine is a small end, reading this memory in hexadecimal is

0110 0010 0000 0110 0000 0100

‚Äč 6 2 0 3 0 4

After the experiment, the conclusion is consistent with our hypothesis, but perhaps only vs this compiler does this, not all compilers do this, because C does not specify standards.

Through experiments, it is found that offsetof cannot operate on bit segments.

2.2 cross platform problem of bit segment
  • It is uncertain whether the int bit field (the space opened up by int) is regarded as a signed number or an unsigned number.

  • The maximum number of bit segments is uncertain. For example, on a 16 bit machine, if int is 2byte, writing more than 16 bit segments cannot run.

  • Whether the members in the bit segment are defined from left to right or right to left defines the standard and is clearly defined

  • When a structure contains two bit segments and the second bit segment is too large to accommodate the remaining bits of the first bit segment, it is uncertain whether to discard the remaining bits or use them.

3, Enumeration

Enumeration means to enumerate one by one.

Gender can be listed one by one

The month has 12 months, which can also be listed one by one

Enumeration can be used in these places

#include <stdio.h>
enum COLOR {
	RED=6,
	GREEN=10,
	BLUE
};//Enumeration constant initialization
int main()
{
	enum COLOR  c= GREEN;//Define an enumeration variable c
	printf("%d %d %d", RED, GREEN, BLUE);
	return 0;
}

Enumeration gives the name some meaning, so that when we design programs, especially when using switch statements, we can write case RED: in this way, it looks more readable.

Advantages of enumeration

  • Increase the readability and maintainability of the code
  • Compared with #define defined identifiers, enumeration has type checking, which is more rigorous
  • Prevents naming contamination (encapsulation)
  • Convenient for debugging (you can see the value during debugging and #define will replace it directly)
  • Easy to use, you can define multiple enumeration constants at a time.

4, Consortium

Federation is also a special custom type.

Variables defined by this type also contain a series of members, which are characterized by a common space. (therefore, a consortium is also called a consortium)

#include <stdio.h>
union U {
	char c;
	int a;
};
int main()
{
	union U u = { 0 };
	printf("%d\n", sizeof(union U));
	printf("%p\n", &u);
	printf("%p\n", &(u.a));
	printf("%p\n", &(u.c));
	return 0;
}

I found three addresses as like as two peas. What for?

This shows that c and i share a space.

Because they share a space, modifying c will change i, and modifying i will change c.

In order to store members, the size of a union is at least the size of the largest member.

16.0 judging whether a machine is a big end or a small end
Determine whether a machine is a big end or a small end
int main()
{
    int a=1;//0x 00 00 00 01
    //Here low address to high address
    //01 00 00 small end storage
    //00 01 big end storage
    //The big end will put the high address at the low address and the low address at the high address
    //The small end will put the high address in the high address and the low address in the low address
    //Practice 1 we only look at the first byte
    char* pc=(char*)&a;
    if(*pc==1)
    {
        printf("Small end");
    }
    else
    {
        printf("Big end");
    }
}
//We can't use forced type conversion char to judge here, because it will only convert the first bit. The large end of the first bit is placed at the back and the small end is placed at the front, which can't be seen at all.

//Practice 2: use the union Community
    union U {
        char c;
        int i;
    } u;
    u.i = 1;
//If it is the big end, it stores the low bit in the high address. Our u.c read-only bit of the low address cannot be read
//If it is a small terminal, it stores this low bit in the low address, and our u.c can read it.
    if (u.c == 1)
    {
        printf("\n Small end");
    }
    else
    {
        printf("\n Big end");
    }

Considering the nature of the consortium, use scenarios: when using one member at the same time, do not use other members.

16.1 calculation of consortium size:
  • The size of the consortium is at least the size of the largest member, so we generally assume that the size of the consortium is the size of the largest member
  • If it is checked that the maximum member size is not an integer multiple of the maximum alignment number, align the size of the consortium to an integer multiple of the maximum alignment number.

Alignment of common bodies

#include <stdio.h>

union Un1
{
	char c[5];//When the array finds the alignment number, it is equivalent to putting 5 elements of its own type here. The alignment number is naturally 1
	int i;//The number of alignments is 4
};//max(5,4)=5 is not a multiple of the maximum alignment number 4, so some space is wasted to align to 8
union Un2
{
	short c[7];//The number of alignments is 2
	int i;//The number of alignments is 4
};//max(4,14)=14 is not a multiple of 4, aligned to 16
int main()
{
	printf("%d\n", sizeof(union Un1));
	printf("%d\n", sizeof(union Un2));
	return 0;
}

5, Implementation of telephone address book

This is a good exercise for custom types, and it also took me a lot of time.

contact.h

#define _CRT_SECURE_NO_WARNINGS 1

#ifndef define _CONTACT_H_

#define _CONTACT_H_



#include <stdio.h>

#include <string.h>

//Some convenient numbers

#define MAXNAME 20

#define MAXSEX 5

#define MAXTEL 20

#define MAXDOOR 30

#define MAX 1000



//Human information

typedef struct {

	char name[MAXNAME];

	char sex[MAXSEX];

	int age;

	char tel[MAXTEL];

	char address[MAXDOOR];

}person;



//mail list

typedef struct {

	person perinfo[MAX];

	int sz;//Number of valid people in the current address book

}Contact;



enum Option {

	EXIT,

	ADD,

	DELETE,

	FIND,

	CHANGE,

	SHOW,

	CLEAR,

	SORT,

};//Use enumeration to make switch look more intuitive

void Initcontact(Contact* p);



void add(Contact* p);



void show(Contact* p);



void find(Contact* p);



void contactdelete(Contact* p);



void contactchange(Contact* p);



void contactclear(Contact* p);



void contactsort(Contact* p);



#endif



contact.c



#define _CRT_SECURE_NO_WARNINGS 1

#include "contact.h"



void Initcontact(Contact* p)

{

	p->sz = 0;

	memset(&p->perinfo, 0, MAX * sizeof(person));

}



void add(Contact* p)

{

	if (p->sz == MAX)

	{

		printf("The address book is full\n");

	}

	else

	{

		printf("Please enter your name\n");

		scanf("%s", p->perinfo[p->sz].name);

		printf("Please enter gender\n");

		scanf("%s", p->perinfo[p->sz].sex);

		printf("Please enter age\n");

		scanf("%d", &(p->perinfo[p->sz].age));

		printf("Please enter phone number\n");

		scanf("%s", p->perinfo[p->sz].tel);

		printf("Please enter your address\n");

		scanf("%s", p->perinfo[p->sz].address);

		p->sz++;

	}

}



void show(Contact* p)

{

	printf("%-20s\t%-5s\t%-s\t%-14s\t%-30s\n", "name", "sex", "age", "tel", "address");

	for (int i = 0; i < p->sz; i++)

	{

		printf("%-20s\t%-5s\t%-d\t%-14s\t%-30s\n", p->perinfo[i].name, p->perinfo[i].sex, p->perinfo[i].age, p->perinfo[i].tel, p->perinfo[i].address);

	}

}



void find(Contact* p)

{

	int a = 0;

	printf("Enter 1 if you want to find by phone number or 0 if you want to find by name\n");

	scanf("%d", &a);

	if (a == 0)

	{

		char c[MAXNAME];

		printf("Please enter a search name\n");

		scanf("%s", c);

		int ret = 0;

		for (int i = 0; i < p->sz; i++)

		{

			if (strcmp(c, p->perinfo[i].name) == 0)

			{

				printf("Search succeeded\n The corresponding information is\n");

				ret = 1;

				printf("%-20s\t%-5s\t%-d\t%-14s\t%-30s\n", p->perinfo[i].name, p->perinfo[i].sex, p->perinfo[i].age, p->perinfo[i].tel, p->perinfo[i].address);

				break;

			}

		}

		if (ret == 0)

		{

			printf("There is no such person in the phone book. Please check whether the name of this person is entered correctly\n");

		}

	}

	else if (a == 1)

	{

		int ret = 0;

		printf("Please enter the phone number to be found\n");

		char c[MAXTEL];

		scanf("%s", c);

		for (int i = 0; i < p->sz; i++)

		{

			if (strcmp(c, p->perinfo[i].tel) == 0)

			{

				printf("Search succeeded\n The corresponding information is\n");

				ret = 1;

				printf("%-20s\t%-5s\t%-d\t%-14s\t%-30s\n", p->perinfo[i].name, p->perinfo[i].sex, p->perinfo[i].age, p->perinfo[i].tel, p->perinfo[i].address);

				break;

			}

		}

		if (ret == 0)

		{

			printf("There is no such person in the phone book. Please check whether the name of this person is entered correctly\n");

		}

	}

	else

	{

		printf("Input error, about to return to the initial interface\n");

	}

}



void contactdelete(Contact* p)

{

	int a = 0;

	printf("Enter 1 if you want to delete by phone number or 0 if you want to delete by name\n");

	scanf("%d", &a);

	if (a == 0)

	{

		char c[MAXNAME];

		printf("Please enter the name to delete\n");

		scanf("%s", c);

		int ret = 0;

		int i = 0;

		for ( i = 0; i < p->sz; i++)

		{

			if (strcmp(c, p->perinfo[i].name) == 0)

			{

				ret = 1;

				break;

			}

		}

		if (ret == 0)

		{

			printf("There is no such person in the phone book. Please check whether the name of this person is entered correctly\n");

		}

		else

		{

			for (int j= i; j < p->sz; j++)

			{

				p->perinfo[j] = p->perinfo[j + 1];

			}

			p->sz--;

			printf("Delete succeeded\n");

		}

	}

	else if (a == 1)

	{

		int ret = 0;

		printf("Please enter the phone number you want to delete\n");

		char c[MAXTEL];

		scanf("%s", c);

		for (int i = 0; i < p->sz; i++)

		{

			if (strcmp(c, p->perinfo[i].tel) == 0)

			{

				int j = i;

				for (j = i; i < p->sz; j++)

				{

					p->perinfo[j] = p->perinfo[j + 1];

				}

				p->sz--;

				printf("Delete succeeded\n");

				ret = 1;

				break;

			}

		}

		if (ret == 0)

		{

			printf("There is no such person in the phone book. Please check whether the telephone number of this person is entered correctly\n");

		}

	}

	else

	{

		printf("Input error, about to return to the initial interface\n");

	}

}



void contactchange(Contact* p)

{

	char c[MAXNAME];

	printf("Please enter the name of the company to be modified\n");

	scanf("%s", c);

	int ret = 0;

	for (int i = 0; i < p->sz; i++)

	{

		if (strcmp(c, p->perinfo[i].name) == 0)

		{

			int change[5] = {0};

			printf("Do you need to modify the name? To modify the name, please enter 1, otherwise enter 0\n");

			scanf("%d", &change[0]);

			if (change[0] == 1)

			{

				printf("Please enter a new name\n");

				scanf("%s", p->perinfo[i].name);

			}

			printf("Do you need to change gender? To modify gender, please enter 1, otherwise enter 0\n");

			scanf("%d", &change[1]);

			if (change[1] == 1)

			{

				printf("Please enter the correct gender\n");

				scanf("%s", p->perinfo[i].sex);

			}

			printf("Do you need to modify the age? To modify the age, please enter 1, otherwise enter 0\n");

			scanf("%d", &change[2]);

			if (change[2] == 1)

			{

				printf("Please enter a new age\n");

				scanf("%d",&( p->perinfo[i].age));

			}

			printf("Do you need to modify the phone number? To modify the phone number, please enter 1, otherwise enter 0\n");

			scanf("%d", &change[3]);

			if (change[3] == 1)

			{

				printf("Please enter a new phone number\n");

				scanf("%s", p->perinfo[i].tel);

			}

			printf("Do you need to change your address? To modify the address, please enter 1, otherwise enter 0\n");

			scanf("%d", &change[4]);

			if (change[4] == 1)

			{

				printf("Please enter a new address\n");

				scanf("%s", p->perinfo[i].address);

			}

			ret = 1;

			printf("Modification succeeded!\n");

			printf("This person's new contact information is:\n");

			printf("%-20s\t%-5s\t%-d\t%-14s\t%-30s\n", p->perinfo[i].name, p->perinfo[i].sex, p->perinfo[i].age, p->perinfo[i].tel, p->perinfo[i].address);

			break;

		}

	}

	if (ret == 0)

	{

		printf("There is no such person in the phone book. Please check whether the name of this person is entered correctly\n");

	}

}



void contactclear(Contact* p)

{

	Initcontact(p);

}



void contactsort(Contact* p)

{

	int i, j;

	char temp1[MAXNAME];

	char temp2[MAXSEX];

	int temp3;

	char temp4[MAXTEL];

	char temp5[MAXDOOR];

	for (i = 0; i < p->sz; i++)

	{

		for (j = 0; j < p->sz - 1 - i; j++)

		{

			if (strcmp(p->perinfo[j].name, p->perinfo[j + 1].name) > 0)

			{

				strcpy(temp1, p->perinfo[j].name);

				strcpy(temp2, p->perinfo[j].sex);

				temp3 = p->perinfo[j].age;

				strcpy(temp4, p->perinfo[j].tel);

				strcpy(temp5, p->perinfo[j].address);



				strcpy(p->perinfo[j].name, p->perinfo[j + 1].name);

				strcpy(p->perinfo[j].sex, p->perinfo[j + 1].sex);

				p->perinfo[j].age = p->perinfo[j + 1].age;

				strcpy(p->perinfo[j].tel, p->perinfo[j + 1].tel);

				strcpy(p->perinfo[j].address, p->perinfo[j + 1].address);



				strcpy(p->perinfo[j + 1].name, temp1);

				strcpy(p->perinfo[j + 1].sex, temp2);

				p->perinfo[j + 1].age = temp3;

				strcpy(p->perinfo[j + 1].tel, temp4);

				strcpy(p->perinfo[j + 1].address, temp5);

			}

		}

	}

	printf("Sorting succeeded! The new address book information is as follows!\n");

	show(p);

}



test.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "contact.h"



void menu()

{

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

	printf("************This is an address book device*************\n");

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

	printf("********Enter the corresponding number to start the corresponding function***********\n");

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

	printf("******1.ADD******************2.DELETE******\n");

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

	printf("******3.FIND*****************4.CHANGE******\n");

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

	printf("******5.SHOW*****************6.CLEAR*******\n");

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

	printf("******7.SORT*****************0.EXIT********\n");

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

}

int main()

{

	int input = 0;

	Contact contact;

	Initcontact(&contact);



	do {

		menu();

		scanf("%d", &input);

		switch (input)

		{

		case ADD: add(&contact); break;

		case DELETE:contactdelete(&contact); break;

		case FIND:find(&contact); break;

		case CHANGE:contactchange(&contact); break;

		case SHOW:show(&contact); break;

		case CLEAR:contactclear(&contact); break;

		case SORT:contactsort(&contact); break;

		case EXIT:

			printf("sign out\n");

			break;

		default: printf("Input error, please re-enter\n");

		}

	} while (input!=0);



	return 0;

}
//In terms of main functions, we don't need switch statements
//Because these functions are similar, we can use function pointer array
//However, you need to define the exittable function again
void exittable(Contact* p)
{
	printf("sign out\n");
}
int main()
{
	int input = 0;
    void(*pf[])(Contact*)={exitable,add,contactdelete,
    find,contactchange,show,contactclear,contactsort};
	Contact contact;
	Initcontact(&contact);
	do {
		menu();
		scanf("%d", &input);
		(*pf[input])(&contact);
	} while (input!=0);

	return 0;
}

Posted by bills50000 on Tue, 21 Sep 2021 16:45:35 -0700