I'm working on a programm that generates Serial Codes. I know there a several threads about this topic, but I wasn't able to solve my problem.
I want to create a string that looks like this:
3S6G-TXMS-RLP6-VE5N
I can only use uppercase letters and numbers and every group of characters (like 3S6G) can only have a max. of 2 numbers in it.
My real struggle is that I have to open the internet explorer and navigate it to a address that includes this serial. It should look like this one: https://www.mywebpage.com/serial/3S6G-TXMS-RLP6-VE5N.
I hope someone can help me, because I'm not able to find a solution by myself.
At the moment it doesn't run, when I start the program, it instantly crashes. Also I didn't implement the Internet Explorer yet.
My Code:
#include <stdio.h>
#include <windows.h>
#include <time.h>
static const char abc[]=
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"123456789";
char Str[80];
char Str2[80];
char Str3[80];
char Str4[80];
char Stra[80];
unsigned int i;
int StringLength = sizeof(abc) -1;
char genRandom() {
return abc[rand() % StringLength];
}
int main()
{
SetConsoleTitle("Serial Generator");
srand(time(NULL));
for(i = 0; i < 4; i++) {
sprintf(Str, "%s", genRandom());
}
srand(time(NULL)-1);
for(i = 0; i < 4; i++) {
sprintf(Str2, "%s", genRandom());
}
srand(time(NULL)-2);
for(i = 0; i < 4; i++) {
sprintf(Str3, "%s", genRandom());
}
srand(time(NULL)-3);
for(i = 0; i < 4; i++) {
sprintf(Str4, "%s", genRandom());
}
sprintf(Stra, "%s-%s-%s-%s", Str, Str2, Str3, Str4);
printf("Your serial: \n");
printf("%s \n", Stra);
return 0;
}
I'm new to C, so please apologize if I ask dump questions.
Caveat:
I moved you code to a Linux box to test it there. I was able to successfully compile the code by (a) removing the #include <windows.h> line and (b) by removing the SetConsoleTitle("Serial Generator");
The compiler I'm using is gcc 4.8.2
OK, several things I see here
(1) you do not need to call srand more than once. srand seeds the random number generator. Really, really simplistically think of a huge table of random numbers and every time you make a call to rand you get the next number. srand picks where in that table you start. If you call srand multiple times in very quick succession, there is a good chance you will always be getting the same number.
(2) Why are all of your string arrays sized to 80? From what I can see, you will be sticking in four characters and allowing for the null terminator, you only need 5 bytes.
(3) Third, pay attention to compiler warnings ... they are there for a reason. When I compile you code I get the following warnings (I compiled with -g -ansi -Wall -pedantic):
dummy.c:19:5: warning: implicit declaration of function ‘rand’ [-Wimplicit-function-declaration]
return abc[rand() % StringLength];
^
dummy.c: In function ‘main’:
dummy.c:27:5: warning: implicit declaration of function ‘srand’ [-Wimplicit-function-declaration]
srand(time(NULL));
^
dummy.c:29:13: warning: format ‘%s’ expects argument of type ‘char *’, but argument 3 has type ‘int’ [-Wformat=]
sprintf(Str, "%s", genRandom());
Both rand and srand are declared in <stdlib.h> and including this file got rid of the first two errors.
The next error (of which there are four of that form, I've only shown one), from taking the results of getRandom() which returns a char and then try to write it into the buffer Str1 using a string format specifier. Remember that a char data type is really an integer.
Additionally, sprintf(....) will overwrite what is in the buffer with the new string, so calling in a loop doesn't append strings, it will over write the contents. You can accomplish what you want with a loop that looks like this:
for(i = 0; i < 4; i++) {
Str2[i] = genRandom();
}
I suspect that this was the root cause of the error you initially reported.
(4) There is no reason for the variable i to have file scope, it should be moved inside main.
(5) You really don't need to use so many string variables. Consider this loop:
Stra[4] = Stra[9]=Stra[14] = '-'
for(i = 0; i < 4; i++) {
Stra[i] = genRandom();
Stra[5+i] = genRandom();
Stra[10+i] = genRandom();
Stra[15+i] = genRandom();
}
With all these changes and modifications, your program now looks like:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*#include <windows.h>*/
#include <time.h>
static const char abc[]= "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789";
#define STRING_LEN 20
char Stra[STRING_LEN];
int StringLength = sizeof(abc) -1;
char genRandom() {
return abc[rand() % StringLength];
}
int main()
{
/* SetConsoleTitle("Serial Generator");*/
unsigned int i;
memset(Stra, '\0', STRING_LEN);
Stra[4] = Stra[9]=Stra[14] = '-';
for(i = 0; i < 4; i++) {
Stra[i] = genRandom();
Stra[5+i] = genRandom();
Stra[10+i] = genRandom();
Stra[15+i] = genRandom();
}
printf("Your serial: \n%s \n ", Stra);
return 0;
}
Running this program on my Linux system produces the following:
******#ubuntu:~$ gcc -ansi -pedantic -Wall dummy.c -o dummy
******#ubuntu:~$ ./dummy
Your serial:
II4U-LK6E-C6CN-FCMV
Finally, your code (and thus my answer) does not address the restriction of no more than 2 digits.
Related
Wrote a program that multiply two arrays like this:
uv = u1v1 + u2v2 + u3v3 + ... un*vn
after getting from the user both of the arrays, i get a "signal: segmentation fault (core dumped)" error.
here's the code:
#include <stdio.h>
int scalar_product(int vectorU[], int vectorV[], int vectorLength) {
int i, sum = 0;
for (i = 0; i < vectorLength; i++)
sum += (vectorU[i] * vectorV[i]);
return sum;
}
void userInterface() {
int vectorLength = 0, i;
printf("Please enter the length of the vectors: ");
scanf("%d", &vectorLength);
int vectorU[vectorLength], vectorV[vectorLength];
printf("\nVector U:");
for (i = 0; i < vectorLength; i++) {
printf("\n%d) ", (i + 1));
scanf("%d", &vectorU[i]);
}
printf("\nVector V:");
for (i = 0; i < vectorLength; i++) {
printf("\n%d) ", (i + 1));
scanf("%d", &vectorV[i]);
}
printf(scalar_product(vectorU, vectorV, vectorLength));
}
main(void) {
userInterface();
}
This call of printf is incorrect
printf(scalar_product(vectorU, vectorV, vectorLength));
You need to write at least
printf( "%d\n", scalar_product(vectorU, vectorV, vectorLength));
Also it would be better to declare and define the function like
long long int scalar_product( const int vectorU[], const int vectorV[], int vectorLength) {
long long int sum = 0;
for ( int i = 0; i < vectorLength; i++)
sum += ( long long int )vectorU[i] * vectorV[i];
return sum;
}
To output the result you need to use the format string "%lld\n"..
The type long long int is used to avoid an overflow.
Another way is to declare the function return type as double.
Also you forgot to specify the return type int of the function main.
Here:
printf(scalar_product(vectorU, vectorV, vectorLength));
... you have failed to specify a format for printf. As a result, it attempts to interpret the result of scalar_product() as a pointer to the format string. Undefined behavior results.
If your compiler is not emitting a warning about that then you should either learn how to turn up the warning level so that it does, or else get a better compiler. If your compiler is emitting a warning about it, then take this as a lesson that it is not safe to ignore compiler warnings.
Probably you wanted somethign more like this:
printf("%d\n", scalar_product(vectorU, vectorV, vectorLength));
As a minor additional issue, you have forgotten the return type for main(). Your compiler is probably treating it as returning int, which turns out to be the right thing to do, but that doesn't make your code correct. You want:
int main(void) {
// ...
With those two changes, your program compiles for me without any diagnostics, and runs without error, producing the result I expect.
At least, for small vector lengths. If you try really large vectors then you might exceed the available space for allocating your vectors on the stack.
I need to create an array of strings, each representing a card of the Spanish deck:
#define __USE_MINGW_ANSI_STDIO 1
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
char *type[4]= {"copas", "basto", "espada", "oro"};
char *number[10]= {"Uno", "Dos", "Tres", "Cuatro", "Cinco", "Seis", "Siete", "Diez", "Once", "Doce"};
char *deck[40];
int deckIndex= 0;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 10; j++) {
char card[100] = "";
strcat(card, number[j]);
strcat(card, " de ");
strcat(card, type[i]);
strcat(card, "\n");
deck[deckIndex]= card;
deckIndex++;
}
}
for (int i = 0; i < 40; i++)
{
printf("%s\n", deck[i]);
}
return 0;
}
However, all entries of deck[] point to the same string. As a result, "Doce de oro" is printed 40 times. I don't understand why this happens, but I've theorized it's because card[] is being reinitialized in the same memory direction, and overrides what was already written there in the previous iteration. If I'm right, I would have to declare every array separately, but I have no idea how to do that without writing 40 different arrays.
Tldr:
¿Why do all entries of deck[] point to the same location?
¿How do I fix it?
(Btw suggestions for a better title are appreciated)
In C, memory on the stack is allocated in terms of Scopes. So yes, your theory is right. You are rewriting on the same location.
To fix your program, there are two possible solutions I can think of.
You can use Multidimensional Arrays.
Or you can allocate memory in heap using malloc (but make sure to free it once you are done with it)
As pointed out in the comments, in the deck[deckIndex]= card; line, you are assigning the same pointer1 to each of your deck elements – and, worse, a pointer to a variable (the card array) that is no longer valid when the initial nested for loop goes out of scope.
To fix this, you can make copies of the card string, using the strdup function, and assign the addresses of those copies to the deck elements. Further, as also mentioned in the comments, you can simplify the construction of the card string using a single call to sprintf, rather than using multiple strcat calls.
Here's how you might do that:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
char* type[4] = { "copas", "basto", "espada", "oro" };
char* number[10] = { "Uno", "Dos", "Tres", "Cuatro", "Cinco", "Seis", "Siete", "Diez", "Once", "Doce" };
char* deck[40];
int deckIndex = 0;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 10; j++) {
char card[100] = "";
sprintf(card, "%s de %s", number[j], type[i]);
deck[deckIndex] = strdup(card);
deckIndex++;
}
}
for (int i = 0; i < 40; i++) {
printf("%s\n", deck[i]);
}
// When you're done, be sure to free the allocated memory:
for (int i = 0; i < 40; i++) {
free(deck[i]);
}
return 0;
}
If your compiler does not support the strdup function (most do, and it is part of the ISO C Standard from C23), writing your own is very simple:
char* strdup(const char *src)
{
char* result = malloc(strlen(src) + 1); // Add one to make room for the nul terminator
if (result) strcpy(result, src);
return result;
}
1 Well, formally, a new card array is born on each iteration of the inner for loop, but it would be a very inefficient compiler that chose to do that, rather than simply re-using the same memory – which is clearly what is happening in your case.
Right, this is (the last) assignment for my C introduction web class.
The assignment presents the main program, does not explain anything about it and tells you to write a function to print and sum the array in it.
However I don't really understand what is going on in the main program.
Translated for your convenience;
Source code:
#include <stdio.h>
#include <stlib.h>
void print_count(int *, int);
int main(int argc, char *argv[]) {
int x, sum = 0, size = 0, array[5];
if (argc == 6) {
/* Program name and parameters received from command line */
for (x = 0; x < argc - 1; x++) {
array[x] = atoi(argv[x + 1]);
}
print_count(array, size);
} else {
printf("Error\n");
}
return 0;
}
Now I am completely clueless as to how to start writing the program requested and what variables to call/how to write the function.
Edit3: completed exercise
void print_count(int *array, int size) {
int i;
int sum = 0;
printf("Elements: ");
for (i = 0; i <= size; i++) {
printf("%d ", (array[i]);
sum = sum += array[i]);
}
printf("\nSum = %d ", sum);
return 0;
}
I would like to understand what is going on in the main program and preferably come to an answer on how to actually write the function by myself.
This:
array[5] = atoi(argv[x+1]);
is clearly wrong, it always tries to assign to array[5] which is out of bounds. It should be:
array[x] = atoi(argv[x + 1]);
This converts the x + 1:th argument from string format into an integer, and stores that in array[x]. If you're not familiar with the standard function atoi(), just read the manual page.
So if you start the program like this:
./myprogram 1 2 3 4 5
That has 6 arguments (the first is the name itself), and will end up with array containing the numbers one through five.
Then in the summing function, the first line should be something like:
void print_count(int *array, int size)
so that you give names to the arguments, which makes them usable in the function. Not providing names is an error, I think.
And it doesn't need to "interact" with main() more than it already does; main() calls print_count(), passing it a pointer to the first element of array and the length of the array, that's all that's needed to compute the sum.
Your print_count function has a few issues:
The loop runs one step too far: i should vary between 0 and size-1 included. The standard idiom for this loop is:
for (i = 0; i < size; i++) {
...
Incrementing sum is simply done with:
sum += array[i];
There is an extra ( on the first printf line.
You should print a newline after the output.
Returning 0 from a void function is invalid.
Here is a corrected version:
void print_count(int *array, int size) {
int i;
int sum = 0;
printf("Elements: ");
for (i = 0; i < size; i++) {
printf("%d ", array[i]);
sum += array[i]);
}
printf("\nSum = %d\n", sum);
}
the following proposed code:
cleanly compiles.
explains what is being accomplished at each step of the 'main()' function.
properly outputs error messages to 'stderr'.
implements the typical method to announce an error in the number of command line parameters.
Now the proposed code with explanatory comments:
#include <stdio.h> // printf(), fprintf()
#include <stdlib.h> // atoi(), exit(), EXIT_FAILURE
void print_count(int *, int);
int main(int argc, char *argv[])
{
if (argc != 6)
{
fprintf( stderr, "USAGE: %s int1 int2 int3 int4 int5\n", argv[0] );
exit( EXIT_FAILURE );
}
// implied else, correct number of arguments
// only declare variables when they are needed
int array[5];
// place each command line parameter into 'array',
// except program name
// I.E. skip the program name in argv[0]
for( int i = 1; i < argc; i++ )
{
// array[] index starts at 0, but loop counter starts at 1
array[i-1] = atoi(argv[i]);
} // end for( each value pointed at by argv[], except program name )
// print sum of command line parameters to stdout
int size = argc-1; // number of command line parameters after program name
print_count(array, size);
return 0;
} // end function: main
I don't understand why I am getting the error:
~/SecureSoftware$ gcc AddNumTest.c
AddNumTest.c:11:0: warning: "INT_MAX" redefined [enabled by default]
/usr/lib/gcc/x86_64-linux-gnu/4.6/include-fixed/limits.h:121:0: note: this is the location of the previous definition
I am looking for a way to not crash my program when a big number is added in the command line.
#include<stdio.h>
#include <stdlib.h>
#include <limits.h>
#define INT_MAX (2147483647)
#define INT_MIN (-2147483647)
int main(int argc, char** argv)
{
int i, TotalOfNumbers = 0;
for (i = 1; i < argc; i++)
{
TotalOfNumbers += atoi(argv[i]);
printf("Total of numbers entered = %d\n", TotalOfNumbers);
}
return 0;
}
Redefining INT_MIN and INT_MAX doesn't change the actual limits, it just makes the constants describing them inaccurate.
The limits are based on your platform's integer sizes / widths. To have genuinely different limits, you need to use different data types (for instance, long rather than int).
If a long isn't big enough, you may need to move up further, to a long long; note that these aren't specified prior to the C99 standard, so you need to have a reasonably modern compiler.
Changing your program to use longs instead of ints would look like this:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
int main(int argc, char** argv)
{
long long i, TotalOfNumbers = 0;
for (i = 1; i < argc; i++)
{
TotalOfNumbers += atoll(argv[i]);
printf("Total of numbers entered = %lld\n", TotalOfNumbers);
}
return 0;
}
Here is the correct way to convert text to integers in C: unlike atoi, strtol will actually tell you if the number is too large, although in a somewhat awkward fashion.
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
long
reliable_atol(const char *s)
{
char *endp;
long rv;
errno = 0;
rv = strtol(s, &endp, 10);
if (errno || endp == s || *endp) {
fprintf(stderr, "number malformed or out of range: %s\n", s);
exit(1);
}
return rv;
}
Use this function instead of atoi in your code, and change TotalOfNumbers to long (and print it with %ld).
You might also want to try to detect overflow in the addition, but you can do that without using INT_MAX or INT_MIN:
int main(int argc, char **argv)
{
int i;
long TotalOfNumbers = 0;
for (i = 1; i < argc; i++) {
long n = reliable_atol(argv[i]);
long sum = (long) ((unsigned long)TotalOfNumbers + (unsigned long)n);
if ((n > 0 && sum < TotalOfNumbers) || (n < 0 && sum > TotalOfNumbers)) {
fputs("numeric overflow while computing sum\n", stderr);
exit(2);
}
TotalOfNumbers = sum;
}
printf("total %ld\n", TotalOfNumbers);
return 0;
}
The casts are required, because signed integer overflow provokes undefined behavior but unsigned integer overflow doesn't. This code technically won't work on a non-twos-complement CPU but nobody has manufactured one of those in decades and the C standard's continued provision for the possibility is getting decidedly silly.
If I stick the above two code samples together, making a complete program, I get this for your test case:
$ gcc -O2 -Wall test.c # default mode for this CPU+OS: long is 64 bits
$ ./a.out 22220020202 45
total 22220020247
$ gcc -O2 -Wall -m32 test.c # alternative mode: long is 32 bits
$ ./a.out 22220020202 45
number malformed or out of range: 22220020202
My aim is to write an app which generates an char - array (each should be random-filled with strings of the length 4) and sorts this array. The time this process takes should be measured. I coded the following:
#include <string.h>
#include <jni.h>
#include <time.h>
#include <math.h>
clock_t start, finish;
static int ARRAY_LENGTH = 200;
static int WORD_LENGTH = 4;
char values[200];
void sortStringArray(void){
int i, j;
for(i = 0; i < ARRAY_LENGTH; i++){
for(j = 0; j < ARRAY_LENGTH-1; j++){
if(strcmp(values[j], values[j+1]) > 0) {
char holder = values[j+1];
values[j+1] = values[j];
values[j] = holder;
}
}
}
}
char generateRandomChar(char aC[]){
int length = strlen(aC);
char randStr[WORD_LENGTH];
int m;
for(m = 0; m <WORD_LENGTH; m++){
int randNr = rand()%length;
randStr[m] = aC[randNr];
}
return randStr;
}
void fillStringArray(void)
{
char allowedChars[] = "abcdefghijklmnopqrstuvwxyz";
int k;
for(k = 0; k < ARRAY_LENGTH; k++){
char randStr = generateRandomChar(allowedChars);
values[k] = randStr;
}
}
double
Java_com_example_hellojni_HelloJni_processStringSort( JNIEnv* env, jobject thiz)
{
start = clock();
fillStringArray();
sortStringArray();
finish = clock();
return ((double)(finish - start));
}
Since I am pretty new to coding C, i am not that fimilar with the concept of pointers, and therefore i recieve some mistakes.
alt text http://img38.imageshack.us/img38/2894/androidndkdebugc.jpg
It would be helpful if sb could explain me where it would be useful to use a pointer in this code. Some help with the errors would be very appreciated.
Thanks! Ripei
Without re-writing your code from scratch, it is difficult to to know where to start. I'm afraid it is all wrong. In order to get a good understanding of pointer and character string use in C, you must read a good, authoritative book on the language, Luckily, C has one of the best such books in the world - The C Programming Language. If you haven't already got a copy, get one, and if you have, re-read the chapters on pointers and strings.
Well for one thing you seem to think that char means string.... sometimes? char means a character, a number between 0 and 255. As the warnings on line 15 say, values[j] and values[j+1] are not strings (char *), they are characters (char). You probably want to make values an array of strings, ie an array of arrays of characters.
The 2nd set of warnings you're getting are related to line 31, where you're returning an array of characters (a pointer) from a function that states that it returns a character. The compiler silently casts the pointer to a character (since a pointer is a number) and returns that. You'll end up with a random number, which is probably not what you want.
To fix this you'll have to make the function return a char *, but there's a catch. randStr is gone as soon as you get out of the function, thus making it impossible to return. You could use strdup to duplicate the string and, after you're done using it in your main function, you call free to get rid of it.
While we're on this function, the parameter to it should be a char *, not a char[]. They have different meanings.
The last message (the only error reported as such apparently) is because you didn't define rand(). Adding a #include <stdlib.h> at the beginning of the program should fix it.
Thank you very much Blindy for your hints. I tried to implement your hints. Now the program doesn't throw errors but the problem is that i can't check if the operation is done correctly with the programm-environment i've to work with. Do you think the code is correct as it is shown below? Also the time it takes is quite less: 11ms. Do I calc this right?
Neil Butterworth,... well your're probably right, but I had to start somehow... and I tried my best to do so.
Vinko Vrsalovic,... well you're not right ;) I did it step by step but I thought that its better to show you the whole program and all errors at one time.
#include <string.h>
#include <jni.h>
#include <time.h>
#include <stdlib.h>
long start, finish;
static int ARRAY_LENGTH = 500;
static int WORD_LENGTH = 4;
static int LOOPS = 10;
char *values[1000];
static long getTime(void){
struct timeval now;
gettimeofday(&now, NULL);
return (long)(now.tv_sec*1000 + now.tv_usec/1000);
}
void sortStringArray(void){
int i, j;
for(i = 0; i < ARRAY_LENGTH; i++){
for(j = 0; j < ARRAY_LENGTH-1; j++){
if(strcmp(values[j], values[j+1]) > 0) {
char *holder = values[j+1];
values[j+1] = values[j];
values[j] = holder;
}
}
}
}
char* generateRandomChar(char *aC){
int length = strlen(aC);
char randStr[WORD_LENGTH];
int m;
for(m = 0; m <WORD_LENGTH; m++){
int randNr = rand()%length;
randStr[m] = aC[randNr];
}
return strdup(randStr);
}
void fillStringArray(void)
{
char *allowedChars = "abcdefghijklmnopqrstuvwxyz";
int k;
for(k = 0; k < ARRAY_LENGTH; k++){
char *randStr = generateRandomChar(allowedChars);
values[k] = randStr;
}
}
jlong
Java_com_example_hellojni_HelloJni_processStringSort( JNIEnv* env, jobject thiz)
{
start = getTime();
int i;
for(i = 0; i < LOOPS; i++){
fillStringArray();
sortStringArray();
}
finish = getTime();
return (finish - start);
}