C program behaves differently in gcc and llvm compiler - c

I wrote a program that consists of main and a function expand. The problem is that the code returns the intended result when compiled and run with Xcode (latest version) however when compiled and run with gcc compiler through terminal the code is stuck immediately after running (no warnings or errors!). This is the command I use to compile the code in the terminal:
gcc expand.c -o expand -Wall -pedantic -ansi
Below is my code. I have no idea what my problem is:
#include <stdio.h>
#define MAX_LEN 100
#define ATOI_GAP 48
void expand(char s1[], char s2[]);
int main()
{
int i;
char s2[MAX_LEN]; /* declare the target array */
char s1[4]; /* declare the source array */
s1[0] = 'a';
s1[1] = '-';
s1[2] = 'z';
s1[3] = '\0';
for(i = 0; i < MAX_LEN; ++i) { /* print s2 array */
printf("%d ", s2[i]);
}
expand(s1, s2);
for(i = 0; s2[i] != '\0'; ++i) { /* print s2 array */
printf("%c ", s2[i]);
}
return 0;
}
/* the function gets string s1 of format "letterX-letterY"
and fills the "-" with the consequent letters from letterX to
letterY. For example, if s1 = "a-d", then s2 will be "abcd"*/
void expand(char s1[], char s2[]) {
int start = s2[0] = s1[0]; /* the first letter of the array s2 is the same as that of the array s1 */
int stop = s1[2]; /* determine at which letter we need to stop */
int j;
printf("inside expand");
for(j = 1; j < stop - '0' - ATOI_GAP; ++j) {
s2[j] = ++start; /* fill in the gap */
}
s2[j] = '\0';
printf("finished expand");
}

Found the issue, I was incorrectly running the output C file. I previously exported the path with all my C output files, so to call the file in question I was just typing "filename" in the terminal. However, the exported path wasn't sourced properly so I wasn't getting any result. When I run the file as "./filename" everything is working.

Related

char-array (string) with arbitrary number of elements in c

I have problem with assigning value to string array in c. The code is part of a hangman game
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
int main()
{
srand(time(0));
int random = rand() % 5;
char *sWords[] = {"banana", "apple", "GOAT", "jordan", "zhiki"};
printf("%s\n", sWords[random]);
char *sTempWord = sWords[random];
char *sTempArr;
for (int i = 0; sTempWord[i] != '\0'; i++)
sTempArr[i] = '_';
for (int i = 0; strlen(sTempArr); i++)
printf("%c ", sTempArr[i]);
}
There are no errors, and when I run the program it just exits. The plan is to get random word from the list, create temporary array with the length of the randomly-selected word and assing all elements with value '_'.
Also, when I try to make array with constant value, (like char sTempArr[len] where len=strlen(sTempWord), it says: expression must have a constant value
When declaring an array, the compiler needs to know the length at compile time (e.g. the value can't be a variable).
You can either create an initial empty array with a known number of items (you will need to make sure it's big enough to fit any word from sWords, including null terminator):
char sTempArr[100];
or you can allocate dynamic memory at runtime with something like malloc():
#include <stdlib.h>
int len = strlen(sTempWord) + 1; // +1 for '\0'
char *sTempArr; = malloc(len);
// ...
free(sTempArr); // When you are done using the array
They are not the same.
Not initialized pointer.
char *sTempArr;
You do not null character terminate the string
for (int i = 0; sTempWord[i] != '\0'; i++)
sTempArr[i] = '_';
As the string is null character terminated you can't call strlen
for (int i = 0; strlen(sTempArr); i++)
printf("%c ", sTempArr[i]);
char sTempArr[strlen(sTempWord) + 1];
int i;
for (i = 0; sTempWord[i] != '\0'; i++)
sTempArr[i] = '_';
sTempArr[i] = 0;
for (i = 0; strlen(sTempArr); i++)
printf("%c ", sTempArr[i]);

Iterate through every char in string stored in an array

I am really new to C and in my first half year at university. This is my first questio on StackOverflow.
My task is to program it so every string stored in numbers is being converted into a decimal, without changing anything outside the main function.
I am now trying for the past 4 hours to solve this problem, where I want to iterate trough every char in the string I am currently to then, based on there position in comparison to the length to convert it into a decimal.
My only question here is to someone help me to understand how I can get the string length without using strlen() due to the fact I can't add #include <string.h>
This is what I got so far (getting the length of the array to iterate through every index):
#include <stdio.h>
#include <math.h> // Kompilieren mit -lm : gcc -Wall -std=c11 dateiname.c -lm
int main() {
char* numbers[] = {
"01001001",
"00101010",
"010100111001",
"011111110100101010010111",
"0001010110011010101111101111010101110110",
"01011100110000001101"};
// Add here..
int length = sizeof(numbers);
for ( int i = 0; i < length; i++ ){
//how do i get the string size without strlen() D:
}
return 0;
}
In C, strings are really just char arrays with a special terminator character to mark the end of the string. So, say you have something like:
char *str = "hello";
This is essentially equivalent to this:
char str[] = {'h', 'e', 'l', 'l', 'o', '\0'};
Notice that \0 character at the end of the array? This is the special terminator character that C places at the end of strings. Functions like strlen() pretty much iterate through the char array looking for the first occurrence of the \0 character and then stopping.
So, you can make your own version of strlen(), say my_strlen() like this:
int my_strlen(char *str)
{
/* Initialize len to 0 */
int len = 0;
/* Iterate through str, increment len, and stop when we reach '\0' */
while(str[len] != '\0')
len++;
/* Return the len */
return len;
}
Then within your for loop, you can just call this function. Also, note that your calculation of the size of the numbers array:
int length = sizeof(numbers);
will not give you the number of elements in the array. That code gives you the size (in bytes) or numbers which is an array of char pointers. If you want to get the number of elements, you have to divide that size by the size (in bytes) of a single element (i.e., a char pointer). So, something like this would work:
int length = sizeof(numbers) / sizeof(numbers[0]);
Your final code can look something like this:
#include <stdio.h>
#include <math.h> // Kompilieren mit -lm : gcc -Wall -std=c11 dateiname.c -lm
int my_strlen(char *str) {
/* Initialize len to 0 */
int len = 0;
/* Iterate through str, increment len, and stop when we reach '\0' */
while(str[len] != '\0')
len++;
/* Return the len */
return len;
}
int main() {
char* numbers[] = {
"01001001",
"00101010",
"010100111001",
"011111110100101010010111",
"0001010110011010101111101111010101110110",
"01011100110000001101"};
// Add here..
// Notice the change here
int length = sizeof(numbers) / sizeof(numbers[0]);
for(int i = 0; i < length; i++ ){
int str_len = my_strlen(numbers[i]);
// Do what you need with str_len
}
return 0;
}
This project can be done without computing the length of the strings. How? In C, all strings are nul-terminated containing the nul-character '\0' (with ASCII value 0) after the last character that makes up the string. When you need to iterate over a string, you just loop until the character values is 0 (e.g. the nul-character)
This is how all string function know when to stop reading characters. Since you have an array-of-pointers that contains your strings, you just need to loop over each pointer and for each pointer, loop over each character until the nul-character is found.
Putting it altogether, (and noting you don't need math.h), you can do:
#include <stdio.h>
#include <math.h> // Kompilieren mit -lm : gcc -Wall -std=c11 dateiname.c -lm
int main() {
char* numbers[] = {
"01001001",
"00101010",
"010100111001",
"011111110100101010010111",
"0001010110011010101111101111010101110110",
"01011100110000001101"};
int nnumbers = sizeof numbers / sizeof *numbers; /* no. of elements */
for (int i = 0; i < nnumbers; i++) {
long long unsigned number = 0;
/* you don't care about the length, strings are nul-terminated,
* just loop until \0 is found.
*/
for (int j = 0; numbers[i][j]; j++) {
number <<= 1; /* shift left */
number += numbers[i][j] == '1' ? 1 : 0; /* add bit */
}
printf ("%s = %llu\n", numbers[i], number); /* output result */
}
return 0;
}
(note: you must use a 64-bit type to hold the converted values as "1010110011010101111101111010101110110" requires a minimum of 38 bits to represent)
Example Use/Output
Simple example output converting each string to a numeric value:
$ ./bin/binstr2num
01001001 = 73
00101010 = 42
010100111001 = 1337
011111110100101010010111 = 8342167
0001010110011010101111101111010101110110 = 92790519158
01011100110000001101 = 379917
#include <stdio.h>
int main(){
char arr[20]="Hello";
int count=0;
while(arr[count]!='\0'){
count++;
}
printf("%d",count);
return 0;
}
Look at this small code, you will understand. In C a string ended with a NULL character. We can use that advantage.
There are a few ways to do it. IMO, a simple, reasonable way to implement strlen is:
size_t string_length(const char *s) { return strchr(s, '\0') - s; }
but if you're not allowed to use strlen then you're probably not allowed to use strchr either. So you just have to count. The most idiomatic way to do that is probably a bit obscure for a complete beginner, so here is a more verbose method.
Note that your computation of the number of elements in the array is invalid, and has been corrected below.
#include <stdio.h>
int
length(const char *s)
{
int len = 0;
while( *s++ ){
len += 1;
}
return len;
}
int
main(void)
{
char *numbers[] = {
"01001001",
"00101010",
"010100111001",
"011111110100101010010111",
"0001010110011010101111101111010101110110",
"01011100110000001101"
};
int count = sizeof numbers / sizeof *numbers; /* Number of entries */
for( int i = 0; i < count; i++ ){
printf(" length of %s is %d\n", numbers[i], length(numbers[i]));
}
return 0;
}
It's pretty subjective, but IMO a more idiomatic way to write this is:
#include <stdio.h>
int
length(const char *e)
{
const char *s = e;
while( *e++ )
;
return e - s - 1;
}
int
main(void)
{
char *numbers[] = {
"01001001",
"00101010",
"010100111001",
"011111110100101010010111",
"0001010110011010101111101111010101110110",
"01011100110000001101"
};
char **e = numbers + sizeof numbers / sizeof *numbers;
for( char **t = numbers; t < e; t++ ){
printf(" length of %s is %d\n", *t, length(*t));
}
return 0;
}

strcat() has a problem in xcode using gcc

if I compile with XCode at the height of strcat() the following error is returned:
Thread 1: EXC_BAD_INSTRUCTION (code = EXC_I386_INVOP, subcode = 0x0)
while, if I compile from terminal (gcc -Wall program.c -o Out):
Illegal instruction: 4
lung2 is the length of s2.
MAX equals 30 and it is the array's maximum length.
Here is the code:
char s1[MAX] = { '\0' };
char s2[MAX] = { '\0' };
int flag = 0;
char *ptr;
unsigned long int lung1, lung2 = 0;
int verifica = 0;
j = 0;
...
while (j < lung1) {
ptr = strstr(s1, s2);
if (ptr) {
strncpy(ptr, "*", lung2);
strcat(s1, ptr + lung2);
flag = 1;
} else {
j++;
}
}
The code replaces each occurrence of s2 in s1 with an asterisk *.
On some platforms the behavior of strcat is undefined if the source and destination overlap, which is the case here since ptr points into s1.

Passing argument from main to function in C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
// Compile this program with:
// cc -std=c99 -Wall -Werror -pedantic -o rot rot.c
#define ROT 3
// The rotate function returns the character ROT positions further along the
// alphabetic character sequence from c, or c if c is not lower-case
char rotate(char c)
{
// Check if c is lower-case or not
if (islower(c))
{
// The ciphered character is ROT positions beyond c,
// allowing for wrap-around
return ('a' + (c - 'a' + ROT) % 26);
}
else
{
return ('A' + (c - 'A' + ROT) % 26);;
}
}
// Execution of the whole program begins at the main function
int main(int argc, char *argv[])
{
for (int j = 2; j < argc; j++){
// Calculate the length of the second argument
int length = strlen(argv[j]);
// Loop for every character in the text
for (int i = 0; i< length; i++)
{
// Determine and print the ciphered character
printf("%c" ,rotate(argv[j][i]));
printf("%c" ,rotate(argv[j][i])-ROT);
printf("%d",i+1);
printf("\n");
}
// Print one final new-line character
printf("\n");
}
// Exit indicating success
exit(EXIT_SUCCESS);
return 0;
}
I am struggling with a program that rotates the given characters by the amount user type in as the first argument of argv.
Now I need to modify the program to achieve this. The question says I can use àtoi` function to do that.
My confusion is that How can my argv[1] value in Main be passed into function rotate (Variable ROT)?
The ideal output would be (using terminal in MAC)
./rot 1 ABC
AB1
BC2
CD3
ROT is a macro. You can't change it at runtime. Use a variable instead.
(You need to error check strtol() and ensure there are as many argv[] passed before using them -- strtol() is better than atoi as helps detect errors).
int rot = (int)strtol(argv[1], 0, 0);
printf("%c" ,rotate(rot, argv[j][i]));
printf("%c" ,rotate(rot, argv[j][i])-ROT);
and change it to:
char rotate(int rot, char c) {
...
}
and use rot instead of ROT.

Random String Generator for Serial

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.

Resources