【问题标题】:Can I use the uint64_t in a for block?我可以在 for 块中使用 uint64_t 吗?
【发布时间】:2016-04-07 12:42:14
【问题描述】:

所以我正在尝试编写一个代码来查找 10 000 000 000 000 之前的所有素数。所以我在某些变量中使用uint64_t。我还想将结果放在纯文本文件中,听起来很容易。或者这就是我的想法。我用

编译代码
gcc -lm --std=c11 primenumbers.c -o primes

我收到 0 个错误或警告……对我有好处!但是当我执行程序时,我收到了可怕的错误消息

分段错误(核心转储)

起初我认为可能是我没有正确分配字符串的内存,所以当我需要使字符串变大时,我继续在任何地方使用malloc()/free(0,不,它仍然保留出现了。

代码如下:

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdbool.h>
#include <inttypes.h>
#include <stdlib.h>

bool test_number(uint64_t c);

int main(void){
    uint64_t b = 10000000000000;
    uint64_t i;
    char *s = " ";
    char *helper = "";
    char *helper_two;
    char *helper_three;
    int format = 0;

    FILE *ptrPrimes;


    for(i = 2; i <= b; i++){
        if (test_number(i)){
            format++;
            sprintf(helper_three, "%llu", i);
            helper = malloc(strlen(s));
            helper_two = malloc(sizeof(strlen(helper_three)) + 1);
            sprintf(helper_two, " %s", helper_three);
            strcpy(helper, s);
            free(s);
            if(format % 120 == 0){
                s = malloc(sizeof(helper) + sizeof(helper_two) + 1);
                sprintf(s, "%s%s\n", helper, helper_two);
            }else{
                s = malloc(sizeof(helper) + sizeof(helper_two));
                sprintf(s, "%s%s", helper, helper_two);
            }
            free(helper);
            free(helper_two);
            helper_three = NULL;
        }        
    }

    if((ptrPrimes = fopen("primenumbers.txt", "w")) != NULL){
        fprintf(ptrPrimes, "%s", s);
    }else{
        printf("Sorry mate, an error curred\n");
    }

    return 0;
}

bool test_number(uint64_t c){
    uint64_t i;
    c = sqrt(c);
    for(i = 2; i <= c; i++){
        if(c % i == 0) return false;        
    }
    return true;
}

然后我认为这可能是在 for 标头中使用了uint64_t。那么您认为这可能是什么错误?

编辑

我尝试了所有建议以及我自己的一些建议,现在代码如下所示:

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <inttypes.h>
#include <stdlib.h>
#include <stdbool.h>

bool test_number(uint64_t c);

int main(void){
    uint64_t b = 10000000000000;
    uint64_t i;
    char *s;
    char *helper;
    char *helper_two;
    char *helper_three;
    uint64_t format = 0;

    FILE *ptrPrimes;


    for(i = 2; i <= b; i++){
        if (test_number(i)){
            printf("%llu\n", i);
            format++;
            helper_three = malloc(sizeof(char) * snprintf(NULL, 0, "%llu", i));
            sprintf(helper_three, "%llu", i);
            helper = malloc(sizeof(char) * strlen(s));
            helper_two = malloc(sizeof(char) * strlen(helper_three) + 1);
            sprintf(helper_two, " %s", helper_three);
            strcpy(helper, s);
            if(format % 120 == 0){
                s = malloc(sizeof(char) * strlen(helper) + sizeof(char) * strlen(helper_two) + 1);
                sprintf(s, "%s%s\n", helper, helper_two);
            }else{
                s = malloc(sizeof(char) * strlen(helper) + sizeof(char) * strlen(helper_two));
                sprintf(s, "%s%s", helper, helper_two);
            }
            free(helper);
            free(helper_two);
            free(helper_three);
        }        
    }

    if((ptrPrimes = fopen("primenumbers.txt", "w")) != NULL){
        fprintf(ptrPrimes, "%s", s);
    }else{
        printf("Sorry mate, an error curred\n");
    }

    return 0;
}

bool test_number(uint64_t c){
    uint64_t i;
    uint64_t b = sqrt(c);
    for(i = 2; i <= b; i++){
        if(!(i % 2) && i != 2) continue;
        if(c % i == 0) return false;        
    }
    return true;
}

在数字 29 之后一切正常,出于某种原因(显然)我收到了以下错误消息:

2
3
5
7
11
13
17
19
23
29

* `./primes' 中的错误:free():下一个大小无效(快速):0x000000000258f100 *

======= 回溯:========= /lib64/libc.so.6(+0x77e35)[0x7f8f212abe35]
/lib64/libc.so.6(+0x8051a)[0x7f8f212b451a]
/lib64/libc.so.6(cfree+0x4c)[0x7f8f212b7ccc]
./primes[0x400a8f]
/lib64/libc.so.6(__libc_start_main+0xf0)[0x7f8f21254580] ./primes[0x4007b9] ======= 内存映射:======== 00400000-00401000 r-xp 00000000 fd:02 13507592 /home/lain/primes 00601000-00602000 r--p 00001000 fd:02 13507592
/home/lain/primes 00602000-00603000 rw-p 00002000 fd:02 13507592
/home/lain/primes 0258f000-025b0000 rw-p 00000000 00:00 0
[堆] 7f8f1c000000-7f8f1c021000 rw-p 00000000 00:00 0 7f8f1c021000-7f8f20000000 ---p 00000000 00:00 0 7f8f2101d000-7f8f21033000 r-xp 00000000 fd:00 789942
/usr/lib64/libgcc_s-5.3.1-201 7f8f21033000-7f8f21232000 ---p 00016000 fd:00 789942 /usr/lib64/libgcc_s-5.3.1-201 7f8f21232000-7f8f21233000 r--p 00015000 fd:00 789942
/usr/lib64/libgcc_s-5.3.1-201 7f8f21233000-7f8f21234000 rw-p 00016000 fd:00 789942 /usr/lib64/libgcc_s-5.3.1-201 7f8f21234000-7f8f213eb000 r-xp 00000000 fd:00 788930
/usr/lib64/libc-2.22.so 7f8f213eb000-7f8f215eb000 ---p 001b7000 fd:00 788930 /usr/lib64/libc-2.22.so 7f8f215eb000-7f8f215ef000 r--p 001b7000 fd:00 788930
/usr/lib64/libc-2.22.so 7f8f215ef000-7f8f215f1000 rw-p 001bb000 fd:00 788930 /usr/lib64/libc-2.22.so 7f8f215f1000-7f8f215f5000 rw-p 00000000 00:00 0 7f8f215f5000-7f8f216f6000 r-xp 00000000 fd:00 788938
/usr/lib64/libm-2.22.so 7f8f216f6000-7f8f218f5000 ---p 00101000 fd:00 788938 /usr/lib64/libm-2.22.so 7f8f218f5000-7f8f218f6000 r--p 00100000 fd:00 788938
/usr/lib64/libm-2.22.so 7f8f218f6000-7f8f218f7000 rw-p 00101000 fd:00 788938 /usr/lib64/libm-2.22.so 7f8f218f7000-7f8f21918000 r-xp 00000000 fd:00 788921
/usr/lib64/ld-2.22.so 7f8f21ad3000-7f8f21ad6000 rw-p 00000000 00:00 0 7f8f21b14000-7f8f21b17000 rw-p 00000000 00:00 0 7f8f21b17000-7f8f21b18000 r--p 00020000 fd:00 788921
/usr/lib64/ld-2.22.so 7f8f21b18000-7f8f21b19000 rw-p 00021000 fd:00 788921 /usr/lib64/ld-2.22.so 7f8f21b19000-7f8f21b1a000 rw-p 00000000 00:00 0 7fffa035b000-7fffa037d000 rw-p 00000000 00:00 0
[堆栈] 7fffa0381000-7fffa0383000 r--p 00000000 00:00 0
[vvar] 7fffa0383000-7fffa0385000 r-xp 00000000 00:00 0
[vdso] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0
[vsyscall]

我不太明白为什么在 29 点之前一切正常。

【问题讨论】:

  • free(s); - 第一次执行此行时,字符串s 指向静态内存。
  • 编译所有警告和调试信息 (g++ -std=c++11 -Wall -Wextra -g) 然后使用调试器 (gdb) 找出段错误在哪里
  • 或者,更好的是,使用 C++ 字符串重写所有代码。
  • @kfx 你为什么要这么说?是c 不是c++,你能告诉我在c 程序中使用c++ 字符串的方法吗?
  • @kfx 你可以说应该使用 haskell 或 python 来代替......尝试开始语言战争真的没有意义。这个网站的工作方式是 OP 询问了一个关于如何用 C 编码的问题,所以答案应该是关于用 C 编码的。没人关心你个人使用不同的语言。

标签: c string pointers memory-management


【解决方案1】:

这很令人不安

sizeof(strlen(...));

那里不需要sizeof

但几乎所有malloc()s 都以错误的方式分配空间。如果要预测sprintf() 的长度,请尝试snprintf()0 长度为NULL 目标缓冲区,请检查返回值。

【讨论】:

  • selfautofacepalm 我正在尝试一些解决方案,但我完全忘记了改变一些事情。
【解决方案2】:

在您的代码中,

  sprintf(helper_three, "%llu", i);

helper_three 未分配任何内存。因此,helper_three 指向的内存位置本质上不是有效。任何访问无效内存的尝试都会调用undefined behavior。分段错误是副作用之一。

您需要在写入之前将内存分配给helper_three

之后,

 helper_two = malloc(sizeof(strlen(helper_three)) + 1);

大错特错。你需要的是

helper_two = malloc(strlen(helper_three) + 1);

然后,sizeof(helper) 和其他 sizeof(pointer) 无法按您预期的方式工作。在指针上使用sizeof 计算的是指针本身的大小,而不是分配给指针的内存量。如果这些指针包含一个字符串,您需要使用strlen() 来获取大小。

【讨论】:

  • 那也错了,我需要的是:helper_two = malloc(sizeof(char) * (strlen(helper_three) + 1))
【解决方案3】:

好的,我得到了这个答案:

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <inttypes.h>
#include <stdlib.h>
#include <stdbool.h>

bool test_number(uint64_t c);

int main(void){
    uint64_t b = 9223372036854775783;
    uint64_t i;
    char *s;
    char *helper;
    char *helper_two;
    char *helper_three;
    uint64_t format = 0;

    FILE *ptrPrimes;


    for(i = 2; i <= b; i++){
        if (test_number(i) == true){
            //printf("%llu", i);
            format++;
            helper_three = malloc(sizeof(char) * snprintf(NULL, 0, "%llu", i));
            sprintf(helper_three, "%llu ", i);
            helper_two = malloc(sizeof(char) * (strlen(helper_three) + 1));
            strcpy(helper_two, helper_three);
            if (format == 1){
                s = malloc(sizeof(char));
                sprintf(s, "%s", helper_three);
               }else{
                if (s != NULL){
                    helper = malloc(sizeof(char) * (strlen(s) +1));
                    strcpy(helper, s);
                    free(s);
                    if(format % 120 == 0){
                        s = malloc(sizeof(char) * strlen(helper) + sizeof(char) * (strlen(helper_two) + 1) +1);
                        strcpy(s, helper);
                        strcat(s, helper_two);
                        strcat(s, "\n");
                    }else{
                        s = malloc(sizeof(char) * strlen(helper) + sizeof(char) * (strlen(helper_two) + 1));
                        strcpy(s, helper);
                        strcat(s, helper_two);
                    }
                }
            }
            free(helper);
            free(helper_two);
            free(helper_three);
        }        
    }

    if((ptrPrimes = fopen("primenumbers.txt", "w")) != NULL){
        fprintf(ptrPrimes, "%s", s);
    }else{
        printf("Sorry mate, an error ocurred\n");
    }

    return 0;
}

bool test_number(uint64_t c){
    uint64_t i;
    uint64_t b = sqrt(c);

    switch(c){
        case 1:
            return false;
        case 2:
            return true;
    }

    if(c % 2 == 0) return false;

    for(i = 3; i <= b; i += 2){
        if(c % i == 0) return false;
    }
    return true;
}

我只是想重新学习 C(11) 的一些概念,所以没有必要优化代码,这从来都不是我的意图(即使我调整了 test_number 函数)。不过还是谢谢大家的帮助。

我总是需要使用sizeofstrlensizeof 来获取系统上字符的大小,并使用 strlen 来获取字符串的长度(显然),这样我才能获得合适的内存量保存字符串。我不应该只单独使用strlen。我会为一个未知的结构获取内存(字符串长度的大小,无论如何都没有意义)。

我最大的错误之一是我没有考虑字符串中的 '\0' 字符。 strlen 似乎忽略了它(畏缩)。再次感谢您的帮助。

附:如果您使用clang,您会因为“%llu”格式说明符而收到警告。我发现它很有趣,尽管clang 对某些功能的支持会比gcc 更大。不想在编译器之间引发战争,两者都是很棒的工具,只是:工具

【讨论】:

    猜你喜欢
    • 2021-11-08
    • 2013-08-14
    • 2012-02-13
    • 1970-01-01
    • 2022-01-02
    • 2020-03-26
    • 2013-11-04
    • 2016-08-01
    • 1970-01-01
    相关资源
    最近更新 更多