Extracting an 4 digit int (decimal) into string in C manually - c

I'm struggling with this programming assignment I have for one of my classes here. I'm an electrical engineering student so my programming is by no means amazing. I'm told to write a c program that takes a 12-bit number and extracts each of that 12 bit number's digits into a char array. I did the quick math and realized that the largest number we can obtain is 0xFFF or 4095 in decimal. I found an algorithm that I thought would work quite well but for some reason, my code isn't doing what I thought. I am continuing to try and troubleshoot this, but with my only way to run it being linux terminal window, I don't have a great debugging utility to step through the program. Any help would be greatly appreciated. Feel free to ask some questions as well and I'll do my best to field them. I am not a fluent programmer so bear that in mind. Also, if someone could explain integer division to me that would be helpful. I was under the assumption that something like 8/10 would return a result of 0 but I don't know that it's working that way when I run the program. Thank you.
I CANNOT USE FUNCTIONS TO DO THIS AND MUST DO IT MANUALLY.
Here is what I have thus far.
Attempt # Solution:
//12 bit value into string of decimal chars
//EX: 129 -> a '1' a '2' and a '9'
void main (void) {
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <stddef.h>
//Initialize an array with 5 spaces, each space
//holds one character (accounts for largest number 4095)
char OUT[5];
uint8_t length = sizeof(char);
//Isolating each int value happens here
//initialize i to act as a counter to loop through array
uint8_t i=2;
//Initialize an input value to test the code;
uint16_t IN=549;
while (IN/10 > 0)
{
OUT[length-(i+1)] = '0' + (IN%10);
IN=IN/10;
if (IN <= 10)
{
if (IN = 10)
{
OUT[length-(i+1)] ='1';
//fixes infinite loop issue
IN=0;
}
else
{
OUT[length-(i+1)] ='0' + IN;
//fixes infinite loop issue
IN=0;
}
}
//Increment Counter to keep track of char array
i++;
}
//add the new line at the end of the array of chars
OUT[length-1]='\n';
printf("String is -> %s", OUT);
}
Couple of notes:
Using IN%10 is part of the algorithm that isolates the furthest right digit in decimal. I had to add some "fudge factors" to my counter to get the array to line up properly and account for the \n at the end of my char array. The conditional statements that I put inside my while loop were to catch some edge cases (mainly when IN became 10 or less).

It looks like you are bending over backwards to handle the fact that you have to print the leftmost character first. The logic is much simpler if you just generate the rightmost character first and then reverse it.
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <stddef.h>
#include <string.h>
//12 bit value into string of decimal chars
//EX: 129 -> a '1' a '2' and a '9'
void main (void) {
char OUT[5];
memset(OUT, 0, 5);
int i=0;
int j;
uint16_t IN=549;
// Generate the string in reverse order.
while (IN != 0)
{
OUT[i++] = '0' + (IN%10);
IN/=10;
}
// Reverse the string
for (j = 0; j < i/2; j++) {
char temp = OUT[j];
OUT[j] = OUT[i-1-j];
OUT[i-1-j] = temp;
}
printf("String is -> %s\n", OUT);
}

This line is your problem:
uint8_t length = sizeof(char);
The sizeof function returns the size of the type between parentheses. In this case it returns 1, because a char is a 1 byte variable. Then when you try to access the elements of the array you get a negative number from length-(i+1).

Here is my final solution using the more complex way in case anyone is curious/stumbles into the problem later on.
void main (void) {
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <stddef.h>
//Initialize an array with 5 spaces, each space holds one character (accounts for largest number 4095)
char OUT[5];
OUT[0] = '0';
OUT[1] = '0';
OUT[2] = '0';
OUT[3] = '0';
OUT[4] = '0';
uint8_t length =5; //sizeof(char) was giving me an error and thus not used.;
//Isolating each int value happens here
//initialize i to act as a counter to loop through array
uint8_t i=2;
//Initialize an input value to test the code;
uint16_t IN=4012;
//Initialize variable for % operator value
uint16_t mod=0;
while (IN/10 > 0)
{
mod=IN%10;
OUT[length-i] = '0' + mod;
IN=IN/10;
if (IN <= 10)
{
if (IN == 10)
{
OUT[length-(i+2)] ='1';
OUT[length-(i+1)] ='0';
//fixes infinite loop issue
IN=0;
}
else
{
OUT[length-(i+1)] ='0' + IN;
//fixes infinite loop issue
IN=0;
}
}
//Increment Counter to keep track of char array
i++;
}
//add the new line at the end of the array of chars
OUT[length-1]='\n';
printf("String is -> %s", OUT);
}

Related

Type casting failure in C program

As a C fresher, I am trying to write a recursive routine to convert a decimal number to the equivalent binary. However, the resultant string is not correct in the output. I think it has to be related to the Type casting from int to char. Not able to find a satisfactory solution. Can anyone help? Thanx in advance.
Code:
#include <stdio.h>
#include <conio.h>
int decimal, counter=0;
char* binary_string = (char*)calloc(65, sizeof(char));
void decimal_to_binary(int);
int main()
{
puts("\nEnter the decimal number : ");
scanf("%d", &decimal);
decimal_to_binary(decimal);
*(binary_string + counter) = '\0';
printf("Counter = %d\n", counter);
puts("The binary equivalent is : ");
puts(binary_string);
return 0;
}
void decimal_to_binary(int number)
{
if (number == 0)
return;
else
{
int temp = number % 2;
decimal_to_binary(number/2);
*(binary_string + counter) = temp;
counter++;
}
}
Should the casting store only the LSB of int in the char array each time?
Do not use global variables if not absolutely necessary. Changing the global variable in the function makes it very not universal.
#include <stdio.h>
char *tobin(char *buff, unsigned num)
{
if(num / 2) buff = tobin(buff, num / 2);
buff[0] = '0' + num % 2;
buff[1] = 0;
return buff + 1;
}
int main(void)
{
char buff[65];
unsigned num = 0xf1;
tobin(buff, num);
printf("%s\n", buff);
}
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
int decimal, counter=0;
//char* binary_string = (char*)calloc(65, sizeof(char));
//C does not allow initialization of global variables with
//non constant values. Instead declare a static char array with 65 elements.
//Alternatively declare binary_string in the main function and allocate memory with calloc.
char binary_string[65];
void decimal_to_binary(int);
int main()
{
puts("\nEnter the decimal number : ");
scanf("%d", &decimal);
decimal_to_binary(decimal);
//*(binary_string + counter) = '\0';
// This is more readable:
binary_string[counter] = '\0';
printf("Counter = %d\n", counter);
puts("The binary equivalent is : ");
puts(binary_string);
return 0;
}
void decimal_to_binary(int number)
{
if (number == 0)
return;
else
{
int temp = number % 2;
//decimal_to_binary(number/2);
//you call decimal_to_binary again before increasing counter.
//That means every time you call decimal_to_binary, the value of count
//is 0 and you always write to the first character in the string.
//*(binary_string + counter) = temp;
//This is more readable
//binary_string[counter] = temp;
//But you are still setting the character at position counter to the literal value temp, which is either 0 or 1.
//if its 0, you are effectively writing a \0 (null character) which in C represents the end of a string.
//You want the *character* that represents the value of temp.
//in ASCII, the value for the *character* 0 is 0x30 and for 1 it is 0x31.
binary_string[counter] = 0x30 + temp;
counter++;
//Now after writing to the string and incrementing counter, you can call decimal_to_binary again
decimal_to_binary(number/2);
}
}
If you compile this, run the resulting executable and enter 16 as a number, you may expect to get 10000 as output. But you get00001. Why is that?
You are writing the binary digits to the string in the wrong order.
The first binary digit you calculate is the least significant bit, which you write to the first character in the string etc.
To fix that aswell, you can do:
void decimal_to_binary(int number){
if(number == 0){
return;
}
else{
int temp = number % 2;
counter++;
//Store the position of the current digit
int pos = counter;
//Don't write it to the string yet
decimal_to_binary(number/2);
//Now we know how many characters are needed and we can fill the string
//in reverse order. The first digit (where pos = 1) goes to the last character in the string (counter - pos). The second digit (where pos = 2) goes to the second last character in the string etc.
binary_string[counter - pos] = 0x30 + temp;
}
}
This is not the most efficient way, but it is closest to your original solution.
Also note that this breaks for negative numbers (consider decimal = -1, -1 % 2 = -1).

Сhanging even and odd characters in a string array

It is necessary that in the array 4 elements were selected, in these elements the indices changed 0-2, 1-3, then the next 4 elements were taken and so until the array ends
I tried to use built-in loops, but it didn't quite work out. Either the test was displayed shifted 2 indexes forward, or the first 2 indexes were transferred to the end
Code
Example
Without code we can't really help you fix it... but here is a solution:
#include <stdio.h>
#include <string.h>
int main()
{
char str[11] = "HelloWorld";
for(int i = 0; i < strlen(str); i += 2)
{
char tmp = str[i];
str[i] = str[i+1];
str[i+1] = tmp;
}
printf("%s", str);
return 0;
}
Output: eHllWorodl
Save the current character in a temporary variable, replace it with the next one.

C program randomly inserting random name of function into my array

I have the following program that converts decimal to binary:
#include <stdio.h>
#include <string.h>
int main() {
printf("Number (decimal): ");
int no;
scanf("%d", &no);
char bin[64];
while (no > 0) {
for (int i = strlen(bin); i > 0; i--) {
bin[i] = bin[i - 1];
}
int bit = no % 2;
char digit = bit + '0';
bin[0] = digit;
no /= 2;
}
printf("%s", bin);
return 0;
}
The program works correctly, but randomly the string "ttime__vdso_get" gets appended on the end.
The numbers that make it happen are different every time I compile.
1: 1
2: 01ttime_vsdo_get
3: 10ttime_vsdo_get
It becomes a little different when the numbers get bigger:
100039: 11000011011000111ttime__vdso_getm#
10000000000000000000000000000: ttime
What is happening?
If I had to diagnose it I'd say that I've managed to make a compiling program that's pulling memory from the wrong places. I don't know how how I managed to do it, though.
I'm using GCC, if it matters.
Just do char bin[64] = "";, never forget that a valid string is nul terminatedM#��M#.
And strlen() return an size_t !
I can also advice you to use char bin[sizeof no * CHAR_BIT + 1] = ""; that will use a correct maximum size for your string.
It may be because of this line of code :
for (int i = strlen(bin); i > 0; i--) {
bin[i] = bin[i - 1];
}
Try replacing strlen(bin) with 63.
It may also be a good idea to initialize your array bin with 0s.
try filling varible
char bin[64]
with 0

Pointers to string C

trying to write function that returns 1 if every letter in “word” appears in “s”.
for example:

containsLetters1("this_is_a_long_string","gas") returns 1
containsLetters1("this_is_a_longstring","gaz") returns 0
containsLetters1("hello","p") returns 0
Can't understand why its not right:
#include <stdio.h>
#include <string.h>
#define MAX_STRING 100
int containsLetters1(char *s, char *word)
{
int j,i, flag;
long len;
len=strlen(word);
for (i=0; i<=len; i++) {
flag=0;
for (j=0; j<MAX_STRING; j++) {
if (word==s) {
flag=1;
word++;
s++;
break;
}
s++;
}
if (flag==0) {
break;
}
}
return flag;
}
int main() {
char string1[MAX_STRING] , string2[MAX_STRING] ;
printf("Enter 2 strings for containsLetters1\n");
scanf ("%s %s", string1, string2);
printf("Return value from containsLetters1 is: %d\n",containsLetters1(string1,string2));
return 0;
Try these:
for (i=0; i < len; i++)... (use < instead of <=, since otherwise you would take one additional character);
if (word==s) should be if (*word==*s) (you compare characters stored at the pointed locations, not pointers);
Pointer s advances, but it should get back to the start of the word s, after reaching its end, i.e. s -= len after the for (j=...);
s++ after word++ is not needed, you advance the pointer by the same amount, whether or not you found a match;
flag should be initialized with 1 when declared.
Ah, that should be if(*word == *s) you need to use the indirection operator. Also as hackss said, the flag = 0; must be outside the first for() loop.
Unrelated but probably replace scanf with fgets or use scanf with length specifier For example
scanf("%99s",string1)
Things I can see wrong at first glance:
Your loop goes over MAX_STRING, it only needs to go over the length of s.
Your iteration should cover only the length of the string, but indexes start at 0 and not 1. for (i=0; i<=len; i++) is not correct.
You should also compare the contents of the pointer and not the pointers themselves. if(*word == *s)
The pointer advance logic is incorrect. Maybe treating the pointer as an array could simplify your logic.
Another unrelated point: A different algorithm is to hash the characters of string1 to a map, then check each character of the string2 and see if it is present in the map. If all characters are present then return 1 and when you encounter the first one that is not present then return 0. If you are only limited to using ASCII characters a hashing function is very easy. The longer your ASCII strings are the better the performance of the second approach.
Here is a one-liner solution, in keeping with Henry Spencer's Commandment 7 for C Programmers.
#include <string.h>
/*
* Does l contain every character that appears in r?
*
* Note degenerate cases: true if r is an empty string, even if l is empty.
*/
int contains(const char *l, const char *r)
{
return strspn(r, l) == strlen(r);
}
However, the problem statement is not about characters, but about letters. To solve the problem as literally given in the question, we must remove non-letters from the right string. For instance if r is the word error-prone, and l does not contain a hyphen, then the function returns 0, even if l contains every letter in r.
If we are allowed to modify the string r in place, then what we can do is replace every non-letter in the string with one of the letters that it does contain. (If it contains no letters, then we can just turn it into an empty string.)
void nuke_non_letters(char *r)
{
static const char *alpha =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
while (*r) {
size_t letter_span = strspn(r, alpha);
size_t non_letter_span = strcspn(r + letter_span, alpha);
char replace = (letter_span != 0) ? *r : 0;
memset(r + letter_span, replace, non_letter_span);
r += letter_span + non_letter_span;
}
}
This also brings up another flaw: letters can be upper and lower case. If the right string is A, and the left one contains only a lower-case a, then we have failure.
One way to fix it is to filter the characters of both strings through tolower or toupper.
A third problem is that a letter is more than just the 26 letters of the English alphabet. A modern program should work with wide characters and recognize all Unicode letters as such so that it works in any language.
By the time we deal with all that, we may well surpass the length of some of the other answers.
Extending the idea in Rajiv's answer, you might build the character map incrementally, as in containsLetters2() below.
The containsLetters1() function is a simple brute force implementation using the standard string functions. If there are N characters in the string (haystack) and M in the word (needle), it has a worst-case performance of O(N*M) when the characters of the word being looked for only appear at the very end of the searched string. The strchr(needle, needle[i]) >= &needle[i] test is an optimization if there are likely to be repeated characters in the needle; if there won't be any repeats, it is a pessimization (but it can be removed and the code still works fine).
The containsLetters2() function searches through the string (haystack) at most once and searches through the word (needle) at most once, for a worst case performance of O(N+M).
#include <assert.h>
#include <stdio.h>
#include <string.h>
static int containsLetters1(char const *haystack, char const *needle)
{
for (int i = 0; needle[i] != '\0'; i++)
{
if (strchr(needle, needle[i]) >= &needle[i] &&
strchr(haystack, needle[i]) == 0)
return 0;
}
return 1;
}
static int containsLetters2(char const *haystack, char const *needle)
{
char map[256] = { 0 };
size_t j = 0;
for (int i = 0; needle[i] != '\0'; i++)
{
unsigned char c_needle = needle[i];
if (map[c_needle] == 0)
{
/* We don't know whether needle[i] is in the haystack yet */
unsigned char c_stack;
do
{
c_stack = haystack[j++];
if (c_stack == 0)
return 0;
map[c_stack] = 1;
} while (c_stack != c_needle);
}
}
return 1;
}
int main(void)
{
assert(containsLetters1("this_is_a_long_string","gagahats") == 1);
assert(containsLetters1("this_is_a_longstring","gaz") == 0);
assert(containsLetters1("hello","p") == 0);
assert(containsLetters2("this_is_a_long_string","gagahats") == 1);
assert(containsLetters2("this_is_a_longstring","gaz") == 0);
assert(containsLetters2("hello","p") == 0);
}
Since you can see the entire scope of the testing, this is not anything like thoroughly tested, but I believe it should work fine, regardless of how many repeats there are in the needle.

Array manipulation in C

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;
}

Resources