Click here to Skip to main content
14,826,846 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hello. I use C to do a simple game.
I have an array like this one:

| | | | | | ....... and between "|" I want to run a for loop to blink "*"

inside "|" in random positions of array ,but I receive this error:
Segmentation fault (core dumped)

I haven't finished it yet.

Code:

What I have tried:

C++
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>


int pos_rand(char *array);


int main(void)
{
    char *array[21];
    for (int i = 0; i <= 9; i++)
    {
        printf(" ");
    }

    *(array + pos_rand(*array)) = "*";
    
    for (int i = 0; i <= 20; i++)
    {
        if(i % 2 == 0 && strcmp(*(array + i) , "*") != 0)
        {
             *(array + i) = " | ";
        }
        
        else if(strcmp(*(array + i) , "*") != 0)
        {
             *(array + i) = " ";
        }
    }
    
    for (int i = 0; i <= 20; i++)
    {
        printf("%s" , *(array + i));
    }
    
    printf("\n\nPosition:    ");

    for (int i = 1; i <= 10; i++)
    {
        printf("%d   " , i);
    }
    printf("\n\n");
}


int pos_rand(char *array)
{
    srand(time(NULL));    
    return (rand() % 10) * 2 + 1;   // recieve an odd random number between 1 to 21.
}



I can't understand where the problem is...

Thanks for your help!!!
Posted
Updated 13-Aug-20 8:26am

The problem in your code is the line
char *array[21];
defines an array of char pointers (or strings), however those pointers aren't initialized, and there is no memory behind them. To get that fixed, you might have to do something like a loop with a malloc for each array element.


IMHO it would be easier to keep the logic and the display of the game separate.

In the logic, you have an array of cells, each having only a few possible states; you could model that with an array of integers.

When displaying, you would then have to iterate that array and build a string from substrings such as " | " and "*".

And if you use (a) some constants/defines and (b) bracket-style array accesses, everything becomes much more readable. as in:

#define EMPTY 0
#define STAR 1
#define BAR 2
#define CELLCOUNT 10

int array[2*CELLCOUNT+1];
char mystring[4*CELLCOUNT];

for(int i=0; i<=CELLCOUNT ; i++) array[2*i]=BAR;
for(int i=0; i<CELLCOUNT ; i++) array[2*i+1]=EMPTY;
array[rand_pos()]=STAR;

mystring[0]=0;
for(int i=0; i<2*CELLCOUNT+1; i++) {
    switch(array[i]) {
        case BAR:
            strcat(mystring, " | ");
            break;
        case STAR:
            strcat(mystring, "*");
            break;
        case EMPTY:
            strcat(mystring, " ");
            break;
    }
}
   
v4
There's so much here, it's hard to know where to start, but lets begin here:
c
int pos_rand(char *array)
{
    srand(time(NULL));    
    return (rand() % 10) * 2 + 1;   // recieve an odd random number between 1 to 21.
}

First off, there doesn't seem to be any point to the argument char *array as array is not used anywhere in the array.
Secondly, srand() is only used to seed the random number generator, and would normally only be used once per program. Consider the following program:
C
#include <stdlib.h>
#include <time.h>

int getrand()
{
    srand(time(NULL));
    return rand();
}


int main()
{
    for(int i = 0; i < 10; ++i)
        printf("%d\n", getrand());

    return 0;
}
The output for this program might look like this:
$ ./example
1824823912
1824823912
1824823912
1824823912
1824823912
1824823912
1824823912
1824823912
1824823912
$
What's happening here is that rand() gets its starting point reset every time, so as long as the call to getrand() is within the same second on the clock, it will return the same value.

Then there's this usage: *(array + i). Unless you're working on an obfuscated C program, that's not how you would typically access the i'th element of an array. The normal way to do it is array[i]

Next make sure you've compiled your program with -g option (adds in info for debugger) e.g. gcc -Wall -Wextra -g myprog.c -o myprog
Then use gdb to take examine what's going on
You may want to look at the gdb documentation and find out how to run a program, get the backtrace, change frames and print the values of variables.
   
Not the question, but ...
This code retruns an odd random number between 1 to 19.
C++
return (rand() % 10) * 2 + 1;   // recieve an odd random number between 1 to 21.

change to
C++
return (rand() % 11) * 2 + 1;

to get desired result.
   
Comments
jeron1 12-Aug-20 18:26pm
   
Which, if equal to 21 would result in an out of bounds index of the array as it is currently written.
Patrice T 12-Aug-20 18:33pm
   
code an comment are inconsistent
jeron1 12-Aug-20 18:48pm
   
indeed
Luc Pattyn 12-Aug-20 18:26pm
   
I disagree, he only wants 10 different results from the random function, the array holds 10 cells and 11 walls surrounding those 10 cells.

It is his comment that is confusing, should have been
return (rand() % 10) * 2 + 1;   // return an odd random number in [1,19]
I will just address the random number issue. Firstly, there are (at least) two ways to seed the random number generator (RNG). Pseudo-randomly or with a fixed number. For game purposes, it is often useful to use a fixed number so you can come back and use the same sequence of random values. You can call this the game number as is often done in card games. The pseudo-random way is to use the time. If you use srand and rand, the random values will range from 0 to RAND_MAX which is usually 32,767. Here is a little function that will seed the RNG for you :
C++
typedef unsigned short USHORT;

#define PSEUDO_RANDOM_SEED 0

void SeedRNG( USHORT seedVal )
{
    USHORT seed = seedVal;
    if( seedVal == PSEUDO_RANDOM_SEED )
    {
        time_t now = time( NULL );
        seed = (USHORT)( now % RAND_MAX );
    }
    srand( seed );
}
That will allow you to see the RNG either way - pseudo-randomly by passing 0 or in a repeated way by passing a non-zero value.

It is important to seed the RNG only one time.

Here is a handy random number generation function. You can specify the range of values you want to span.
C++
int GetRandomInt( int minval, int maxval )
{
    int range = maxval - minval + 1;
    int value = rand() % range;   // limit the value to the range of interest
    return range + minval;        // offset it by minimum to get it into the ROI
}
Lastly, here is how you can use them.
C++
void Testem()
{
    const int valueCount = 20;
    int value;

    SeedRNG( PSEUDO_RANDOM_SEED );

    for( int n = 0; n < valueCount; ++n )
    {
        value = GetRandomInt( 10, 90 );
        printf( "value %2d is %2d\n", n + 1, value );
    }
}
This little sample should print twenty random values ranging between 10 to 90.
   
Thank you all guys.I used malloc and free and it worked.
Now I want to "blink" the star "*" between "|" ,but I want to generate odd random numbers without being repeated in successive positions:
For example ,I use a for loop,so:
If i = 1 ,then I generate an odd random number in [1 , 19].
When i = 2 ,I want to generate an odd random number between [1 , 19],except previous number(i = 1).
When i = 3, I 'm able to use the number of (loop: i = 1) ,but not number in
(loop: i = 2) ,etc...


I thought and tried something but doesnn't work good and it sticks.
Whole code:

C++
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>


int pos_rand(char *array);
void delay(int number_of_seconds);
void run(char *array);
int change_pos(char *array , int ps);


int main(void)
{
    char *array;
    for(int i = 1; i <= 10; i++)
    {
        run(array);
        system("clear");
    }
    
}


int pos_rand(char *array)
{
    srand(time(NULL));    
    return (rand() % 10) * 2 + 1;   // recieve an odd random number between 1 to 19.
}




void delay(int number_of_seconds) 
{ 
    // Converting time into milli_seconds 
    int milli_seconds = 1000 * number_of_seconds; 
  
    // Storing start time 
    clock_t start_time = clock(); 
  
    // looping till required time is not achieved 
    while (clock() < start_time + milli_seconds); 
} 


void run(char *array)
{
    printf("Array:");
    for (int i = 0; i <= 7; i++)
    {
        printf(" ");
    }

    array = malloc(sizeof(char) * 21);
    if(!array)
    {
        printf("ERROR\n");
        exit(0);
    }

    for(int i = 0; i <= 9; i++)
    {
        array[ change_pos(array , i) ] = '*';
    }
    
    
    
    for (int i = 0; i <= 20; i++)
    {

        if(i % 2 == 0 && array[i] != '*')
        {
            array[i] = '|';
        }
        
        else if(array[i] != '*')
        {
            array[i] = ' ';
        }
    }
    
    for (int i = 0; i <= 20; i++)
    {
        printf("%c" , array[i]);
    }
    
    printf("\n\nPosition:      ");

    for (int i = 1; i <= 10; i++)
    {
        printf("%d " , i);
    }
    delay(300);
    printf("\n");
    for (int i = 0; i <= 20; i++)
    {
        array[i] = ' ';
    }

    printf("\n");
    free(array);
}



int change_pos(char *array , int ps)
{
    int *arr_pos;
    int previous;
    
    arr_pos = malloc(sizeof(int) * 10);
    do
    {
        previous = pos_rand(array);
        arr_pos[ps] = previous;
    }
    while(arr_pos[previous] == arr_pos[previous + 1]);
    free(arr_pos);
    return previous;
}
   
To new question:
Quote:
Now I want to "blink" the star "*" between "|" ,but I want to generate odd random numbers without being repeated in successive positions:

Random numbers without repeat are not random!
Think of a deck of cards, you shuffle all the deck at once, then you draw cards 1 by 1. when all cards draw, shuffle again.
Shuffling - Wikipedia[^]
Fisher–Yates shuffle - Wikipedia[^]
   

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900