배열
배열은 개발에서 흔히 사용되는 데이터 구조입니다. 물론 우리는 배열이 컨테이너와 동일하다는 것을 알고 있지만 값과 문자를 저장할 수 있을 뿐만 아니라 함수의 항목과 구조의 데이터를 저장합니다.
typedef struct _value { int val_1; int val_2; }VALUE; typedef struct _table { char index; char data[100]; int (*UniSetFunc)(VALUE*); }TABLE; int add(VALUE *val ) { int temp = 0; temp = val->val_1 + val->val_2; return temp; } TABLE page[10] { {“ First section ”, “abcdefghijklmn”, add}, {“Second section”, “opqrstuvwxyz”, NULL} }; int main() { VALUE AddValue; AddValue.val_1 = 2; AddValue.val_2 = 4; int result = 0; result = page[0]-> UniSetFunc(&AddValue); printf(“The Result of add is %d\n”, result); return 0; }
이때 배열은 Python 언어의 사전과 유사한 구조로 변환되므로 이후 개발 및 활용은 물론 추가 업그레이드 및 유지 관리가 용이합니다.
코드 분석: 우선 함수의 이름이 함수의 입력 주소로 사용될 수 있다는 것을 알고 있습니다(배열의 주소를 나타내는 배열의 이름과 유사). TABLE 구조는 int (* UniSetFunc)(VALUE*) 멤버 함수를 정의합니다. 여기서 UniSetFunc는 함수의 입력 매개변수로 사용되며 VALUE*는 TABLE 유형 배열 페이지를 포함합니다. add 함수를 간접적으로 호출하고 AddValue.val_1 및 AddValue.val_1 두 숫자의 합을 구현하기 위해 페이지 [0]-> UniSetFunc(&AddValue)에서 호출할 수 있는 함수의 항목 주소와 구조의 데이터입니다. 값을 추가합니다.
메모리 적중률 문제:
코드 연산의 효율성을 높이기 위해서는 메모리 공간을 최대한 활용하고 메모리 영역에 지속적으로 접근해야 합니다.
메모리에서 배열이 저장되는 위치는 전체 영역이며, 정의된 배열 array[2][2]에 대해 array[0][0] 주소를 가정합니다. 가 0x04030이면 array[0][1], array[1][0], array[1][1]의 주소는 각각 0x04031, 0x04032, 0x04033이므로 메모리 적중률이 향상됩니다. 점프 접근보다는 메모리 공간 영역에 대한 지속적인 접근 다음으로 행렬 곱셈 문제를 살펴보겠습니다.
for (int i = 0; i < 2; ++i) { for (int j = 0; j < 2; ++j) { for (int k = 0; k < 3; ++k) { matrix[i][j] += matrix1[i][k] * matrix2[k][j]; } } }
위 코드는 행렬1과 행렬2를 곱한 후 행렬에 대입하는 일반적으로 사용되는 방법입니다. 즉, 행렬1 행렬을 사용하여 행렬2의 열 벡터를 곱한 행 벡터를 구하는 방법입니다. 그런 다음 이를 행렬에 할당하므로 메모리의 행렬 저장 구조와 관련하여 행렬2에 액세스할 때 연속 액세스를 사용하지 않으므로 메모리 적중률이 낮다는 것을 분명히 알 수 있습니다. 다음으로 메모리 적중률이 높은 방법을 살펴보겠습니다.
for (int i = 0; i < 2; ++i) { for (int k = 0; k < 3; ++k) { for (int j = 0; j < 2; ++j) { matrix[i][j] += matrix1[i][k] * matrix2[k][j]; } } }
코드에서는 두 번째 for 루프와 세 번째 for 루프의 위치만 교환하고 다른 부분은 변경되지 않은 것을 볼 수 있습니다. 그러나 메모리 적중률이 크게 향상되었습니다. 행렬 곱셈의 목적은 행렬1과 행렬2 내부의 요소들을 순차적으로 곱한 다음 이를 누적하는 것입니다. 이러한 방식으로 행렬1과 행렬2에 액세스할 때 메모리 누락이 발생하지 않으므로 메모리 적중 확률이 향상됩니다.
휘발성, 상수, 정적의 관계:
const 키워드는 상수 키워드이며, 이 키워드가 작용하는 양은 상수입니다. 예를 들어 const int value = 12; 상수는 프로그램에 의해 변경될 수 없습니다. const 키워드는 프로그램이 실수로 고정 상수를 변경하는 것을 방지하기 위해 제때에 const 키워드를 추가해야 합니다. const 키워드가 상수에 작용하는 경우 상수를 직접 초기화해야 합니다. 전체 프로그램이 실행되는 동안에는 변경할 수 없으므로 즉시 초기화해야 합니다. 예: const int 값 = 12는 정확하지만 const int value; value = 12; 이 구문은 잘못되었습니다! 다음으로 좀 더 어려운 문제인 상수 포인터와 포인터 상수를 살펴보겠습니다. 먼저 코드를 살펴보겠습니다.
#define SWITCH 1 int main() { int val_1 = 5; int val_2 = 10; const int *p1 = &val_1; int const *p2 = &val_1; int *const p3 = &val_1; #ifdef SWITCH // This is a switch *p1 = 20; *p2 = 21; *p3 = 22; #endif #ifndef SWITCH p1 = &val_2; p2 = &val_2; p3 = &val_2; #endif printf("%d\n", *p1); printf("%d\n", *p2); printf("%d\n", *p3); return 0; }
cygwin 컴파일러에서 실행하면 다음 오류를 볼 수 있습니다.
그림에서 포인터 p1과 p2는 포인터 상수로서 val_1의 값만 읽을 수 있다는 것을 분명히 알 수 있습니다. 즉, 변경할 수 없습니다. 변수의 내용이므로 *p1 = 20; *p2 = 21; (#ifdef SWITCH ... #endif는 매크로 스위치인 조건부 컴파일입니다.) 그런 다음 #define SWITCH 1 문을 주석 처리합니다. 이때 두 번째 코드 블록이 실행되고 결과는 다음과 같습니다.
오류를 보면 알 수 있습니다. p3은 상수 포인터이므로 고정된 주소만 가리킬 수 있고 가리키는 방향을 변경할 수 없으므로 p3 = &val_2의 연산이 잘못되었으므로 올바른 코드는 다음과 같습니다.
int main() { int val_1 = 5; int val_2 = 10; const int *p1 = &val_1; int const *p2 = &val_1; int *const p3 = &val_1; printf("Frist\n"); printf("%d\n", *p1); printf("%d\n", *p2); printf("%d\n", *p3); p1 = &val_2; p2 = &val_2; *p3 = 22; printf("Second\n"); printf("%d\n", *p1); printf("%d\n", *p2); printf("%d\n", *p3); return 0; }
const int * const p = &a;或int const *const p = &a; 在定义函数的时候,若该入口参数在程序执行的过程中不希望被改变,则一定要将该形参用const来修饰,一来这样可以防止该段程序将其改变,二来对于形参而言,一个无论是否是const修饰的实参都可以将其传入const形的形参,而一个const形的实参是无法传入非const形的形参中,所以为了使编译不出错在定义函数的时候,一定要将不希望被改变的量用const关键字来修饰。
Static关键字为静态关键字,它的作用是将作用的变量存入内存中,而非存入寄存器中(即将变量存入堆中而非栈中),并且该作用的变量仅保存最近一次获取的值。接下来我们来看一段代码。
void countfun () { static int count = 0; ++count; printf(“This is %d number, enter into this function !\n”, count ); } int main() { for (int i = 0; i < 5; ++i) { countfun(); } return 0; }
这段代码的运行结果如下:
而若将除去static关键字,则运行的结果如下:
由此我们可以清楚的看出,static作用的变量count只会存入当前的结果,因此循环调用countfun( )函数的时候并没有从新将count变量置为0,而是保存了前一次的值。
Static关键字在项目中的应用是很广泛的,它不仅仅有上述所介绍的特点,同时若想要定义的全局变量在整个工程中仅在当前.C文件中有效时,也应该将这个全局变量用static来修饰,这样在其他的文件中是无法访问这个变量,从而降低了模块间的耦合度,提高了模块的内聚性,防止其他文件将其改变,从而更加的安全。
volatile关键字在嵌入式领域中是十分重要的一个关键字,尤其是在与硬件相关或多线程的编程中更为重要。volatile关键字修饰的变量说明它是可以随时发生改变的,我们不希望编译器去优化某些代码的时候,需要将这个变量用volatile关键字来修饰,从而程序每次访问该变量的时候是直接从内存中提取出来,而不是从临时的寄存器中将该变量的副本给提取出来利用!例如当我们想要实现某个中断处理时,其用来做判断条件的标记位则应该用volatile来修饰,这样当这个中断在别的地方被触发的时候就可以被实时的检测到,不至于由于优化而忽略中断。接下来我们看一段代码:
int main() { volatile int i = 10; int a = i; printf(“i = %d\n”, a); __asm { mov dword ptr[ebp-4], 0x10 } int b = i; printf(“i = %d\n”, b); return 0; }
此程序输出结果为i = 10;i = 16; 若将volatile关键字去掉,则结果为i = 10;i = 10;
即不加关键字会将汇编代码忽略掉,所以为了防止代码优化以及可以及时检测到外部程序对该变量的改变,我们必须将该变量加上volatile关键字。我们知道volatile关键字表征该量是易变的,const关键字代表该量是常量不能改变,那么volatile与const是否可以一起修饰同一个量呢,是肯定的,例如在硬件编程中ROM所存储的数据是不允许用户改变的,即指向该数据的指针必须为常量指针(const int *p = &ram_data),然而开发商却可以将其意外的改变,为了防止ROM的内容被意外的改变时,而用户程序没有及时的发现,必须将该量用volatile修饰,所以应这样定义该指针(volatile const int *p = &rom_data)。
位运算
在数字解码与编码的过程中,位运算的操作是司空见惯的事,同时位运算在提高程序的性能方面也独占鳌头,因此位运算操作是必需要深入了解的问题。
在乘法以及除法的操作中我可以使用未运行来提高代码的质量,例如:a = a * 16;这种操作完全可以替换为:a = a
在数据类型转换的过程中也需要做位运算操作,例如我们想将一个unsigned short类型的数据存入unsigned char类型的数组中,就需要进行位运算,首先分析知道unsigned short占用16个字节,unsigned char占用8个字节,想要将大字节的数据存入小字节,必须要对大字节进行分割,即将高8位与低8为分离开来分别存放,来看实现代码:
unsigned char * DrawCompo_Pj_BT_Change(unsigned short *subarray) { unsigned char temp[500]; (void)_sys_memset(&temp, 0x00, sizeof(temp) ); unsigned short i = 0; while (subarray[i] != 0x0000) { if( (subarray[i] & 0xff00) == 0x0000) { temp[i++] = (unsigned char)(subarray[i] & 0x00ff); } else { temp[i] = (unsigned char)( (subarray[i] & 0xff00) >> 8); temp[i++] = (unsigned char)(subarray[i] & 0x00ff); } } temp[i] = '\0'; return temp; }
temp[i] = (unsigned char)( (subarray[i] & 0xff00) >> 8);即取subarray[i]数据的高8位,temp[i++] = (unsigned char)(subarray[i] & 0x00ff);取低8位。这样就可以实现将高字节的数据完整的存入到低字节中。
位运算还可以用来判断变量的符号,我们知道对于一个有符号的变量,其最高位为其符号位,故检查改变的最高位即可知道该变量为正还是为负。看一段代码:
int main() { short test_data = -12; if (test_data & 0xF000) { printf("This number is negative "); } else { printf("This number is positive "); } return 0; }
对于想要交换两个数的值的时候,通常我们的做法如下:
void swap(int &data1, int &data2) { int temp = 0; temp = data1; data1 = data2; data2 = temp; }
这样的代码比较简单易懂,然而美中不足的是它会产生一个临时变量temp,接下来我们用位运算来重写这个程序;
void swap(int &data1, int &data2) { data1 = data1 ^ data2; data2 = data1 ^ data2; data1 = data1 ^ data2; }
从上面的代码我们可以看出少了一个临时变量,同时也加快了代码的运行效率。
尾递归:
递归调用给我们带来了很多方便,也简化了代码,使程序看起来更加的简洁和明了,但递归调用也通常伴随着一个潜在的危险:出栈,接下来我们来看一个常见的递归。
int factorial(int n) { if (n < 1) { return 1; } else { return factorial(n-1)*n; } }
通常在求一个数的阶乘的时候我们习惯于采用上述方法,然而分析来看当输入的n值较大时,factorial(n-1)*n所计算的值会不断的压入堆栈,生成很多的临时变量,等待下一个的值的确定才得以计算,然而在内存中堆栈的大小是固定的,当输入的n值很大时,极有可能产生堆栈溢出!因此,有一个好的方法解决这种问题即尾递归调用。接下来我们来看这种强大的算法。
int factorial(int n, int m) { if (n < 2) { return m; } else { factorial(n-1, n*m); } }
从代码中可以看出,通过引入一个新的参数m来存放每次递归所产生的值,这样就避免了每次递归都要进行压栈操作,也就不会产生堆栈溢出的现象,而且普通的递归每次递归只能等待下一次递归得到的结果后才能继续运算,而尾递归每次执行都会进行运算,一次循环执行完毕即可得到结果,其时间复杂度为O(n);

.NET에서 C#의 프로그래밍 프로세스에는 다음 단계가 포함됩니다. 1) C# 코드 작성, 2) 중간 언어 (IL)로 컴파일하고 .NET 런타임 (CLR)에 의해 실행됩니다. .NET에서 C#의 장점은 현대적인 구문, 강력한 유형 시스템 및 .NET 프레임 워크와의 긴밀한 통합으로 데스크탑 응용 프로그램에서 웹 서비스에 이르기까지 다양한 개발 시나리오에 적합합니다.

C#은 Microsoft가 개발 한 최신 객체 지향 프로그래밍 언어이며 .NET 프레임 워크의 일부로 개발되었습니다. 1.C#은 캡슐화, 상속 및 다형성을 포함한 객체 지향 프로그래밍 (OOP)을 지원합니다. 2. C#의 비동기 프로그래밍은 응용 프로그램 응답 성을 향상시키기 위해 비동기 및 키워드를 기다리는 키워드를 통해 구현됩니다. 3. LINQ를 사용하여 데이터 컬렉션을 간결하게 처리하십시오. 4. 일반적인 오류에는 NULL 참조 예외 및 인덱스 외 예외가 포함됩니다. 디버깅 기술에는 디버거 사용 및 예외 처리가 포함됩니다. 5. 성능 최적화에는 StringBuilder 사용 및 불필요한 포장 및 Unboxing을 피하는 것이 포함됩니다.

C#.NET 애플리케이션에 대한 테스트 전략에는 단위 테스트, 통합 테스트 및 엔드 투 엔드 테스트가 포함됩니다. 1. 단위 테스트를 통해 MSTEST, NUNIT 또는 XUNIT 프레임 워크를 사용하여 코드의 최소 단위가 독립적으로 작동합니다. 2. 통합 테스트는 일반적으로 사용되는 시뮬레이션 된 데이터 및 외부 서비스를 결합한 여러 장치의 기능을 확인합니다. 3. 엔드 투 엔드 테스트는 사용자의 완전한 작동 프로세스를 시뮬레이션하며 셀레늄은 일반적으로 자동 테스트에 사용됩니다.

C# 수석 개발자와의 인터뷰에는 비동기 프로그래밍, LINQ 및 .NET 프레임 워크의 내부 작업 원리와 같은 핵심 지식을 마스터하는 것이 필요합니다. 1. 비동기 프로그래밍은 비동기를 통해 작업을 단순화하고 응용 프로그램 응답 성을 향상시키기 위해 기다리고 있습니다. 2.linq는 SQL 스타일로 데이터를 운영하고 성능에주의를 기울입니다. 3. Net Framework의 CLR은 메모리를 관리하며 가비지 컬렉션은주의해서 사용해야합니다.

C#.NET 인터뷰 질문 및 답변에는 기본 지식, 핵심 개념 및 고급 사용이 포함됩니다. 1) 기본 지식 : C#은 Microsoft가 개발 한 객체 지향 언어이며 주로 .NET 프레임 워크에 사용됩니다. 2) 핵심 개념 : 위임 및 이벤트는 동적 바인딩 방법을 허용하고 LINQ는 강력한 쿼리 기능을 제공합니다. 3) 고급 사용 : 비동기 프로그래밍은 응답 성을 향상시키고 표현 트리는 동적 코드 구성에 사용됩니다.

C#.net은 강력한 생태계와 풍부한 지원으로 인해 마이크로 서비스를 구축하는 데 인기있는 선택입니다. 1) ASP.NETCORE를 사용하여 RESTFULAPI를 작성하여 주문 생성 및 쿼리를 처리하십시오. 2) GRPC를 사용하여 마이크로 서비스 간의 효율적인 통신을 달성하고 주문 서비스를 정의하고 구현하십시오. 3) Docker Containerized 마이크로 서비스를 통해 배포 및 관리를 단순화합니다.

C# 및 .NET의 보안 모범 사례에는 입력 확인, 출력 인코딩, 예외 처리, 인증 및 인증이 포함됩니다. 1) 일반 표현식 또는 내장 방법을 사용하여 악성 데이터가 시스템에 들어가는 것을 방지하기 위해 입력을 확인하십시오. 2) XSS 공격을 방지하기 위해 출력 인코딩 httputility.htmlencode 메서드를 사용하십시오. 3) 예외 처리는 정보 유출을 피하고 오류를 기록하지만 자세한 정보를 사용자에게 반환하지는 않습니다. 4) ASP.NETIDENITY 및 CAMPLES 기반 승인을 사용하여 신청서를 무단 액세스로부터 보호합니다.

C 언어의 결장의 의미 ( ':') : 조건부 명세서 : 조건부 표현 및 명령문 분리 블록 루프 문 : 초기화, 조건부 및 증분 표현식 매크로 정의 분리 : 매크로 이름 및 매크로 값 단일 라인 주석 설명 : 콜론에서 라인으로의 내용을 주석 차원으로 표현


핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

MinGW - Windows용 미니멀리스트 GNU
이 프로젝트는 osdn.net/projects/mingw로 마이그레이션되는 중입니다. 계속해서 그곳에서 우리를 팔로우할 수 있습니다. MinGW: GCC(GNU Compiler Collection)의 기본 Windows 포트로, 기본 Windows 애플리케이션을 구축하기 위한 무료 배포 가능 가져오기 라이브러리 및 헤더 파일로 C99 기능을 지원하는 MSVC 런타임에 대한 확장이 포함되어 있습니다. 모든 MinGW 소프트웨어는 64비트 Windows 플랫폼에서 실행될 수 있습니다.

SublimeText3 Linux 새 버전
SublimeText3 Linux 최신 버전

DVWA
DVWA(Damn Vulnerable Web App)는 매우 취약한 PHP/MySQL 웹 애플리케이션입니다. 주요 목표는 보안 전문가가 법적 환경에서 자신의 기술과 도구를 테스트하고, 웹 개발자가 웹 응용 프로그램 보안 프로세스를 더 잘 이해할 수 있도록 돕고, 교사/학생이 교실 환경 웹 응용 프로그램에서 가르치고 배울 수 있도록 돕는 것입니다. 보안. DVWA의 목표는 다양한 난이도의 간단하고 간단한 인터페이스를 통해 가장 일반적인 웹 취약점 중 일부를 연습하는 것입니다. 이 소프트웨어는

Atom Editor Mac 버전 다운로드
가장 인기 있는 오픈 소스 편집기

안전한 시험 브라우저
안전한 시험 브라우저는 온라인 시험을 안전하게 치르기 위한 보안 브라우저 환경입니다. 이 소프트웨어는 모든 컴퓨터를 안전한 워크스테이션으로 바꿔줍니다. 이는 모든 유틸리티에 대한 액세스를 제어하고 학생들이 승인되지 않은 리소스를 사용하는 것을 방지합니다.
