I am facing some problems with the output of the following program. The program randomly generate words, first a random consonant then a random vowel, and then the same again for the maximum number of letters you want.
When I print the word generated right after it is generated it gives me a list of words, as intended. When I am out of the word generating and stacking loop, and print an output of the words again, I get all the words mashed up in one long chain, it is really bizarre. What is wrong?
#include <stdio.h>
#define MAXWORDS 10
#define MAXLETTERS 6
int lcg(int Xcur) /*linear congruential generator*/
{
int A = 445, C = 700001, M = 2097152;
int Xnext = (A * Xcur + C) % M;
return Xnext;
}
int main()
{
int x;
printf("input seed for linear congruential generator: ");
scanf("%d",&x);
char consonants[]="bcdfghjklmnprstvwxz";
char vowels[]="aeiou";
int i,j;
int turn;
char words[MAXWORDS][MAXLETTERS];
for(i=0;i<MAXWORDS;i++)
{
turn=1;
for(j=0;j<MAXLETTERS;j++,turn++)
{
x=lcg(x); /* random number generated */
if(turn%2) /* one consonant, one vowel, in turn */
words[i][j]=consonants[x%19];
else
words[i][j]=vowels[x%5];
}
words[i][j]='\0';
/* print each word generated */
printf("word %d: %s\n", i+1, words[i]);
}
/* print the first word again */
printf("\n\nthe 1st word again: %s\n",words[0]);
return 0;
}
output:
input seed for linear congruential generator: 23
word 1: wuduca
word 2: navozo
word 3: depiza
word 4: jukiti
word 5: raliwi
word 6: danila
word 7: cexewi
word 8: bamohu
word 9: jiruzi
word 10: temomo
the 1st word again: wuducanavozodepizajukitiraliwidanilacexewibamohujiruzitemomo
It is because is is getting stored in continuous manner without any null char.
Method 1:
If you just want to print it properly you can do it by writing below line:
printf("\n\nthe 1st word again: %s\n",words[0]);
as
printf("\n\nthe 1st word again: %.*s\n",MAXLETTERS, words[0]);
Method 2:
Declare words as
char words[MAXWORDS][MAXLETTERS+1];
and write the inside for loop as
for(j=0;j<MAXLETTERS;j++,turn++)
{
x=lcg(x); /* random number generated */
if(turn%2) /* one consonant, one vowel, in turn */
words[i][j]=consonants[x%19];
else
words[i][j]=vowels[x%5];
}
words[i][MAXLETTERS] = '\0';
There is no room in the array for the string terminator. Consequently writing the '\0' terminator is undefined behaviour. In practice (since a 2D array is contiguous), the terminator was written to the next string, which was then overwritten by its data.
Try changing
char words[MAXWORDS][MAXLETTERS];
to
char words[MAXWORDS][MAXLETTERS+1];
Also,
Watch out for int overflow.
Code does not insure 0 <= Xcur <= (INT_MAX - C)/A, so A * Xcur + C results can then exceed INT_MAX...
int A = 445, C = 700001, M = 2097152;
int Xnext = (A * Xcur + C) % M;
... resulting in UB: likely negative values can then return from the function.
x=lcg(x);
words[i][j]=consonants[x%19];
x%19 results then in -18 ... 18 leading to bad indexing.
Simple fix, yet does not address the root of the issue.
//Use %19u so the result is never < 0, unlike %19
words[i][j]=consonants[x%19u];
I would also use unsigned math to avoid UB of overflow and not generate negative results.
int lcg(int Xcur) /*linear congruential generator*/
{
unsigned A = 445, C = 700001, M = 2097152;
int Xnext = (A * Xcur + C) % M;
return Xnext;
}
Code also has issue with 16-bit int.
Related
my first post here.
I'm trying to write a program in C, which generates a random password made of numbers, letters and capitals. The problem is that characters in password must NOT be repeated. I tried a few ways to prevent that, but nothing seemed to work.
void createPassword() {
char password[LENGTH];
char nums[] = "0123456789";
char letters[] = "abcdefghijklmnopqrstuvwxyz";
char caps[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int selector = rand() % 3; //random choice of character type
int i;
printf("Vytvorene heslo: ");
for(i = 0;i < LENGTH;i++) {
if(selector == 1) { //if selector == 1, add number to password etc.
password[i] = nums[rand() % 10];
printf("%c", password[i]);
selector = rand() % 3;
}
else if(selector == 2) {
password[i] = letters[rand() % 26];
printf("%c", password[i]);
selector = rand() % 3;
}
else {
password[i] = caps[rand() % 26];
printf("%c", password[i]);
selector = rand() % 3;
}
}}
I'll be glad if someone could tell me what to do next.
Picking a random index of an array is the same as picking the values of a shuffled array sequentially. I used Fisher–Yates shuffle Algorithm for shuffling of the array. After generating a shuffled array, just pick the index of the next character from the shuffled array, and use symbols[] to access the corresponding character from it. Also. I used srand(time(0)) to give a random seed for the random number generator. Include time.h for using time(0).
void createPassword() {
char password[LENGTH];
int total = 10+26+26;
char symbols[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
int i;
int ar[total];
for(i = 0; i < total; i++){
ar[i] = i;
}
srand(time(0));
for (i = total-1; i >= 1; i--){
// get random 0 <= temp <= i
int temp = rand() % (i+1);
// Swap ar[temp] and ar[i]
int temp2 = ar[i];
ar[i] = ar[temp];
ar[temp] = temp2;
}
printf("Vytvorene heslo: ");
for(i = 0;i < LENGTH;i++) {
password[i] = symbols[ar[i]];
printf("%c", password[i]);
}
}
That's not a big deal, random seeds are similar for several runs in C.
You may need to set the random seed to time(0) by adding something like this, first of your code:
srand(time(0));
You should import time.h too.
#include <time.h>
Besides if you want to make a password consisting numbers and alphabets at the same time you may need to move selector assignment into the loop.
An easy way to force random numbers with no repeating letters can be implemented by using an array of elements, that will play the role of a card deck.
Each time you get a card, you get it from the rest of the deck (there's a point that differentiates cards that have been already xtracted with cards that are still to be output) You select a random number between 0 to n-1 where n-1 is the number of cards left in the deck. Once extracted, you switch the card extracted with the first of the group that is still to be extracted, and advance the point one position behind it, so it becomes already extracted and is not selected again.
A sample implementation is shown below, in the function extract, which uses an array of cells to store the available objects to print (they can be anything, they are char in the given implementation to be able to produce what you want ---random strings with non repeating characters):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
typedef char cell;
/* cell is a type (the above definition allows to be generic)
* array is the array of cards still to be output, n is its size.
* which is the card we select from the array, so it must be in
* range 0..n-1. */
cell extract(cell *array, size_t n, int which)
{
if (which) {
/* exchange position n with position 0 */
cell temp = array[0];
array[0] = array[which];
array[which] = temp;
}
return array[0];
}
/* this is a simple main program to illustrate how to use the
* function above. */
int main(int argc, char **argv)
{
unsigned N = 10;
unsigned seed = 0;
/* we use an array, because we need to modify it. */
char alpha[1024] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int opt;
int show_seed = 0;
while ((opt = getopt(argc, argv, "n:s:a:S")) != EOF) {
switch (opt) {
case 'n': N = atoi(optarg); break;
case 's': seed = atoi(optarg); break;
case 'S': show_seed = 1; break;
case 'a': strncpy(alpha, optarg, sizeof alpha); break;
}
}
if (seed) srand(seed);
else {
sranddev();
srand(seed = (unsigned)rand());
if (show_seed) {
fprintf(stderr,
"seed = %u\n",
seed);
}
}
argc -= optind;
argv += optind;
int len;
cell *pos;
for (pos = alpha, len = strlen(alpha);
*pos && len && N--;
pos++, len--)
{
putchar(extract(pos, len, rand() % len));
}
puts(""); /* final \n */
}
The program's usage is:
deck [ -a string ][ -S ][ -s seed ][ -n N ]
where:
-a allows you to specify the string where characters will be taken from. Defaults to ABCDEF...XYZ
-S prints the seed used in the run, so you can specify it to initialize the random number generator.
-s specifies a seed from a previous run to generate the same sequence. Defaults to a random initialization based on sranddev() (FreeBSD)
-n specifies the number of characters to select from the string. Defaults to 10.
A sample run is:
$ deck -s 123456
UKWOACYZLI
$ deck -s 123456 -n 26
UKWOACYZLITPJHQESVGMRBXFDN
$ _
As you see no character is repeated.
this is my first question on Stack Overflow, sorry if it's not well written.
I have a little problem. I wrote a program in C (I'm currently learning C, I am a newbie, my first language, don't say I should've learnt Python, please, because I'm doing just fine with C). So, I wrote this little program. It's an attempt of mine to implement a sorting algorithm (I made the algorithm myself, with no help or documentation, it's very inefficient I think, I was just fooling around, though I don't know whether the algorithm already exists or not). The only sorting algorithm I know is QuickSort.
In any case, here is the final program (has plenty of comments, to help me remember how it works if I'll ever revisit it):
// trying to implement my own sorting algorithm
// it works the following way:
// for an array of n integers, find the largest number,
// take it out of the array by deleting it, store it
// at the very end of the sorted array.
// Repeat until the original array is empty.
// If you need the original array, simply
// make a copy of it before sorting
/***************************************/
// second implementation
// same sorting algorithm
// main difference: the program automatically
// computes the number of numbers the user enters
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
int *sort(int *a, int n); // sort: the actual sorting function
char *read_line(char *str,int *num_of_chars); // read_line: reads input in string form
int *create_array(char *str, int n); // create_array: counts the num of integers entered and extracts them
// from the string the read_line function returns, forming an array
int size_of_array_to_be_sorted = 0; // of integers
int main(void)
{
int *array, i, *sorted_array, size = 3;
char *str = malloc(size + 1);
if (str == NULL)
{
printf("\nERROR: malloc failed for str.\nTerminating.\n");
exit(EXIT_FAILURE);
}
printf("Enter the numbers to be sorted: ");
str = read_line(str, &size);
array = create_array(str, size + 1);
sorted_array = sort(array, size_of_array_to_be_sorted);
printf("Sorted: ");
for (i = 0; i < size_of_array_to_be_sorted; i++)
printf("%d ", sorted_array[i]);
printf("\n\n");
return 0;
}
int *sort(int *a, int n)
{
int i, j, *p, *sorted_array, current_max;
sorted_array = malloc(n * (sizeof(int)));
if (sorted_array == NULL)
{
printf("ERROR: malloc failed in sort function.\nTerminating.\n");
exit(EXIT_FAILURE);
}
for (i = n - 1; i >= 0; i--) // repeat algorithm n times
{
current_max = a[0]; // intiliaze current_max with the first number in the array
p = a;
for (j = 0; j < n; j++) // find the largest integer int the array
if (current_max < a[j])
{
current_max = a[j];
p = (a + j); // make p point to the largest value found
}
*p = INT_MIN; // delete the largest value from the array
sorted_array[i] = current_max; // store the largest value at the end of the sorted_array
}
return sorted_array;
}
char *read_line(char *str, int *num_of_chars)
{
int i = 0; // num of chars initially
char ch, *str1 = str;
while ((ch = getchar()) != '\n')
{
str1[i++] = ch;
if (i == *num_of_chars) // gives str the possibility to
{ // dinamically increase size if needed
str1 = realloc(str, (*num_of_chars)++);
if (str1 == NULL)
{
printf("\nERROR: realloc failed in read_line.\nTerminating.\n");
exit(EXIT_FAILURE);
}
}
}
// at the end of the loop, str1 will contain the whole line
// of input, except for the new-line char. '\n' will be stored in ch
str1[i++] = ch;
str1[i] = '\0'; // store the null char at the end of the string
return str1;
}
int *create_array(char *str, int n)
{
int *array, i, j, k, num_of_ints = 0;
for (i = 0; i < n; i++) // computing number of numbers entered
if (str[i] == ' ' || str[i] == '\n')
num_of_ints++;
array = calloc((size_t) num_of_ints, sizeof(int)); // allocacting necessary space for the array
if (array == NULL)
{
printf("\nERROR: calloc failed in create_array.\nTerminating.\n");
exit(EXIT_FAILURE);
}
k = 0;
i = 1; // populating the array
for (j = n - 1; j >= 0; j--)
{
switch (str[j])
{
case '0': case '1': case '2':
case '3': case '4': case '5':
case '6': case '7': case '8':
case '9': array[k] += ((str[j] - '0') * i);
i *= 10;
break;
case '-': array[k] = -array[k]; // added to support negative integers
default: i = 1;
if (str[j] == ' ' && (str[j - 1] >= '0' && str[j - 1] <= '9'))
/* only increment k
*right before a new integer
*/
k++;
break;
}
}
// the loop works in this way:
// it reads the str string from the end
// if it finds a digit, it will try to extract it from the
// string and store in array, by adding to one of the elements
// of array the current char - ASCII for '0', so that it actually gets a digit,
// times the position of that digit in the number,
// constructing the number in base 10: units have 1, decimals 10, hundreds 100, and so on
// when it finds a char that's not a digit, it must be a space, so it resets i
// and increments k, to construct a new number in the next element of array
size_of_array_to_be_sorted = num_of_ints;
return array;
}
I've written everything myself, so if you think I use some bad methods or naive approaches or something, please tell me, in order for me to be able to correct them. Anyways, my problem is that I have these 'try to handle errors' if statements, after every call of malloc, calloc or realloc. I have a Linux machine and a Windows one. I wrote the program on the Linux one, which has 4GB of RAM. I wrote it, compiled with gcc, had to change a few things in order to make it work, and it runs flawlessly. I have no problem. I then copied it onto a USB drive and compiled it with mingw on my Windows machine, which has 8GB of RAM. I run it, and if I give it more than 3 2-digit integers, it displays
ERROR: realloc failed in read_line.
Terminating.
At least I know that the 'error handling' if statements work, but why does this happen? It's the same code, the machine has twice as much RAM, with most of it free, and it runs with no problem on Linux.
Does this mean that my code is not portable?
Is it something I don't do right?
Is the algorithm wrong?
Is the program very, very inefficient?
Sorry for the long question.
Thanks if you wanna answer it.
The line in question is:
str1 = realloc(str, (*num_of_chars)++);
where *num_of_chars is the current size of str. Because you are using post-increment, the value passed for the new allocation is the same as the current one, so you haven't made str any bigger, but go ahead and act as if you had.
I am like 3 weeks new at writing c code, so I am a newbie just trying some examples from a Harvard course video hosted online. I am trying to write some code that will encrypt a file based on the keyword.
The point is each letter of the alphabet will be assigned a numerical value from 0 to 25, so 'A' and 'a' will be 0, and likewise 'z' and 'Z' will be 25. If the keyword is 'abc' for example, I need to be able to convert it to its numerical form which is '012'. The approach I am trying to take (having learned nothing yet about many c functions) is to assign the alphabet list in an array. I think in the lecture he hinted at a multidimensional array but not sure how to implement that. The problem is, if the alphabet is stored as an array then the letters will be the actual values of the array and I'd need to know how to search an array based on the value, which I don't know how to do (so far I've just been returning values based on the index). I'd like some pseudo code help so I can figure this out. Thanks
In C, a char is an 8-bit integer, so, assuming your letters are in order, you can actually use the char value to get the index by using the first letter (a) as an offset:
char offset = 'a';
char value = 'b';
int index = value - offset; /* index = 1 */
This is hard to answer, not knowing what you've learned so far, but here's a hint to what I would do: the chars representing letters are bytes representing their ASCII values, and occur sequentially, from a to z and A to Z though they don't start at zero. You can cast them to ints and get the ascii values out.
Here's the pseudo code for how I'd write it:
Cast the character to a number
IF it's between the ascii values of A and Z, subtract it from A
ELSE Subtract it from the ASCII value of a or A
Output the result.
For what it's worth, I don't see an obvious solution to the problem that involves multidimensional arrays.
char '0' is the value 48
char 'A' is the value 65
char 'a' is the value 97
You said you want to learn how to search in the array:
char foo[26]; //your character array
...
...
//here is initialization of the array
for(int biz=0;biz<26;biz++)
{
foo[biz]=65+biz; // capital alphabet
}
...
...
//here is searching 1 by 1 iteration(low-yield)
char baz=67; //means we will find 'C'
for(int bar=0;bar<26;bar++)
{
if(foo[bar]==baz) {printf("we found C at the index: %i ",bar);break;}
}
//since this is a soted-array, you can use more-yield search algortihms.
Binary search algortihm(you may use on later chapters):
http://en.wikipedia.org/wiki/Binary_search_algorithm
The use of a multidimensional array is to store both the lower case and upper case alphabets in an array so that they can be mapped. An efficient way is using their ASCII code, but since you are a beginner, I guess this example will introduce you to handle for loops and multidimensional arrays, which I think is the plan of the instructor as well.
Let us first set up the array for the alphabets. We will have two rows with 26 alphabets in each row:
alphabetsEnglish[26][2] = {{'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'},
{'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'}};
Now we can map elements of both cases.
int main()
{
int c,i,j;
char word[10];
printf("Enter a word:");
scanf("%s",word);
c=strlen(word);
printf("Your word has %d letters ", c);
for (i = 0; i < c; i++) //loop for the length of your word
{
for (j = 0; j <= 25; j++) //second loop to go through your alphabet list
{
if (word[i] == alphabetsEnglish[0][j] || word[i] == alphabetsEnglish[1][j]) //check for both cases of your alphabet
{
printf("Your alphabet %c translates to %d: ", word[i], j);
}
}
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int *conv(char* str){
static const char* table = "abcdefghijklmnopqrstuvwxyz";
int size, *ret, *p;
if(NULL==str || *str == '\0') return NULL;
size = strlen(str);
ret=p=(int*)malloc(size*sizeof(int));
while(*str){
char *pos;
pos=strchr(table, tolower(*str++));
*p++ = pos == NULL ? -1 : pos - table;
}
return ret;
}
int main(void){
char *word = "abc";
int i, size = strlen(word), *result;
result = conv(word);
for(i=0;i<size;++i){
printf("%d ", result[i]);//0 1 2
}
free(result);
return 0;
}
I'm new to C and I was doing okay in my class(online) until the last couple of programs. They're getting more complicated and I'm not much of a strategist. But, I'm trying and I'm frustrated.
I've been working on this one for a while (it's past due) and my ulimate goal is to convert a number into words for a paycheck.
What I'm trying to do here is convert the double value to an int and put the int into a char array, so that eventually the "array amount" will read (if pay was $1234.56) 001234. Then I was thinking that I could do ifs or cases for each position (hundThous = 0, tenThous = 0, Thous = 1, etc..) to convert it. I'm getting stuck here, though and need help.
How do I put the value 1234 into the char array?
Also, in the function above, I called "checkWriter(money);" , where money is the double. Is that correct? I just want it to call this function to print the converted double to words.
void checkWriter(double z)
{
double v;
int w, y, cents;
int b, c, x, length;
char array[SIZE];
char amount[SIZE]; /*size = 7, our largest value will be in the hundred thousands*/
v = 100 * z; /*make z a whole number*/
w = ((int)v); /*convert z to an integer w*/
cents = w % 100; /*cents equals the remainder of w/100*/
y = (w - cents)/100; /*y equals the converted integer minus cents, divided by 100*/
sprintf(array, "%-6d", y); /* ATTEMPTING TO PUT y INTO array (saw this on google) */
printf("%s\n\n", array); /* Just wanted to see if it worked. It didn't. I got -2big
number.*/
length = strnlen(array); /*find length of the value in array*/
array[length] = '\0'; /* affix terminating null character to array */
b = SIZE - length - 1; /* b is amount of zeroes needed */
for(c = 0; c < length - 1; c++) { /* loops, plugging zeroes in amount until b=c,
then attaches array to amount */
if(b == c) {
amount[c] = '\0';
strcat(amount, array);
}
else {
amount[c] = '0';
}
}
printf("%s\n\n", amount); /* Checking to see if it worked. Nope. All zeroes. And
sometimes extra symbols at the end*/
return;
}
Would really appreciate help. Thank you!!!
Please, look at this and this articles.
Basically, you convert double to integer with rounding using
(int)double_value;
and then convert it to char array using
snprintf(arr, length, "%d", your_integer);
I have the following string:
char * strIn = "f2";
When I look at strIn[0] I would like to get 1111 instead of 'f'.
How do i do it?
Thanks
You mean a hex string to binary conversion?
strtol with a base of 16 should do the trick
...Someone said earlier
and f in binary would be 11001100
All I can say is wow... no, F in binary equals 1111 (15 decimal)
If I understood your question correctly, you want to get the binary value for any ascii character... ie.
When I look at strIn[0] I would like
to get 1111 instead of 'f'.
So... here is a little function that will do that...
int ConvertHexAsciiValue(char c)
{
if(isalpha(c))
{
char r = tolower(c);
if(r > 'f')
{
// - Handle error here - character is not base 16
return 0;
}
int nIndex = (int)('a' - r);
nIndex = -nIndex;
nIndex += 10;
return nIndex;
}
else if(isdigit(c))
{
int nIndex = c - '0';
return nIndex;
}
// Handle error here - character is not A-F or 0-9
return 0;
}
If I didn't understand you correctly, you should know that you cannot read a string "1111" for a character strIn[0]. You can however, get a binary value for each character (interpreted as a hexidecimal value) using the function I provided...
for(int x = 0; x < strlen(strIn); x++)
{
int val = ConvertHexAsciiValue(strIn[x]);
printf("Value %d: %d\n", x, val);
}
If strIn were set to "f2", this code would produce the following output on the console
Value 0: 15
Value 1: 2
To get the binary code one must take the decimal number in question, take it and divide it by two repeatedly, save the remainder (which will become the binary number), save the whole number, divide by two, and repeat the whole process until 0 is reached.
Heres a small application I had in my collection that converts a string into binary.
/********************************************************/
/* Binary converter */
/* By Matt Fowler */
/* philosopher150#yahoo.com */
/* converts text into binary using the division method */
/* through ASCII code */
/*compiled with the Dev-C++ compiler (www.bloodshed.net)*/
/********************************************************/
#include <iostream>
using namespace std;
#include <cstring>
#include <cstdlib>
char *entry, letter, choice[2];
int ascii, len, binary[8], total;
void prog();
int main()
{
prog();
return 0;
}
void prog()
{
entry = new char[501];
/* entry should be dynamic, otherwise a new string entry of 501 chars would be created each time function is called! Talk about memory hog! */
cout<<"Enter string to convert (up to 500 chars): ";
cin.getline(entry, 500);
len = strlen(entry); /* get the number of characters in entry. */
/* this loop is executed for each letter in the string. */
for(int i = 0; i<len; i++)
{
total = 0;
letter = entry[i]; /* store the first letter */
ascii = letter; /* put that letter into an int, so we can see its ASCII number */
while(ascii>0) /* This while loop converts the ASCII # into binary, stores it backwards into the binary array. */
{
/* To get the binary code one must take the decimal number in
question, take it and divide it by two repeatedly, save
the remainder (which will become the binary number), save
the whole number, divide by two, and repeat the whole
process until 0 is reached. This if-else statement serves
this functionality, by getting the remainder of the ascii
code, storing it in the array and then dividing the int
ascii by two */
if((ascii%2)==0)
{
binary[total] = 0;
ascii = ascii/2;
total++; /* increasing by one each time will yeild the
number of numbers in the array. */
}
else
{
binary[total] = 1;
ascii = ascii/2;
total++;
}
}
total--; /* due to data type factors, the program will actually
add a 0 at the end of the array that is not supposed
to be there, decrementing total will solve this
problem, as that 0 will not be displayed. */
/* this while loop displays the binary code for that letter. */
while(total>=0)
{
cout<<binary[total];
total--;
}
}
delete[] entry; /* free up the memory used by entry */
cout<<endl<<"Do again(1 = yes, 2= no)?: ";
cin.getline(choice,3);
if(choice[0] == '1')
prog(); /* program is recursive, it calls itself. It's kinda
like a function loop of sorts. */
else
exit(0); /* quits the program */
}