主頁 > 作業系統 > 在C中使用動態陣列分配結構的動態陣列

在C中使用動態陣列分配結構的動態陣列

2022-10-20 04:09:18 作業系統

我正在嘗試分配一個結構陣列,每個結構還包含動態陣列。他們稍后將通過以下方式進行溝通MPI_Sendrecv

struct cell {
    double a, b, c, *aa, *bb;
} *Send_l, *Send_r;

我想要Send_l并且Send_r擁有count多個元素,陣列aa并且bb應該包含sAS多個元素。這都是在 之后完成的MPI_Init

void allocateForSendRecv(int count) {
    int sAS = 5;
    int iter = 0;

    Send_l = (struct cell *)malloc(count * (sizeof(struct cell)));
    for (iter = 0; iter < count; iter  ) {
        Send_l[iter].aa = (double *)malloc((sAS - 1) * sizeof(double));
        Send_l[iter].bb = (double *)malloc((sAS - 1) * sizeof(double));
    }
    //sAS-1, as sizeof(struct cell) already contains a single (double) for aa and bb.

    Send_r = (struct cell *)malloc(count * (sizeof(struct cell)));
    for (iter = 0; iter < count; iter  ) {
        Send_r[iter].aa = (double *)malloc((sAS - 1) * sizeof(double));
        Send_r[iter].bb = (double *)malloc((sAS - 1) * sizeof(double));
    }
}

有了這個,我可以自由地分配、填充和解除分配,但是當我呼叫以下命令時,我的結果與我的參考不同(使用所有堆疊陣列)。

MPI_Sendrecv(&(Send_r[0]), count, ..., &(Send_l[0]), count, ...)

我還沒有找到確切的原因,但是關于類似問題的帖子讓我認為這是由于我的記憶體分配不連續。我試圖通過使用一個 malloc 呼叫來解決這個問題,只是在我填充我的陣列時出現分段aa錯誤bb

    Send_l = malloc(count * (sizeof(*Send_l))   count *(sizeof(*Send_l)   2 * (sAS - 1) * sizeof(double)));

    Send_r = malloc(count * (sizeof(*Send_r))   count *(sizeof(*Send_r)   2 * (sAS - 1) * sizeof(double)));

我重用了一些代碼來分配二維陣列并將其應用于這個結構問題,但無法使其作業。我是否正確地假設,通過一個有效的單個malloc呼叫并因此連續的記憶體分配,我MPI_Sendrecv可以正常作業?或者,使用會MPI_Type_create_struct解決我的非連續記憶體問題嗎?

分段錯誤的最小示例(沒有 MPI)。使用allocateSendRecv,一切都很好。但是單個 alloc inallocateInOneSendRecv給我帶來了問題。

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

struct cell {
    double a, b, c, *aa, *bb;
} *Send_l, *Send_r;

void allocateSendRecv(int count, int sAS);
void fillSendRecv(int count, int sAS);
void freeSendRecv(int count);
void printSendRecv(int count, int sAS);
void allocateInOneSendRecv(int count, int sAS);

int main(int argc, char *argv[])
{
    const int count = 2;
    const int sAS = 9;
    allocateSendRecv(count, sAS);
    //allocateInOneSendRecv(count, sAS);
    fillSendRecv(count, sAS);
    printSendRecv(count, sAS);
    freeSendRecv(count);
    return 0;
}

void allocateSendRecv(int count, int sAS) {
    int iter = 0;

    printf("Allocating!\n");

    Send_r = (struct cell *)malloc(count * (sizeof(struct cell)));
    for (iter = 0; iter < count; iter  ) {
        Send_r[iter].aa = (double *)malloc((sAS - 1) * sizeof(double));
        Send_r[iter].bb = (double *)malloc((sAS - 1) * sizeof(double));
    }

    Send_l = (struct cell *)malloc(count * (sizeof(struct cell)));
    for (iter = 0; iter < count; iter  ) {
        Send_l[iter].aa = (double *)malloc((sAS - 1) * sizeof(double));
        Send_l[iter].bb = (double *)malloc((sAS - 1) * sizeof(double));
    }
}

void allocateInOneSendRecv(int count, int sAS) {
    printf("Allocating!\n");

    Send_l = malloc(count * (sizeof(*Send_l))   count *(sizeof(*Send_l)   2 * (sAS - 1) * sizeof(double)));

    Send_r = malloc(count * (sizeof(*Send_r))   count *(sizeof(*Send_r)   2 * (sAS - 1) * sizeof(double)));
}

void freeSendRecv(int count) {
    int iter = 0;

    printf("Deallocating!\n");

    free(Send_r);

    free(Send_l);
}

void fillSendRecv(int count, int sAS) {
    int iter = 0;
    int iter2= 0;
    double dummyDouble = 5.0;

    printf("Filling!\n");

    for (iter = 0; iter < count; iter  ) {
        Send_l[iter].a = dummyDouble;
        Send_l[iter].b = dummyDouble;
        Send_l[iter].c = dummyDouble;
        for (iter2 = 0; iter2 < sAS; iter2  ) {
            Send_l[iter].aa[iter2] = dummyDouble;
            Send_l[iter].bb[iter2] = dummyDouble;
        }

        dummyDouble  ;

        Send_r[iter].a = dummyDouble;
        Send_r[iter].b = dummyDouble;
        Send_r[iter].c = dummyDouble;
        for (iter2 = 0; iter2 < sAS; iter2  ) {
            Send_r[iter].aa[iter2] = dummyDouble;
            Send_r[iter].bb[iter2] = dummyDouble;
        }
        dummyDouble  ;
    }
}

void printSendRecv(int count, int sAS) {
    int iter = 0;

    printf("Printing!\n");

    for (iter = 0; iter < count; iter  ) {
        printf("%f \n", Send_l[iter].a);
        printf("%f \n", Send_l[iter].b);
        printf("%f \n", Send_l[iter].c);
        printf("%f \n", Send_l[iter].aa[sAS - 1]);
        printf("%f \n\n", Send_l[iter].bb[sAS - 1]);

        printf("%f \n", Send_r[iter].a);
        printf("%f \n", Send_r[iter].b);
        printf("%f \n", Send_r[iter].c);
        printf("%f \n", Send_r[iter].aa[sAS - 1]);
        printf("%f \n\n", Send_r[iter].bb[sAS - 1]);
    }
}

uj5u.com熱心網友回復:

您當前的問題是您只能傳遞Send_l(resp. Send_r) 的起始地址。從那時起,所有記憶體都必須是連續的,并且您必須知道它的總大小并稍后將其提供給MPI_SendRecv.

但是在分配之后,您必須確保aabb成員被正確初始化以指向分配的記憶體塊內。

一個可能的代碼可能是:

void allocateSendRecv(int count, int subCount) {
    int iter;

    // total size of each struct
    size_t sz = sizeof(struct cell)   2 * subCount * sizeof(double);

    // one single contiguous allocation
    Send_r = malloc(count * sz); // nota: never cast malloc in C language!

    // per each cell make aa and bb point into the allocated memory
    for (iter = 0; iter < count; iter  ) {
        Send_r[iter].aa = ((double*)(Send_r   count))   2 *  subCount * iter;
        Send_r[iter].bb = Send_r[iter].aa   subCount;
    }

    // id. for Send_l
    Send_l = malloc(count * sz);
    for (iter = 0; iter < count; iter  ) {
        Send_l[iter].aa = ((double*)(Send_l   count))   2 * subCount * iter;
        Send_l[iter].bb = Send_l[iter].aa   subCount;
    }
}

在這里,我首先是cell結構陣列,然后是 1 個aa陣列和每個結構 1 個bb陣列

這足以擺脫分段錯誤......

uj5u.com熱心網友回復:

您可以使用匿名struct,但有一些注意事項:

#define CELL(n) \
struct { \
    double a, b, c, aa[n], bb[]; \
}

限制是您不能按原樣使用全域變數,并且必須傳遞void *給子例程(然后在主體內強制轉換)。如果需要全域變數,只能使用宣告為的指標void *

例如

#define CELL(n) \
struct { \
    double a, b, c, aa[n], bb[]; \
}

void * Send_r;

void allocateCells(int count, int sAS) {
    Send_r = malloc (count * sizeof(CELL(sAS)); // no cast here
}

void fillCells(void * _cells, int count, int sAS, double dummyDouble) {
    int iter = 0;
    int iter2= 0;

    printf("Filling!\n");

    CELL(sAS) * cells = _cells;

    for (iter = 0; iter < count; iter  ) {
        cells[iter].a = dummyDouble;
        cells[iter].b = dummyDouble;
        cells[iter].c = dummyDouble;
        for (iter2 = 0; iter2 < sAS; iter2  ) {
            cells[iter].aa[iter2] = dummyDouble;
            cells[iter].bb[iter2] = dummyDouble;
        }
}

int main() {
    int sAS = 5;
    int iter = 0;
    allocate(count, sAS);
    fill(Send_r, count, sAS, 5.0);
}    

uj5u.com熱心網友回復:

單一的全域struct

struct cell
{
    double a, b, c, *aa, *bb;
} * Send_l, *Send_r;

有點脆弱:

  • aa并被bb分配為陣列,doublesubCount -1大小不存在。它被隱藏在代碼中。
  • Send_l并且Send_r也是指向陣列的指標,struct cellcount大小不存在。它也隱藏在代碼中。單一struct是全球性的,它也很弱。

這使得測驗、分配或釋放資料變得困難。我將使用一些封裝留下一個C示例,您可以在MPI. 我將使用您的代碼和函式,并帶有一些面向 OOP 的知識:)

該示例包括 2 個程式和函式來序列化和反序列化資料為了進行測驗,第一個程式將資料寫入檔案并由第二個程式讀回。同樣printSendRecv()顯示了資料寫入磁盤之前和之后的資料。

一種Cell結構

typedef struct
{
    double  a;
    double  b;
    double  c;
    double* aa; 
    double* bb;

} Cell;

Send結構_

typedef struct
{
    Cell     l;
    Cell     r;

} Send;

Set結構_


typedef struct
{
    unsigned count;
    unsigned subCount;
    Send*    send;

} Set;

所以 aSet具有描述其內容所需的一切。

函式原型

Set* allocateSendRecv(size_t, size_t);
int  fillSendRecv(Set*);
Set* freeSendRecv(Set*);
int  printSendRecv(Set*, const char*);

使用封裝和一點RAIIfromC 你可以重寫as 的建構式allocateSendRecv()freeSendRecv()解構式struct

Set* allocateSendRecv(size_t count, size_t subCount)
{
    // count is the number of send buffers
    // subcount is the size of the arrays inside each cell
    printf(
        "AllocateSendRecv(count = %llu, subCount = %llu)\n", count,
        subCount);
    Set* nw      = (Set*)malloc(sizeof(Set));
    nw->count    = count;
    nw->subCount = subCount;
    nw->send     = (Send*)malloc(count * sizeof(Send));
    // now that we have Send allocate the Cell arrays
    for (size_t i = 0; i < count; i  )
    {
        nw->send[i].l.aa =
            (double*)malloc(subCount * sizeof(double));
        nw->send[i].l.bb =
            (double*)malloc(subCount * sizeof(double));
        nw->send[i].r.aa =
            (double*)malloc(subCount * sizeof(double));
        nw->send[i].r.bb =
            (double*)malloc(subCount * sizeof(double));
    }
    return nw;
}

Set* freeSendRecv(Set* set)
{
    if (set == NULL) return NULL;
    printf(
        "\nDeallocating(count = %llu, subCount = %llu)\n",
        set->count, set->subCount);

    for (size_t i = 0; i < set->count; i  )
    {
        free(set->send[i].l.aa);
        free(set->send[i].l.bb);
    }
    free(set->send);
    free(set);
    return NULL;
}

以這種方式撰寫tst指標在對 的呼叫中無效freeSendRecv()在這種情況下tst,分配了countandsubCount作為 2 和 5,這進入了Set. fillSendRecv()使用增量填充值可以很容易地確定一些最終的位移。printSendRecv()接受可選訊息的字串。值在創建之前和之后列印Set

示例:序列化序列化緩沖區

連載()

為了首先寫入磁盤或傳輸資料aabb必須擴展陣列。該示例用于使用這些值v2-out x y 4 file創建和顯示 a struct,然后寫入 if tofile

int  main(int argc, char** argv)
{
    char   f_name[256] = {0};
    if (argc < 3) usage();
    strcpy(f_name, argv[3]);
    size_t count    = atoll(argv[1]);
    size_t subCount = atoll(argv[2]);

    Set* tst = allocateSendRecv(count,subCount);
    fillSendRecv(tst);
    printSendRecv(tst, "printSendRecv():    ");
    to_disk(tst, f_name);
    tst = freeSendRecv(tst);
    return 0;
}

這些函式接受Set并寫入檔案:

int    to_disk(Set*, const char*);
int    write_cell(Cell*, const size_t, FILE*);

反序列化()

由于Set具有重新創建所需的所有內容,因此Set只需要檔案名。該示例用于v2-in file讀取資料file并將其顯示在螢屏上

int  main(int argc,char** argv)
{
    char f_name[256] = {0};
    if (argc < 2) usage();
    strcpy(f_name, argv[1]);

    Set* tst = from_disk(f_name);
    printSendRecv(tst, "As read from disk:    ");
    tst = freeSendRecv(tst);
    return 0;
}

這些函式讀取檔案并回傳指向 a 的指標Set和資料:

Set*   from_disk(const char*);
int    read_cell(FILE*, Cell*, const size_t);

示例的輸出

這里的程式是

  • v2-out創建Set并寫入磁盤中的檔案
  • v2-in讀取由創建的檔案v2-out并加載到新的Set
  • dump.bin被創造并Set擁有count = 2subCount = 4
PS C:\SO>
PS C:\SO> .\v2-out 2 4 dump-2-4.bin
AllocateSendRecv(count = 2, subCount = 4)
FillSendRecv()
printSendRecv():        Count is 2, subCount is 4
        Set 1 of 2
        l:
        [a,b,c] = [    42.001,    42.002,    42.003]
        aa:     42.004     42.005     42.006     42.007
        bb:     42.008     42.009     42.010     42.011

        r:
        [a,b,c] = [    42.012,    42.013,    42.014]
        aa:     42.015     42.016     42.017     42.018
        bb:     42.019     42.020     42.021     42.022


        Set 2 of 2
        l:
        [a,b,c] = [    42.023,    42.024,    42.025]
        aa:     42.026     42.027     42.028     42.029
        bb:     42.030     42.031     42.032     42.033

        r:
        [a,b,c] = [    42.034,    42.035,    42.036]
        aa:     42.037     42.038     42.039     42.040
        bb:     42.041     42.042     42.043     42.044



writing 'Set' to "dump-2-4.bin"

Deallocating(count = 2, subCount = 4)



PS C:\SO> .\v2-in dump-2-4.bin

read 'Set' from "dump-2-4.bin"
From disk: Count = 2, SubCount = 4
AllocateSendRecv(count = 2, subCount = 4)
new 'Set' created
As read from disk:        Count is 2, subCount is 4
        Set 1 of 2
        l:
        [a,b,c] = [    42.001,    42.002,    42.003]
        aa:     42.004     42.005     42.006     42.007
        bb:     42.008     42.009     42.010     42.011

        r:
        [a,b,c] = [    42.012,    42.013,    42.014]
        aa:     42.015     42.016     42.017     42.018
        bb:     42.019     42.020     42.021     42.022


        Set 2 of 2
        l:
        [a,b,c] = [    42.023,    42.024,    42.025]
        aa:     42.026     42.027     42.028     42.029
        bb:     42.030     42.031     42.032     42.033

        r:
        [a,b,c] = [    42.034,    42.035,    42.036]
        aa:     42.037     42.038     42.039     42.040
        bb:     42.041     42.042     42.043     42.044




Deallocating(count = 2, subCount = 4)

2個檔案中的示例

標題v2.h

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
    double  a;
    double  b;
    double  c;
    double* aa;
    double* bb;

} Cell;

typedef struct
{
    Cell l;
    Cell r;

} Send;

typedef struct
{
    size_t count;
    size_t subCount;
    Send*    send;

} Set;

Set* allocateSendRecv(size_t, size_t);
int  fillSendRecv(Set*);
Set* freeSendRecv(Set*);
int  printSendRecv(Set*, const char*);
// helpers
Set*   from_disk(const char*);
double get_next(void);
int    print_cell(Cell*, size_t, const char*);
int    read_cell(FILE*, Cell*, const size_t);
int    to_disk(Set*, const char*);
int    write_cell(Cell*, const size_t, FILE*);

檔案中的代碼v2.c

#include "v2.h"
#include <stdio.h>
#pragma pack(show)

Set* allocateSendRecv(size_t count, size_t subCount)
{
    // count is the number of send buffers
    // subcount is the size of the arrays inside each cell
    printf(
        "AllocateSendRecv(count = %llu, subCount = %llu)\n", count,
        subCount);
    Set* nw      = (Set*)malloc(sizeof(Set));
    nw->count    = count;
    nw->subCount = subCount;
    nw->send     = (Send*)malloc(count * sizeof(Send));
    // now that we have Send allocate the Cell arrays
    for (size_t i = 0; i < count; i  )
    {
        nw->send[i].l.aa =
            (double*)malloc(subCount * sizeof(double));
        nw->send[i].l.bb =
            (double*)malloc(subCount * sizeof(double));
        nw->send[i].r.aa =
            (double*)malloc(subCount * sizeof(double));
        nw->send[i].r.bb =
            (double*)malloc(subCount * sizeof(double));
    }
    return nw;
}

int fillSendRecv(Set* s)
{
    printf("FillSendRecv()\n");
    if (s == NULL) return -1;

    for (size_t i = 0; i < s->count; i  = 1)
    {
        // l
        s->send[i].l.a = get_next();
        s->send[i].l.b = get_next();
        s->send[i].l.c = get_next();
        for (size_t j = 0; j < s->subCount; j  = 1)
            s->send[i].l.aa[j] = get_next();
        for (size_t j = 0; j < s->subCount; j  = 1)
            s->send[i].l.bb[j] = get_next();

        // r
        s->send[i].r.a = get_next();
        s->send[i].r.b = get_next();
        s->send[i].r.c = get_next();
        for (size_t j = 0; j < s->subCount; j  = 1)
            s->send[i].r.aa[j] = get_next();
        for (size_t j = 0; j < s->subCount; j  = 1)
            s->send[i].r.bb[j] = get_next();
    }
    return 0;
}

Set* freeSendRecv(Set* set)
{
    if (set == NULL) return NULL;
    printf(
        "\nDeallocating(count = %llu, subCount = %llu)\n",
        set->count, set->subCount);

    for (size_t i = 0; i < set->count; i  )
    {
        free(set->send[i].l.aa);
        free(set->send[i].l.bb);
    }
    free(set->send);
    free(set);
    return NULL;
}

int printSendRecv(Set* s, const char* msg)
{
    if (s == NULL) return -1;
    if (msg != NULL) printf("%s", msg);

    printf(
        "    Count is %llu, subCount is %llu\n", s->count,
        s->subCount);
    for (size_t i = 0; i < s->count; i  = 1)
    {
        printf("\tSet %llu of %llu\n", 1   i, s->count);
        print_cell(&s->send[i].l, s->subCount, "\tl:\n");
        print_cell(&s->send[i].r, s->subCount, "\tr:\n");
        printf("\n");
    }
    printf("\n");
    return 0;
}

// helpers

Set* from_disk(const char* file)
{
    printf("read 'Set' from \"%s\"\n", file);
    FILE* in = fopen(file, "rb");
    if (in == NULL) return NULL;
    size_t res = 0;

    size_t count      = 0;
    res               = fread(&count, sizeof(count), 1, in);
    size_t subCount   = 0;
    res = fread(&subCount, sizeof(subCount), 1, in);
    printf("From disk: Count = %llu, SubCount = %llu\n",
        count,subCount);
    Set* nw = allocateSendRecv(count, subCount);
    if (nw == NULL)
    {
        fclose(in);
        return NULL;  // could not alloc
    }
    printf("new 'Set' created\n");
    nw->count    = count;
    nw->subCount = subCount;

    // so we have the exact structure to hold ALL data
    for (size_t i = 0; i < nw->count; i  = 1)
    {
        read_cell(in, &nw->send[i].l, nw->subCount);
        read_cell(in, &nw->send[i].r, nw->subCount);
    }
    fclose(in);
    return nw;
}

double get_next(void)
{
    static double ix = 42.;
    ix  = .001;
    return ix;
}

int print_cell(Cell* cell, size_t sz, const char* msg)
{
    printf(
        "%s\t[a,b,c] = [.3f,.3f,.3f]\n", msg,
        cell->a, cell->b, cell->c);
    printf("\taa: ");
    for (size_t j = 0; j < sz; j  = 1)
        printf(".3f ", cell->aa[j]);
    printf("\n\tbb: ");
    for (size_t j = 0; j < sz; j  = 1)
        printf(".3f ", cell->bb[j]);
    printf("\n\n");
    return 0;
}

int read_cell(FILE* in, Cell* cell, const size_t size)
{
    if (in == NULL) return -2;
    if (cell == NULL) return -1;
    size_t res = 0;
    // a,b,c,aa,bb
    res  = fread(&cell->a, 1, 3 * sizeof(double), in);
    res  = fread(cell->aa, 1, size * sizeof(double), in);
    res  = fread(cell->bb, 1, size * sizeof(double), in);
    return 0;
}

int to_disk(Set* set, const char* file)
{
    printf("writing 'Set' to \"%s\"\n", file);
    FILE* out = fopen(file, "wb");
    if (out == NULL) return -1;
    size_t res = 0;
    res = fwrite(&set->count, sizeof(set->count), 1, out);
    res = fwrite(&set->subCount, sizeof(set->subCount), 1, out);
    for (size_t i = 0; i < set->count; i  = 1)
    {
        write_cell(&set->send[i].l, set->subCount, out);
        write_cell(&set->send[i].r, set->subCount, out);
    }
    fclose(out);
    return 0;
}

int write_cell(Cell* cell, const size_t size, FILE* out)
{
    if (cell == NULL) return -1;
    if (out == NULL) return -2;
    size_t res = 0;
    // a,b,c, aa, bb
    res  = fwrite(&cell->a, 1, 3 * sizeof(double), out);
    res  = fwrite(cell->aa, 1, size * sizeof(double), out);
    res  = fwrite(cell->bb, 1, size * sizeof(double), out);
    //printf("write_cell(): %llu bytes written to disk\n", res);
    return 0;
}

main()上面的 2 個例子在文本中

鑄造回報malloc()

是的,我總是malloc()像我和許多其他人一樣不喜歡任何暗示的回報。并且還因為malloc()接受任何計算結果為大小的運算式,并且在運算式中并不總是說明該區域。很多時候,程式為許多結構分配資料,其中一些是封閉的。這個小程式有3個。所以使用演員表可以提醒程式員程式打算分配什么,并且可以避免很多錯誤,因為多次表達不足以顯示什么是什么。
關于這件事malloc()并且 cast 來自 C-FAQ,這是一個從未更新過的舊東西,它是 usenet 上所有 2000 年之前的文章的匯編。即使在那個時候,人們也在那里寫了關于 CAST 指標的可能原因。(C-FAQ)[https://c-faq.com/malloc/sd3.html] 中支持強制轉換的原因之一是它可以提醒程式員忘記使用includefor stdlib.h我是認真的:

Suppose that you call malloc but forget to #include <stdlib.h>.
The compiler is likely to assume that malloc is a function
returning int, which is of course incorrect, and will lead to trouble
Therefore, the seemingly redundant casts are used by people who are
(a) concerned with portability to all pre-ANSI compilers, or
(b) of the opinion that implicit conversions are a bad thing.

我會添加我上面描述的原因。

轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/518370.html

標籤:C结构mpi连续的

上一篇:訪問字符指標

下一篇:如何在C語言中將數字視為值1?

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • CA和證書

    1、在 CentOS7 中使用 gpg 創建 RSA 非對稱密鑰對 gpg --gen-key #Centos上生成公鑰/密鑰對(存放在家目錄.gnupg/) 2、將 CentOS7 匯出的公鑰,拷貝到 CentOS8 中,在 CentOS8 中使用 CentOS7 的公鑰加密一個檔案 gpg -a ......

    uj5u.com 2020-09-10 00:09:53 more
  • Kubernetes K8S之資源控制器Job和CronJob詳解

    Kubernetes的資源控制器Job和CronJob詳解與示例 ......

    uj5u.com 2020-09-10 00:10:45 more
  • VMware下安裝CentOS

    VMware下安裝CentOS 一、軟硬體準備 1 Centos鏡像準備 1.1 CentOS鏡像下載地址 下載地址 1.2 CentOS鏡像下載程序 點擊下載地址進入如下圖的網站,選擇需要下載的版本,這里選擇的是Centos8,點擊如圖所示。 決定選擇Centos8后,選擇想要的鏡像源進行下載,此 ......

    uj5u.com 2020-09-10 00:12:10 more
  • 如何使用Grep命令查找多個字串

    如何使用Grep 命令查找多個字串 大家好,我是良許! 今天向大家介紹一個非常有用的技巧,那就是使用 grep 命令查找多個字串。 簡單介紹一下,grep 命令可以理解為是一個功能強大的命令列工具,可以用它在一個或多個輸入檔案中搜索與正則運算式相匹配的文本,然后再將每個匹配的文本用標準輸出的格式 ......

    uj5u.com 2020-09-10 00:12:28 more
  • git配置http代理

    git配置http代理 經常遇到克隆 github 慢的問題,這里記錄一下幾種配置 git 代理的方法,解決 clone github 過慢。 目錄 git配置代理 git單獨配置github代理 git配置全域代理 配置終端環境變數 git配置代理 主要使用 git config 命令 git單獨 ......

    uj5u.com 2020-09-10 00:12:33 more
  • Linux npm install 裝包時提示Error EACCES permission denied解

    npm install 裝包時提示Error EACCES permission denied解決辦法 ......

    uj5u.com 2020-09-10 00:12:53 more
  • Centos 7下安裝nginx,使用yum install nginx,提示沒有可用的軟體包

    Centos 7下安裝nginx,使用yum install nginx,提示沒有可用的軟體包。 18 (flaskApi) [root@67 flaskDemo]# yum -y install nginx 19 已加載插件:fastestmirror, langpacks 20 Loading ......

    uj5u.com 2020-09-10 00:13:13 more
  • Linux查看服務器暴力破解ssh IP

    在公網的服務器上經常遇到別人爆破你服務器的22埠,用來挖礦或者干其他嘿嘿嘿的事情~ 這種情況下正確的做法是: 修改默認ssh的22埠 使用設定密鑰登錄或者白名單ip登錄 建議服務器密碼為復雜密碼 創建普通用戶登錄服務器(root權限過大) 建立堡壘機,實作統一管理服務器 統計爆破IP [root ......

    uj5u.com 2020-09-10 00:13:17 more
  • CentOS 7系統常見快捷鍵操作方式

    Linux系統中一些常見的快捷方式,可有效提高操作效率,在某些時刻也能避免操作失誤帶來的問題。 ......

    uj5u.com 2020-09-10 00:13:31 more
  • CentOS 7作業系統目錄結構介紹

    作業系統存在著大量的資料檔案資訊,相應檔案資訊會存在于系統相應目錄中,為了更好的管理資料資訊,會將系統進行一些目錄規劃,不同目錄存放不同的資源。 ......

    uj5u.com 2020-09-10 00:13:35 more
最新发布
  • vim的常用命令

    Vim的6種基本模式 1. 普通模式在普通模式中,用的編輯器命令,比如移動游標,洗掉文本等等。這也是Vim啟動后的默認模式。這正好和許多新用戶期待的操作方式相反(大多數編輯器默認模式為插入模式)。 2. 插入模式在這個模式中,大多數按鍵都會向文本緩沖中插入文本。大多數新用戶希望文本編輯器編輯程序中一 ......

    uj5u.com 2023-04-20 08:43:21 more
  • vim的常用命令

    Vim的6種基本模式 1. 普通模式在普通模式中,用的編輯器命令,比如移動游標,洗掉文本等等。這也是Vim啟動后的默認模式。這正好和許多新用戶期待的操作方式相反(大多數編輯器默認模式為插入模式)。 2. 插入模式在這個模式中,大多數按鍵都會向文本緩沖中插入文本。大多數新用戶希望文本編輯器編輯程序中一 ......

    uj5u.com 2023-04-20 08:42:36 more
  • docker學習

    ###Docker概述 真實專案部署環境可能非常復雜,傳統發布專案一個只需要一個jar包,運行環境需要單獨部署。而通過Docker可將jar包和相關環境(如jdk,redis,Hadoop...)等打包到docker鏡像里,將鏡像發布到Docker倉庫,部署時下載發布的鏡像,直接運行發布的鏡像即可。 ......

    uj5u.com 2023-04-19 09:26:53 more
  • 設定Windows主機的瀏覽器為wls2的默認瀏覽器

    這里以Chrome為例。 1. 準備作業 wsl是可以使用Windows主機上安裝的exe程式,出于安全考慮,默認情況下改功能是無法使用。要使用的話,終端需要以管理員權限啟動。 我這里以Windows Terminal為例,介紹如何默認使用管理員權限打開終端,具體操作如下圖所示: 2. 操作 wsl ......

    uj5u.com 2023-04-19 09:25:49 more
  • docker學習

    ###Docker概述 真實專案部署環境可能非常復雜,傳統發布專案一個只需要一個jar包,運行環境需要單獨部署。而通過Docker可將jar包和相關環境(如jdk,redis,Hadoop...)等打包到docker鏡像里,將鏡像發布到Docker倉庫,部署時下載發布的鏡像,直接運行發布的鏡像即可。 ......

    uj5u.com 2023-04-19 09:19:04 more
  • Linux學習筆記

    IP地址和主機名 IP地址 ifconfig可以用來查詢本機的IP地址,如果不能使用,可以通過install net-tools安裝。 Centos系統下ens33表示主網卡;inet后表示IP地址;lo表示本地回環網卡; 127.0.0.1表示代指本機;0.0.0.0可以用于代指本機,同時在放行設 ......

    uj5u.com 2023-04-18 06:52:01 more
  • 解決linux系統的kdump服務無法啟動的問題

    問題:專案麒麟系統服務器的kdump服務無法啟動,沒有相關日志無法定位問題。 1、查看服務狀態是關閉的,重啟系統也無法啟動 systemctl status kdump 2、修改grub引數,修改“crashkernel”為“512M(有的機器數值太大太小都會導致報錯,建議從128M開始試,或者加個 ......

    uj5u.com 2023-04-12 09:59:50 more
  • 解決linux系統的kdump服務無法啟動的問題

    問題:專案麒麟系統服務器的kdump服務無法啟動,沒有相關日志無法定位問題。 1、查看服務狀態是關閉的,重啟系統也無法啟動 systemctl status kdump 2、修改grub引數,修改“crashkernel”為“512M(有的機器數值太大太小都會導致報錯,建議從128M開始試,或者加個 ......

    uj5u.com 2023-04-12 09:59:01 more
  • 你是不是暴露了?

    作者:袁首京 原創文章,轉載時請保留此宣告,并給出原文連接。 如果您是計算機相關從業人員,那么應該經歷不止一次網路安全專項檢查了,你肯定是收到過資訊系統技術檢測報告,要求你加強風險監測,確保你提供的系統服務堅實可靠了。 沒檢測到問題還好,檢測到問題的話,有些處理起來還是挺麻煩的,尤其是線上正在運行的 ......

    uj5u.com 2023-04-05 16:52:56 more
  • 細節拉滿,80 張圖帶你一步一步推演 slab 記憶體池的設計與實作

    1. 前文回顧 在之前的幾篇記憶體管理系列文章中,筆者帶大家從宏觀角度完整地梳理了一遍 Linux 記憶體分配的整個鏈路,本文的主題依然是記憶體分配,這一次我們會從微觀的角度來探秘一下 Linux 內核中用于零散小記憶體塊分配的記憶體池 —— slab 分配器。 在本小節中,筆者還是按照以往的風格先帶大家簡單 ......

    uj5u.com 2023-04-05 16:44:11 more