首页 > 解决方案 > 同时用 int 和 string 填充数组

问题描述

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
int main()
{

    srand(time(NULL));

    char hex[]="0123456789ABCDEF";
    char seferNo[]="";
    char numaraDeposu[100][6];
    int j=0;
    for (j=0;j<10;j++)
    {
        char seferNo[]="";
        for (int i=0;i<4;i++)
        {
            int a;
            a=(rand() % 15);
            strncat(seferNo,&hex[a],1);
        }
        strcpy(numaraDeposu[j],seferNo);

        printf("%s\n",numaraDeposu[j]);
    }
}

这工作正常,但我想要 numaraDeposu 二维数组中的数字和字符串(代码)第一维包括 int,第二维包括我的随机代码(完美的英语)

1(随机码)2(随机码)3(随机码)4(随机码)这样

标签: c

解决方案


如评论中所述,您char seferNo[]="";是一个大小为 1 的数组,它只能包含空字符串 ( '\0') 并且仍被视为字符串。您的调用strncpy()调用未定义的行为,因为没有足够的空间'\0'来写入字符。

您可以使用 2D 数组执行您正在尝试的操作,并且无需包含string.h. 您可以通过简单的字符操作来完成这一切stdio.h sprintf(),例如

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

int main (void) {

    srand(time(NULL));

    const char hex[]="0123456789ABCDEF";
    char numaraDeposu[100][6] = {""};
    
    for (int i = 0; i < 100; i++) {
        numaraDeposu[i][0] = hex[rand() % 16];
        sprintf (&numaraDeposu[i][1], "c%03d", rand()%1000);
        
        printf ("%s\n", numaraDeposu[i]);
    }
}

示例使用/输出

$ ./bin/numardeposu2D
Fc598
7c569
Ec247
1c451
Fc172
0c558
Bc501
0c462
Ec318
Ac396
2c742
0c304
4c146
...

当你需要一个持有不同类型的对象时使用结构体

每当您需要将不同类型作为单个对象进行协调时,您应该考虑struct. 在这里,由于您将 2D 数组的每个字符串元素中的第一个字符限制为单个字符,char因此并不完全需要。但是,它将为您在访问第一个字符和剩余代码的方式上提供更多的灵活性。

您可以使用一个简单的结构,例如:

typedef struct {
    unsigned char hexnum;
    char code[7];
} deposu_type;

选择Anunsigned char只是为了使类型不同,但您可以同时使用char两者。然后,您将声明一个结构数组并为数组中的每个结构填充每个成员,例如

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

typedef struct {
    unsigned char hexnum;
    char code[7];
} deposu_type;

int main (void) {

    srand(time(NULL));

    const char hex[]="0123456789ABCDEF";
    deposu_type numaraDeposu[100] = {{ .hexnum = 0 }};
    
    for (int i = 0; i < 100; i++) {
        numaraDeposu[i].hexnum = hex[rand() % 16];
        sprintf (numaraDeposu[i].code, "c%03d", rand()%1000);
        
        printf ("%c %s\n", numaraDeposu[i].hexnum, numaraDeposu[i].code);
    }
}

示例使用/输出

hexnum在和成员之间显示一个空格,code以强调单独引用每个成员的便利性。

$ ./bin/numardeposu_struct
A c190
7 c329
D c955
7 c761
6 c968
D c781
8 c985
9 c449
7 c708
F c893
E c799
E c168

两种解决方案大致等效,但如果您的示例变得更复杂,使用structand 数组将是更简单的解决方案。struct

如果您还有其他问题,请仔细查看并告诉我。


根据需要为尽可能多的 numaraDeposu 动态分配存储

为了回应您关于如何为无限数量的对象分配存储空间的评论(我将其视为未知数字,因为您没有无限的可用内存),您将动态分配存储空间以保存所有numaraDeposu使用malloc(),calloc()realloc().

动态分配存储并不难。首先,为一些合理的数字结构分配存储空间,并将内存块的地址分配给指针变量。例如在这里,让我们为2struct分配存储deposu_type并将结果分配给我们的指针numaraDeposu,例如

    size_t  available = 2,      /* no. of struct available */
            used = 0;           /* no. of struct used */
    
    /* allocate memory for initial (2) struct available */
    deposu_type *numaraDeposu = malloc (available * sizeof *numaraDeposu);
    
    if (numaraDeposu == NULL) {             /* validate EVERY allocation */
        perror ("malloc-numaraDeposu");
        return 1;
    }

注意:您必须始终检查返回以验证您的分配成功或失败并处理任何失败)

您始终为分配保留两个计数器变量。available计数器保存当前numaraDeposu可以放入分配的内存块的used数量,并跟踪您已填充(使用)的数量。当(used == available)您重新分配更大的内存块并更新数量时available。一个常见的增长模式是每次您需要更多可用数量时增加一倍,但您可以随意添加任意数量或任意数量。

一个为其分配存储的简单示例numaraDeposu可以编写如下。使用这种方法,您可以根据numaraDeposu需要分配任意数量的内存,直到用完物理内存:

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

typedef struct {
    unsigned char hexnum;
    char code[7];
} deposu_type;

int main (void) {

    const char hex[]="0123456789ABCDEF";
    size_t  available = 2,      /* no. of struct available */
            used = 0;           /* no. of struct used */
    
    srand(time(NULL));
    
    /* allocate memory for initial (2) struct available */
    deposu_type *numaraDeposu = malloc (available * sizeof *numaraDeposu);
    
    if (numaraDeposu == NULL) {             /* validate EVERY allocation */
        perror ("malloc-numaraDeposu");
        return 1;
    }
    
    for (; used < 100; used++) {
        if (used == available) {    /* reallocate more when (used == available) */
            /* always reallocate using temporary pointer */
            void *tmp = realloc (numaraDeposu, 2 * available * sizeof *numaraDeposu);
            if (!tmp) {                     /* valdate EVERY reallocation */
                perror ("realloc-numaraDeposu");
                break;
            }
            numaraDeposu = tmp;     /* assign reallocated block to pointer */
            available *= 2;         /* updaate no. of struct available */
        }
        numaraDeposu[used].hexnum = hex[rand() % 16];
        sprintf (numaraDeposu[used].code, "c%03d", rand()%1000);
        
        printf ("%c %s\n", numaraDeposu[used].hexnum, numaraDeposu[used].code);
    }
    
    free (numaraDeposu);            /* free all allocated memory */
}

内存使用/错误检查

在您编写的任何动态分配内存的代码中,对于分配的任何内存块,您有 2 个责任:(1)始终保留指向内存块起始地址的指针,(2)它可以在它不存在时被释放更需要。

您必须使用内存错误检查程序,以确保您不会尝试访问内存或写入超出/超出分配块的边界,尝试读取或基于未初始化值的条件跳转,最后确认释放所有分配的内存。

对于 Linuxvalgrind是正常的选择。每个平台都有类似的内存检查器。它们都易于使用,只需通过它运行您的程序即可。

$ valgrind ./bin/numardeposu_struct_dyn
==13231== Memcheck, a memory error detector
==13231== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==13231== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==13231== Command: ./bin/numardeposu_struct_dyn
==13231==
C c582
A c524
4 c742
1 c697
5 c890
...
6 c509
A c079
2 c511
0 c770
==13231==
==13231== HEAP SUMMARY:
==13231==     in use at exit: 0 bytes in 0 blocks
==13231==   total heap usage: 8 allocs, 8 frees, 3,056 bytes allocated
==13231==
==13231== All heap blocks were freed -- no leaks are possible
==13231==
==13231== For counts of detected and suppressed errors, rerun with: -v
==13231== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

始终确认您已释放所有已分配的内存并且没有内存错误。

如果您还有其他问题,请告诉我。


推荐阅读