I got a homework question. I'm so close to complete program. I'm having trouble about one thing. This is the question:
Write a C program that generates and displays a character array of size 10 consisting of
random English lower-case letters. The program then asks the user how many times the array
will be right-shifted and displays the right shifted array at each right-shifting step. A sample
program execution output is given below. ( Hint: Use the ASCII codes of the English lower-case
letters which are 97, 98, ... 122 for a, b, ..., z, respectively, to generate the character array).
This is my code:
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
void print_string (char *string){
int i;
for (i=0 ; i < 10 ; i ++){
printf("%c ", string[i]);
if (i == 9)
printf("\n");
}
}
void random_string(char *string, unsigned length)
{
/* Seed number for rand() */
srand((unsigned int) time(0) + getpid());
/* ASCII characters 97 to 122 */
int i;
for (i = 0; i < length; ++i)
{
string[i] = (rand() % 26)+ 97;
}
string[i] = '\0';
}
void reverse_string(char* str, int left, int right) {
char* p1 = str + left;
char* p2 = str + right;
while (p1 < p2) {
char temp = *p1;
*p1 = *p2;
*p2 = temp;
p1++;
p2--;
}
}
void rotate(char* str, int k, int n) {
reverse_string(str, 0, n-1);
reverse_string(str, 0, k-1);
reverse_string(str, k, n-1);
}
int main(void)
{
char s[11];
int i,shiftNum;
random_string(s, 11);
printf("Randomly constructed array is :\n");
print_string(s);
printf("Enter how many times array will be shifted: ");
scanf("%d",&shiftNum);
rotate(s,shiftNum,11);
print_string(s);
}
What's wrong with this code? When I execute it with 1, I couldn't get the first reverse correctly and I want to display all shifting steps.
For a start, it is atrocious that your lecturer/professor is telling you to use 97..122. C does not require that ASCII be the character set on every system, so this code is entirely non-portable, yet if you look at the history as far as Unix is concerned C is supposed to be a portable programming language. If you want to write this in a portable way, you need to store the characters in an array and select from that array:
char lowercase[] = "abcdefghijklmnopqrstuvwxyz";
string[i] = lowercase[rand() % (sizeof lowercase - 1)];
Now that we've covered that pedantic detail, Cool Guy indicated in a comment that this line of code is erroneous: string[i] = '\0';. He's correct about that.
This should also performed within main, not within random_string: srand((unsigned int) time(0) + getpid());. The reason is that calling random_string multiple times in the same second would result in the same "random string", which is very uncool.
scanf("%d",&shiftNum); can't guarantee success (that the user will input numeric data), and so can't guarantee that shiftNum will contain a sane value. You need to check the return value. For example:
if (scanf("%d", &shiftNum) != 1) {
puts("Invalid shift count!\n");
exit(0);
}
You should probably also consider using an unsigned type for shiftNum (and this will cause the corresponding format spec %d to change to something else, such as %u for unsigned int).
One more important task before I finish this task: You need to modify rotate to handle an input of 0 correctly, since some users might want to rotate/shift 0 times (as an alternative to not rotating/shifting at all). I'm confident that this should be an easy task for you.
Related
I'm sorry if my question is quite vague, because it is without context. So I was trying to solve a question: Write a recursive version of the function itoa(i) which converts an integer i into a string.
As I ran out of idea how to solve it, I started looking online to find solutions and I came across some of them which usually use this line: itoa(n/10, s);. For example, from this StackOverflow question: itoa recursively. I can't understand what it does to i.
So I went on and searched for more solutions and I found one that actually works, the program looks like this:
#include <stdio.h>
char *itoa(int n, char s[]);
int main()
{
char number[100];
printf("-90 to string = %s\n", itoa(-90, number));
return 0;
}
char *itoa(int n, char s[])
{
static int i = 0;
if (n < 0) {
s[i++] = '-';
n = -n; /* does not work for largest negative number in two complement */
}
if (n / 10)
itoa(n /10, s);
s[i++] = n % 10 + '0';
s[i] = '\0';
return s;
}
Problem is, according to the solutions I found on other websites, people said that we should avoid using static int i. I did not read why we should do so because I don't know how static works so I don't know if this program is fine or needs improvements.
Your function pretty much almost right, that is for a recursive method. If you were going to parse the digit to string backward, it is right. Otherwise, I just did a couple fix.
For parsing digit to string, the digits that are being parsed are from the right digits to left digits as the remainder is what being used. Thus, when storing those into a string, we will need to go from high to low indexes. If we use remainders for parsing, we will not know the length of the number that is being parsed. Thus, in most parse cases there will be some extra spaces at the beginning of your string or char array.
For using the static i, you can pass a version of it around but it would make it harder to use as you would need to know to always have to pass i at 11. "i" is at 11 because the maximum digits for an int is 10(digits) + 1 sign and the 12th character which not counted by "i" is the null char. To make it easier to use the function, I configured the third parameter to be a void pointer. However, do not pass it an actual pointer, pass it a NULL. When it see NULL as the third parameter, it know that, that is the first call.
#include <stdio.h>
#include <string.h>
char *itoa(int n, char s[], void * );
int main()
{
char number[100] = {0};
printf("-90 to string = %s\n", itoa(154, number, NULL));
printf("-15 to string = %s\n", itoa(-15, number, NULL));
printf("-2147483648 to string = %s\n", itoa(-2147483648, number, NULL));
return 0;
}
// The reason why I pass a void pointer is because
// instead of passing the value is because it easier to use function without needing to know that the string have to go from right left.
// When you first call it just use NULL as the third parameter. Anything else can ruin it.
char *itoa(int n, char s[], void * firstCall )
{
static int i;
if ( firstCall == NULL ) {
i = 11;
s[11] = 0;
}
int neg = 0;
if (n < 0) {
if ( n == -2147483648 ) {
strcpy(s, "-2147483648");
return s;
}
neg=1;
n = -n; /* does not work for largest negative number in two complement */
}
s[--i] = (n % 10) ^ 48;
if ( n / 10 ) itoa(n / 10, s, s);
if ( neg == 1 ) s[--i] = '-';
return &s[i];
}
Code segment below to extract the first two numerical characters of string str[] and place them into i1 as the decimal value they denote and extract the last two numerical characters of string str and place them into i2 as the decimal value they denote; such that the print statement at the bottom will print 12 and 67 to the screen.
#include<stdio.h>
main(){
char str[]="1234567";
int i1, i2;
//write code here
printf("%d %d\n, i1, i2);
}
I am stuck with what to do. I am assuming I am suppose to use strcat(i1, i2) but I am not getting 12 and 67 when I print it out.
What is the solution to this? Thanks for the help!
Numeric character codes are guaranteed to be in a series
(from 0 to 9. E.g '0' + 1 become '1'),
so you can convert them to numbers by subtracting '0'.
Also Since the end of the string has NUL characters('\0' or simply 0),
you can find the last two letters by looking for it.
(E.g. str[index] == '\0' or str[index] == 0 or simply !str[index])
So on the whole it can be written as one example as follows.
#include <stdio.h>
int main(void){
char str[]="1234567";
int i1, i2;
#define dc2i(dc) ( dc - '0' ) //convert one digit character to int
#define d22i( s) ( 10*dc2i(*s) + dc2i(s[1]) ) //two digit to int
{
const char *i1p = str, *i2p;
//Is it necessary to check if the whole is composed only of numeric characters?
if(!*str || !str[1]){//Is it length of 2 or more? (Do you need a length of 4 or more?)
fprintf(stderr, "'%s' is too short string.", str);
return 1;
}
for(const char *p = str; *p && p[1]; ++p)
i2p = p;//save last pointer
i1 = d22i(i1p);
i2 = d22i(i2p);
}
printf("%d %d\n", i1, i2);
}
If your string has a length equal to or larger than four, and consists only of numerical digits, this piece of code should do the trick. Your assumption was not wrong though, your problem can indeed be solved with the strcat() function, but it is slightly longer and a little more complicated.
#include <stdio.h>
#include <string.h>
main(){
char str[]="1234567";
int i1, i2;
i1 = (str[0] - '0') * 10 + (str[1] - '0');
int length = strlen(str);
i2 = (str[length - 2] - '0') * 10 + (str[length - 1] - '0');
printf("%d %d\n", i1, i2);
return 0;
}
While you can convert directly to i1 and i2 with a manual convert from character to int, stdlib.h provides the strto.. family of functions to preform the conversion for you while providing error checking. (e.g. strtol, strtoul, etc..). While the conversion itself is fairly trivial, always check if a standard library function already does what you are attempting to do. Chances are, if one exists, it has had decades of use and validation and will probably preform quite a bit better than what you reinvent.
Taking this route, your task become simply creating substrings of str containing the needed digits, and then passing the substrings to strtol for conversion to int (while strtol returns a long value, given the explicit definition of str in this case, there is no potential for exceeding the storage capacity of int and no possibility of encountering something other than digits in the string) As such, a simple check of errno can provide assurance that a conversion from str to long took place and a cast to int will resolve the type difference.
Putting those pieces together, you can do something similar to the following:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
enum { NCHR = 2, NOFF = 5 }; /* constants, no. chars, i2 offset */
int main (void) {
char str[]="1234567",
buf1[NCHR + 1] = "", /* buffer to hold substrings */
buf2[NCHR + 1] = ""; /* initialized to provide termination */
int i1 = 0,
i2 = 0;
for (int i = 0; i < NCHR; i++) { /* fill substrings */
buf1[i] = str[i]; /* buf1[] = "12" */
buf2[i] = str[i + NOFF]; /* buf2[] = "67" */
}
errno = 0; /* initialize errno */
i1 = (int)strtol (buf1, NULL, 10); /* perform converstions */
i2 = (int)strtol (buf2, NULL, 10);
if (errno) { /* validate errno remains 0 or handle error */
fprintf (stderr, "error: failed converstion for i1 or l2.\n");
return 1;
}
printf ("i1 = %d\ni2 = %d\n", i1, i2);
return 0;
}
note: both buf1 and buf2 must end with the nul-terminating character '\0' (or equivalently 0). Termination is insured by initializing all characters in each to 0 when they are declared -- and not overwriting the final 0 during use in your code.
Example Use/Output
$ ./bin/subst2int
i1 = 12
i2 = 67
Either way you choose to approach the problem is fine. No one way is more-correct than then other as long as your code is valid (you can worry about optimizations and tweaking the number of instructions well down the road in your learning of C). Look things over in all answers, and let any of the authors know if you have questions.
I need to write a function that gets a string and a number N, the function will return in the same pointer the encrypted string. The function will encrypt a string by the following rules:
Reverse the string, e.g: if the string is "Amnon" the result would be "nonmA".
After the reverse, each letter needs to be replaced by the value of N, e.g: if N=3 then instead of "nonmA" the result would be "qrqpD".
I had no problem doing the reverse part but I'm struggling with switching each letter. Here is the code I wrote so far:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void StRreverse(char* mystr, int N);
void StRreverse(char* mystr, int N)
{
int c, length, n;
char *begin, *end, temp;
length = strlen(mystr);
begin = mystr;
end = mystr;
for (c = 0; c < length - 1; c++)
{
end++;
}
for (c = 0; c < length / 2; c++)
{
temp = *end;
*end = *begin;
*begin = temp;
begin++;
end--;
}
}
void main()
{
char string[100];
printf("Enter some text\n");
gets(string);
StRreverse(string);
printf("Reverse of entered string is \"%s\".\n", string);
system("pause");
}
First, identify 'letters' in a portable way:
#include <ctype.h>
Then you can use isalpha(mystr[c]) to generally identify letters, and specifically islower and isupper. Then, on each letter, add your constant modulo 26. That is, if a becomes b, then y becomes z and z would be a again.
This operation is encoding-dependent as not all encodings have "a" to "z" and "A" to "Z" defined consecutively. Fortunately, it's unlikely you have such a system :) (although it is an interesting exercise to work out a way where this would not be an issue!).
The trick is to 'wrap around' with an offset of either A or a, so capitals and lowercase need a separate line of code:
if (isupper(mystr[c]))
mystr[c] = 'A' + ((mystr[c]-'A' + N + 26) % 26);
if (islower(mystr[c]))
mystr[c] = 'a' + ((mystr[c]-'a' + N + 26) % 26);
where N can be as low as -25, or as high as you want. That lower limit (and the addition of 26 in the statements) is because in some implementations of C, taking the modulus of a negative number returns a negative number as well.
To decode this text -- properly called the Caesar Cypher --, you can apply the same formula with -N.
The most simple way to do switching is by adding the number to that character. For example
`char str[n] = {'a','b','c','d'};
for(int i=0; i less than n; i++)
str[i] = str[i] +3; // we are adding 3 to switch
`
I dont remeber the ascii number for small 'a'. But if its 36 the above code will make it 39 which will be 'd'. Hope it works for u
I am looking for a (relatively) simple way to parse a random string and extract all of the integers from it and put them into an Array - this differs from some of the other questions which are similar because my strings have no standard format.
Example:
pt112parah salin10n m5:isstupid::42$%&%^*%7first3
I would need to eventually get an array with these contents:
112 10 5 42 7 3
And I would like a method more efficient then going character by character through a string.
Thanks for your help
A quick solution. I'm assuming that there are no numbers that exceed the range of long, and that there are no minus signs to worry about. If those are problems, then you need to do a lot more work analyzing the results of strtol() and you need to detect '-' followed by a digit.
The code does loop over all characters; I don't think you can avoid that. But it does use strtol() to process each sequence of digits (once the first digit is found), and resumes where strtol() left off (and strtol() is kind enough to tell us exactly where it stopped its conversion).
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
int main(void)
{
const char data[] = "pt112parah salin10n m5:isstupid::42$%&%^*%7first3";
long results[100];
int nresult = 0;
const char *s = data;
char c;
while ((c = *s++) != '\0')
{
if (isdigit(c))
{
char *end;
results[nresult++] = strtol(s-1, &end, 10);
s = end;
}
}
for (int i = 0; i < nresult; i++)
printf("%d: %ld\n", i, results[i]);
return 0;
}
Output:
0: 112
1: 10
2: 5
3: 42
4: 7
5: 3
More efficient than going through character by character?
Not possible, because you must look at every character to know that it is not an integer.
Now, given that you have to go though the string character by character, I would recommend simply casting each character as an int and checking that:
//string tmp = ""; declared outside of loop.
//pseudocode for inner loop:
int intVal = (int)c;
if(intVal >=48 && intVal <= 57){ //0-9 are 48-57 when char casted to int.
tmp += c;
}
else if(tmp.length > 0){
array[?] = (int)tmp; // ? is where to add the int to the array.
tmp = "";
}
array will contain your solution.
Just because I've been writing Python all day and I want a break. Declaring an array will be tricky. Either you have to run it twice to work out how many numbers you have (and then allocate the array) or just use the numbers one by one as in this example.
NB the ASCII characters for '0' to '9' are 48 to 57 (i.e. consecutive).
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
int main(int argc, char **argv)
{
char *input = "pt112par0ah salin10n m5:isstupid::42$%&%^*%7first3";
int length = strlen(input);
int value = 0;
int i;
bool gotnumber = false;
for (i = 0; i < length; i++)
{
if (input[i] >= '0' && input[i] <= '9')
{
gotnumber = true;
value = value * 10; // shift up a column
value += input[i] - '0'; // casting the char to an int
}
else if (gotnumber) // we hit this the first time we encounter a non-number after we've had numbers
{
printf("Value: %d \n", value);
value = 0;
gotnumber = false;
}
}
return 0;
}
EDIT: the previous verison didn't deal with 0
Another solution is to use the strtok function
/* strtok example */
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] = "pt112parah salin10n m5:isstupid::42$%&%^*%7first3";
char * pch;
printf ("Splitting string \"%s\" into tokens:\n",str);
pch = strtok (str," abcdefghijklmnopqrstuvwxyz:$%&^*");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, " abcdefghijklmnopqrstuvwxyz:$%&^*");
}
return 0;
}
Gives:
112
10
5
42
7
3
Perhaps not the best solution for this task, since you need to specify all characters that will be treated as a token. But it is an alternative to the other solutions.
And if you don't mind using C++ instead of C (usually there isn't a good reason why not), then you can reduce your solution to just two lines of code (using AXE parser generator):
vector<int> numbers;
auto number_rule = *(*(axe::r_any() - axe::r_num())
& *axe::r_num() >> axe::e_push_back(numbers));
now test it:
std::string str = "pt112parah salin10n m5:isstupid::42$%&%^*%7first3";
number_rule(str.begin(), str.end());
std::for_each(numbers.begin(), numbers.end(), [](int i) { std::cout << "\ni=" << i; });
and sure enough, you got your numbers back.
And as a bonus, you don't need to change anything when parsing unicode wide strings:
std::wstring str = L"pt112parah salin10n m5:isstupid::42$%&%^*%7first3";
number_rule(str.begin(), str.end());
std::for_each(numbers.begin(), numbers.end(), [](int i) { std::cout << "\ni=" << i; });
and sure enough, you got the same numbers back.
#include <stdio.h>
#include <string.h>
#include <math.h>
int main(void)
{
char *input = "pt112par0ah salin10n m5:isstupid::42$%&%^*%7first3";
char *pos = input;
int integers[strlen(input) / 2]; // The maximum possible number of integers is half the length of the string, due to the smallest number of digits possible per integer being 1 and the smallest number of characters between two different integers also being 1
unsigned int numInts= 0;
while ((pos = strpbrk(pos, "0123456789")) != NULL) // strpbrk() prototype in string.h
{
sscanf(pos, "%u", &(integers[numInts]));
if (integers[numInts] == 0)
pos++;
else
pos += (int) log10(integers[numInts]) + 1; // requires math.h
numInts++;
}
for (int i = 0; i < numInts; i++)
printf("%d ", integers[i]);
return 0;
}
Finding the integers is accomplished via repeated calls to strpbrk() on the offset pointer, with the pointer being offset again by an amount equaling the number of digits in the integer, calculated by finding the base-10 logarithm of the integer and adding 1 (with a special case for when the integer is 0). No need to use abs() on the integer when calculating the logarithm, as you stated the integers will be non-negative. If you wanted to be more space-efficient, you could use unsigned char integers[] rather than int integers[], as you stated the integers will all be <256, but that isn't a necessity.
The program I wrote works in demographics consisting of only single Hexadecimal values. (Probably not the most elegant solution, but I'm a new programmer) My question is, how would I go about handling of multiple hexadecimal digits, such as 0xAF, or 0xFF, etc? I'm not exactly sure, and I've seemed confuse myself greatly, in the attempt. I'm not asking for someone to hold my hand, but to give me a tip where I've gone wrong in this code and thoughts on how to fix it.
Thanks :)
/* Exercise 2-3. Write the function htoi(s), which converts a string of
* hexadecimal digits (including an optional 0x or 0X) into it's equivalent
* integer value. The allowable digits are 0...9 - A...F and a...f.
*
*/
#include <stdio.h>
#include <string.h>
#define NL '\n'
#define MAX 24
int htoi(char *hexd);
int
main(void)
{
char str[MAX] = {0};
char hex[] = "0123456789ABCDEFabcdef\0";
int c;
int i;
int x = 0;
while((c = getchar()) != EOF) {
for(i = 0; hex[i] != '\0'; i++) {
if(c == hex[i])
str[x++] = c;
}
if(c == NL) {
printf("%d\n", htoi(str));
x = 0, i = x;
}
}
return 0;
}
int
htoi(char *hexd)
{
int i;
int n = 0;
for(i = 0; isdigit(hexd[i]); i++)
n = (16 * i) + (hexd[i] - '0');
for(i = 0; isupper(hexd[i]); i++) /* Let's just deal with lowercase characters */
hexd[i] = hexd[i] + 'a' - 'A';
for(i = 0; islower(hexd[i]); i++) {
hexd[i] = hexd[i] - 'a';
n = (16 + i) + hexd[i] + 10;
n = hexd[i] + 10;
}
return n;
}
Someone has alredy asked this (hex to int, k&r 2.3).
Take a look, there are many good answers, but you have to fill in the blanks.
Hex to Decimal conversion [K&R exercise]
Edit:
in
char hex[] = "0123456789ABCDEFabcdef\0";
The \0 is not necesary. hex is alredy nul terminated. Is len (0...f) + 1 = 17 bytes long.
I'll pick on one loop, and leave it to you to rethink your implementation. Specifically this:
for(i = 0; isdigit(hexd[i]); i++)
n = (16 * i) + (hexd[i] - '0');
doesn't do what you probably think it does...
It only processes the first span of characters where isdigit() is TRUE.
It stops on the first character where isdigit() is FALSE.
It doesn't run past the end because isdigit('\0') is known to be FALSE. I'm concerned that might be accidentally correct, though.
It does correctly convert a hex number that can be expressed solely with digits 0-9.
Things to think about for the whole program:
Generally, prefer to not modify input strings unless the modification is a valuable side effect. In your example code, you are forcing the string to lower case in-place. Modifying the input string in-place means that a user writing htoi("1234") is invoking undefined behavior. You really don't want to do that.
Only one of the loops over digits is going to process a non-zero number of digits.
What happens if I send 0123456789ABCDEF0123456789ABCDEF to stdin?
What do you expect to get for 80000000? What did you get? Are you surprised?
Personally, I wouldn't use NL for '\n'. C usage pretty much expects to see \n in a lot of contexts where the macro is not convenient, so it is better to just get used to it now...
I think that the MAX size of string should be either 10 or 18 instead of 24. (If you have already checked the int on your machine and followed the reasoning bellow, it would be beneficial to include it as a comment in your code.)
10 : since htoi() returns an int , int is usually 4 bytes (check your system's too), so the hexadecimal number can be atmost 8 digits in length (4bits to 1 hex digit, 8 bits to a byte), and we want to allow for the optional 0x or 0X.
18 : would be better if htoi() returned a long and its 8 bytes (again, check your system's), so the hexadecimal number can be atmost 16 digits in length, and we want to allow for the optional 0x or 0X.
Please note that that sizes of int and long are machine dependent, and please look at exercise 2.1 in the K&R book to find them.
Here is my version of a classic htoi() function to convert multiple hexadecimal values into decimal integers. It's a full working program compile it and run.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
int htoi(const char*);
int getRawInt(char);
int main(int argc, char **argv) {
char hex[] = " ";
printf("Enter a hexadecimal number (i.e 33A)\n");
scanf("%s", hex);
printf("Hexedecimal %s in decimal is %d\n", hex, htoi(hex)); // result will be 826
return 0;
}
int htoi(const char *hex) {
const int LEN = strlen(hex) -1;
int power = 1;
int dec = 0;
for(int i = LEN; i >= 0; --i) {
dec += getRawInt(hex[i]) * power;
power *= 16;
}
return dec;
}
int getRawInt(char c) {
if(isalpha(c)) {
return toupper(c) - 'A' + 10;
} return c-'0';
}