分段错误(核心转储)——这个错误只是有时出现,我似乎无法修复它
Segmentation fault (core dumped) - this error is shown only sometimes and I cannot seem to fix it
我在这里和其他地方看到过许多不同的论坛,但我似乎找不到我的代码有什么问题。我没有指针,所以它只能是我正在使用的数组的东西 - 我试图改变它们并看看会发生什么,试图写下正在发生的事情和时间但有时仍然会显示错误。我只知道它与内存和访问我不应该访问的内容有关,但无法确定问题 - 可能更多。
#include <stdio.h>
#include <math.h>
typedef int bool;
#define true 1
#define false 0
int main(int argc, char *argv[]){
int number;
int test;
while ((test = scanf("%d", &number)) == 1){
if (number == 0){
return 0;
}
if (number < 0){
fprintf(stderr, "Error: Chybny vstup!\n");
return 100;
}
printf("Prvociselny rozklad cisla %d je:\n", number);
if (number == 1){
printf("%d", number);
}
else{
bool prime[number+1];
for(int i = 0; i <= number; i++){
prime[i] = true;
}
for(int j = 2; j * j <= number; j++){
if (prime[j] == true){
for (int multiples = 2; prime[j * multiples] <= number; multiples++){
prime[j * multiples] = false;
}
}
}
int result[50];
int multipliers[50];
for(int i = 0; i <= 50; i++){
result[i] = 0;
}
for(int i = 0; i <= 50; i++){
multipliers[i] = 1;
}
int counter = 0;
for (int test=2; test <= number; test++){
if (prime[test]){
if (number % test == 0){
number /= test;
result[counter] = test;
counter++;
while(number % test == 0){
multipliers[counter-1]++;
number /= test;
}
}
}
}
for (int c = 0; c < counter; c++){
if (multipliers[c] > 1){
printf("%d^%d", result[c], multipliers[c]);
}
if (multipliers[c] == 1){
printf("%d", result[c]);
}
if (result[c+1] > 1){
printf(" x ");
}
}
}
printf("\n");
}
if (test == 0){
fprintf(stderr, "Error: Chybny vstup!\n");
return 100;
}
}
您应该始终做的是分段编写您的程序,并在完成每个功能后验证它是否正常工作,然后再转向新功能。由于您随后分别测试了要实现的每个功能,因此您知道任何错误最有可能出现在您最后实现的功能中。
在你的情况下,这个问题立即引起了我的注意:
for (int multiples = 2; prime[j * multiples] <= number; multiples++){
prime[j * multiples] = false;
}
在这里,您测试 prime[j * multiples] <= number
,即将 标志 与数字进行比较。因为延迟标志在数组末尾之前都被归零,j*multiples
将超出 prime[]
数组的范围,并最终使您的程序崩溃。
当然要考j * multiples <= number
因为我一次处理一个功能和一个问题,所以我不知道这是否是您的代码存在的唯一问题。找出答案是你的任务。如果我是你,我会分段编写代码,可能会在测试时加入 printf()
s,以验证每个部分是否有效,这样我就可以依赖我已经编写的代码,并专注于手头的部分,并以最小的挫败感稳步前进。
最近关于埃拉托色尼筛子的问题比较多。我一直发现实现一个抽象的、动态分配的筛选类型和简单的 accessor/modifier 函数来改变它很有用。因为一个程序中应该只有一个筛子,所以可以用全局变量来描述:
#include <stdlib.h>
#include <inttypes.h>
#include <limits.h>
#include <string.h>
#include <stdio.h>
/* This is the number of bits in an unsigned long.
The exact value is floor(log(ULONG_MAX + 1)/log(2)),
but the following definition will be correct on all
modern architectures: */
#define ULONG_BITS (sizeof (unsigned long) * CHAR_BIT)
/* Prime sieve, with a flag for zero and each odd integer,
one bit per flag. */
static unsigned long *sieve = NULL;
/* Largest positive integer within the sieve. */
static uint64_t sieve_max = 4;
/* Number of unsigned longs allocated and initialized in the sieve. */
static size_t sieve_words = 0;
/* Function to discard the sieve, if no longer needed. */
static inline void sieve_free(void)
{
free(sieve); /* free(NULL); is safe, and does nothing. */
sieve = NULL;
sieve_max = 4; /* Since 0, 1, 2, 3, 4 give built-in answers */
sieve_words = 0;
}
最初的sieve_max
是4,因为我们的is_prime()
测试函数处理0、1、2和3个素数,所有更大的偶数无论如何都不是素数;这意味着我们的 is_prime()
:
始终知道整数 0 到 4
/* Return 1 if number is prime according to sieve,
0 if known composite/not prime. */
static inline int is_prime(const uint64_t number)
{
/* 0, 1, 2, and 3 are considered prime. */
if (number <= 3)
return 1; /* Prime */
/* All larger even integers are not prime. */
if (!(number & 1))
return 0; /* Not prime */
/* Outside the sieve? */
if (number > sieve_max) {
fprintf(stderr, "is_prime(): %" PRIu64 " is outside the sieve!\n", number);
exit(EXIT_FAILURE);
}
{
const uint64_t half = number / 2;
const size_t w = half / ULONG_BITS;
const unsigned long m = 1uL << (half % ULONG_BITS);
/* The flag for odd number is (number/2)th.
half / ULONG_BIT is the word where bit
half % ULONG_BIT is in.
Return 0 if the bit is set, 1 if clear. */
return !(sieve[w] & m);
}
}
我们可以很容易地扩大筛子,将所有新标志默认为 "not prime":
static void sieve_upto(const uint64_t max)
{
/* Number of words needed for (max+1)/2 bits. */
const uint64_t nwords = 1 + max / (2 * ULONG_BITS);
const uint64_t nbytes = nwords * (uint64_t)sizeof (unsigned long);
const size_t words = (size_t)nwords;
const size_t bytes = words * sizeof (unsigned long);
unsigned long *temp;
/* Already covered by the current sieve? */
if (sieve_max > max)
return;
/* We need to be able to handle max+1,
and neither bytes or words should overflow. */
if (max >= UINT64_MAX ||
(uint64_t)words != nwords || (uint64_t)bytes != nbytes) {
fprintf(stderr, "sieve_upto(): %" PRIu64 " is too high a maximum.\n", max);
exit(EXIT_FAILURE);
}
/* Do we already have all the bytes we need? */
if (words == sieve_words) {
sieve_max = max;
return;
}
/* Allocate/reallocate. Note that realloc(NULL, size)
is equivalent to malloc(size), so this is safe
even if 'sieve' is NULL. */
temp = realloc(sieve, bytes);
if (!temp) {
fprintf(stderr, "Not enough memory for a sieve up to %" PRIu64 ".\n", max);
exit(EXIT_FAILURE);
}
sieve = temp;
/* Clear the new words to all zeros. */
memset(sieve + sieve_words, 0, (words - sieve_words) * sizeof (unsigned long));
sieve_max = max;
sieve_words = words;
}
最后,我们需要一个函数来标记合数(非质数):
static inline void not_prime(const uint64_t number)
{
/* Primality is internally handled for 0, 1, 2, 3, and 4. */
if (number <= 4)
return;
/* All larger even numbers are internally handled. */
if (!(number & 1))
return;
/* Outside the sieve? */
if (number > sieve_max) {
fprintf(stderr, "not_prime(): %" PRIu64 " is outside the sieve!\n", number);
exit(EXIT_FAILURE);
}
{
const uint64_t half = number / 2;
const size_t w = half / ULONG_BITS;
const unsigned long m = 1uL << (half % ULONG_BITS);
/* Half is the bit index in sieve[].
half / ULONG_BITS is the word containing the bit
half % ULONG_BITS that needs to be set. */
sieve[w] |= m;
}
}
Eratosthenes 构造的筛子我将留给你;我的目的只是展示如何使用动态内存管理创建和管理相对高效(即平衡内存使用和 运行 时间)奇数正整数筛选。
(Verifying 在我的笔记本电脑上,一个简单的 Eratosthenes 筛法找到所有 455,052,511 个小于 10,000,000,000 的素数只用了不到 90 秒,而它找到所有 203,280,221 个 32 位素数用了不到 30 秒,使用一个单核,和上面的函数。对于更高的范围,最好使用开窗筛。注意素数计数函数不考虑0和1素数,不像上面is_prime()
.)
我在这里和其他地方看到过许多不同的论坛,但我似乎找不到我的代码有什么问题。我没有指针,所以它只能是我正在使用的数组的东西 - 我试图改变它们并看看会发生什么,试图写下正在发生的事情和时间但有时仍然会显示错误。我只知道它与内存和访问我不应该访问的内容有关,但无法确定问题 - 可能更多。
#include <stdio.h>
#include <math.h>
typedef int bool;
#define true 1
#define false 0
int main(int argc, char *argv[]){
int number;
int test;
while ((test = scanf("%d", &number)) == 1){
if (number == 0){
return 0;
}
if (number < 0){
fprintf(stderr, "Error: Chybny vstup!\n");
return 100;
}
printf("Prvociselny rozklad cisla %d je:\n", number);
if (number == 1){
printf("%d", number);
}
else{
bool prime[number+1];
for(int i = 0; i <= number; i++){
prime[i] = true;
}
for(int j = 2; j * j <= number; j++){
if (prime[j] == true){
for (int multiples = 2; prime[j * multiples] <= number; multiples++){
prime[j * multiples] = false;
}
}
}
int result[50];
int multipliers[50];
for(int i = 0; i <= 50; i++){
result[i] = 0;
}
for(int i = 0; i <= 50; i++){
multipliers[i] = 1;
}
int counter = 0;
for (int test=2; test <= number; test++){
if (prime[test]){
if (number % test == 0){
number /= test;
result[counter] = test;
counter++;
while(number % test == 0){
multipliers[counter-1]++;
number /= test;
}
}
}
}
for (int c = 0; c < counter; c++){
if (multipliers[c] > 1){
printf("%d^%d", result[c], multipliers[c]);
}
if (multipliers[c] == 1){
printf("%d", result[c]);
}
if (result[c+1] > 1){
printf(" x ");
}
}
}
printf("\n");
}
if (test == 0){
fprintf(stderr, "Error: Chybny vstup!\n");
return 100;
}
}
您应该始终做的是分段编写您的程序,并在完成每个功能后验证它是否正常工作,然后再转向新功能。由于您随后分别测试了要实现的每个功能,因此您知道任何错误最有可能出现在您最后实现的功能中。
在你的情况下,这个问题立即引起了我的注意:
for (int multiples = 2; prime[j * multiples] <= number; multiples++){
prime[j * multiples] = false;
}
在这里,您测试 prime[j * multiples] <= number
,即将 标志 与数字进行比较。因为延迟标志在数组末尾之前都被归零,j*multiples
将超出 prime[]
数组的范围,并最终使您的程序崩溃。
当然要考j * multiples <= number
因为我一次处理一个功能和一个问题,所以我不知道这是否是您的代码存在的唯一问题。找出答案是你的任务。如果我是你,我会分段编写代码,可能会在测试时加入 printf()
s,以验证每个部分是否有效,这样我就可以依赖我已经编写的代码,并专注于手头的部分,并以最小的挫败感稳步前进。
最近关于埃拉托色尼筛子的问题比较多。我一直发现实现一个抽象的、动态分配的筛选类型和简单的 accessor/modifier 函数来改变它很有用。因为一个程序中应该只有一个筛子,所以可以用全局变量来描述:
#include <stdlib.h>
#include <inttypes.h>
#include <limits.h>
#include <string.h>
#include <stdio.h>
/* This is the number of bits in an unsigned long.
The exact value is floor(log(ULONG_MAX + 1)/log(2)),
but the following definition will be correct on all
modern architectures: */
#define ULONG_BITS (sizeof (unsigned long) * CHAR_BIT)
/* Prime sieve, with a flag for zero and each odd integer,
one bit per flag. */
static unsigned long *sieve = NULL;
/* Largest positive integer within the sieve. */
static uint64_t sieve_max = 4;
/* Number of unsigned longs allocated and initialized in the sieve. */
static size_t sieve_words = 0;
/* Function to discard the sieve, if no longer needed. */
static inline void sieve_free(void)
{
free(sieve); /* free(NULL); is safe, and does nothing. */
sieve = NULL;
sieve_max = 4; /* Since 0, 1, 2, 3, 4 give built-in answers */
sieve_words = 0;
}
最初的sieve_max
是4,因为我们的is_prime()
测试函数处理0、1、2和3个素数,所有更大的偶数无论如何都不是素数;这意味着我们的 is_prime()
:
/* Return 1 if number is prime according to sieve,
0 if known composite/not prime. */
static inline int is_prime(const uint64_t number)
{
/* 0, 1, 2, and 3 are considered prime. */
if (number <= 3)
return 1; /* Prime */
/* All larger even integers are not prime. */
if (!(number & 1))
return 0; /* Not prime */
/* Outside the sieve? */
if (number > sieve_max) {
fprintf(stderr, "is_prime(): %" PRIu64 " is outside the sieve!\n", number);
exit(EXIT_FAILURE);
}
{
const uint64_t half = number / 2;
const size_t w = half / ULONG_BITS;
const unsigned long m = 1uL << (half % ULONG_BITS);
/* The flag for odd number is (number/2)th.
half / ULONG_BIT is the word where bit
half % ULONG_BIT is in.
Return 0 if the bit is set, 1 if clear. */
return !(sieve[w] & m);
}
}
我们可以很容易地扩大筛子,将所有新标志默认为 "not prime":
static void sieve_upto(const uint64_t max)
{
/* Number of words needed for (max+1)/2 bits. */
const uint64_t nwords = 1 + max / (2 * ULONG_BITS);
const uint64_t nbytes = nwords * (uint64_t)sizeof (unsigned long);
const size_t words = (size_t)nwords;
const size_t bytes = words * sizeof (unsigned long);
unsigned long *temp;
/* Already covered by the current sieve? */
if (sieve_max > max)
return;
/* We need to be able to handle max+1,
and neither bytes or words should overflow. */
if (max >= UINT64_MAX ||
(uint64_t)words != nwords || (uint64_t)bytes != nbytes) {
fprintf(stderr, "sieve_upto(): %" PRIu64 " is too high a maximum.\n", max);
exit(EXIT_FAILURE);
}
/* Do we already have all the bytes we need? */
if (words == sieve_words) {
sieve_max = max;
return;
}
/* Allocate/reallocate. Note that realloc(NULL, size)
is equivalent to malloc(size), so this is safe
even if 'sieve' is NULL. */
temp = realloc(sieve, bytes);
if (!temp) {
fprintf(stderr, "Not enough memory for a sieve up to %" PRIu64 ".\n", max);
exit(EXIT_FAILURE);
}
sieve = temp;
/* Clear the new words to all zeros. */
memset(sieve + sieve_words, 0, (words - sieve_words) * sizeof (unsigned long));
sieve_max = max;
sieve_words = words;
}
最后,我们需要一个函数来标记合数(非质数):
static inline void not_prime(const uint64_t number)
{
/* Primality is internally handled for 0, 1, 2, 3, and 4. */
if (number <= 4)
return;
/* All larger even numbers are internally handled. */
if (!(number & 1))
return;
/* Outside the sieve? */
if (number > sieve_max) {
fprintf(stderr, "not_prime(): %" PRIu64 " is outside the sieve!\n", number);
exit(EXIT_FAILURE);
}
{
const uint64_t half = number / 2;
const size_t w = half / ULONG_BITS;
const unsigned long m = 1uL << (half % ULONG_BITS);
/* Half is the bit index in sieve[].
half / ULONG_BITS is the word containing the bit
half % ULONG_BITS that needs to be set. */
sieve[w] |= m;
}
}
Eratosthenes 构造的筛子我将留给你;我的目的只是展示如何使用动态内存管理创建和管理相对高效(即平衡内存使用和 运行 时间)奇数正整数筛选。
(Verifying 在我的笔记本电脑上,一个简单的 Eratosthenes 筛法找到所有 455,052,511 个小于 10,000,000,000 的素数只用了不到 90 秒,而它找到所有 203,280,221 个 32 位素数用了不到 30 秒,使用一个单核,和上面的函数。对于更高的范围,最好使用开窗筛。注意素数计数函数不考虑0和1素数,不像上面is_prime()
.)