K&R 2-3 htoi segmentation fault - c

Hi this is my first question here so I apologize if I didn't follow all the rules for posting. This is K&R exercise 2-3 and I'm getting a segmentation fault when compiling with GCC and I'm not familiar with the debugger to understand what's going on. I'd be grateful if anyone could glance over the code and help me with what went wrong.
#include <stdio.h>
#define HEX 16
unsigned int htoi(char s[]) {
int i, len, n, rp, v;
v = 0;
if (s[0] == '0')
if (s[1] == 'x' || s[1] == 'X')
s[1] = '0';
for (len = 0; len != '\0'; ++len) {
}
for (i = len; i >= 0; --i) {
if (s[i] >= '0' && s[i] <= '9')
n = s[i] - '0';
else if (s[i] >= 'A' && s[i] <= 'F')
n = s[i] - 'A' + 10;
else if (s[i] >= 'a' && s[i] <= 'f')
n = s[i] - 'a' + 10;
rp = len - i;
v += n * HEX^rp;
}
return v;
}
int main() {
int test = htoi("0x1a9f");
printf("%d\n", test);
return 0;
}

You are passing the address of a string literal which is read-only. Doing the following will get rid of the segmentation fault.
char temp[] = "0x1a9f";
int test = htoi(temp);
Also:
v += n * HEX^rp;
Is ^ is the XOR operator and not the power operator. For power you need the pow function in math.h
Also:
for (i = len; i >= 0; --i) should be for (i = len - 1; i >= 0; --i) because the value of len goes out of the bound of the array. (Notified by #Grijesh Chauhan and #simonc)

int test = htoi("0x1a9f");
passes the string literal "0x1a9f" to htoi. This may exist in read-only memory and cannot be modified. You therefore get undefined behaviour (with a crash a valid example of this) when you try to write to the string in the line
s[1] = '0';
The easiest fix is to copy the original string into a modifiable variable
char s[] = "0x1a9f";
int test = htoi(s);
As reported by Grijesh, further into htoi, you also read beyond the bounds of the string
for (i = len; i >= 0; --i)
should be:
for (i = len - 1; i >= 0; --i)

Related

My cipher code will compile but does not print — what error have I made? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
Pseudocode explanation of what I am attempting to do.
Convert a character array into an integer array
Iterate through each integer in that array and add q to it, unless that integer + q exceeds an upper bound. If it exceeds that number, return the modulus and add the modulus to a lower bound.
print the converted integer array in its ASCII sequence using %c.
Here is the example:
int main(void)
{
char char_message[] = "abcyzABCYZ";
int q = 10;
int i;
int message[10];
int n = strlen(char_message);
for(i = 0; i < n; i++) {
message[i] = atoi(&char_message[i]);
}
for(i = 0; i < n; i++) {
if(message[i] <= 90) {
if (message[i] + q <= 90) {
message[i] = message[i] + q;
}
else
message[i] = 65 + (message[i] % 90);
}
else if(message[i] >= 97) {
if (message[i] + q <= 122) {
message[i] = message[i] + q;
}
else
message[i] = 97 + (message[i] % 122);
}
}
for(i = 0; i < n; i++) {
printf("%c", message[i]);
}
return 0;
}
EDIT: Below is a second attempt at this problem --------------------------
int main(int argc, char *argv[]) {
if(argc != 3) {
printf("Enter an integer followed by a string \n\n");
return 1;
}
int i;
int offset = atoi(argv[1]);
char **p_message;
p_message = &argv[2];
char encrypt[strlen(*p_message)];
printf("You Entered: %d, %s \n", offset, *p_message);
for(i = 0; i < strlen(*p_message); i++)
{
encrypt[i] = ((*p_message[i] + offset) % 26);
}
for(i = 0; i < strlen(*p_message); i++)
{
printf("%c", encrypt[i]);
}
return 0;
}
I'm not doing your homework for you, but it is obvious that two things are clearly wrong.
Your use of atoi is incorrect. It should not be here at all.
Your calculation of the resulting enciphered character is wrong as well. The modulus placement is wrong in two different locations.
Your use of "magic numbers" in this code is rampant making it much, much more difficult to read than need-be. Avoid using magic numbers.
The following "enciphers" your test string via a simple forward scanning loop, output each resulting character one at a time. I've left the storage to a separate int array for you to handle. Of note the first if-block is expanded out statement by statement so you can see what is going on one step at a time. The second (lower case handling) is done in a single expression. Other than different ranges, the two methods of calculation are equivalent.
Note: this only works on platforms where character ranges A..Z and a..z are continuous. The language standard makes no enforcement of this; it only enforces it for digit characters 0..9. Thus, don't blame me if you run this on an AS/400 or OS/390 (both EBCDIC platforms) and it doesn't work.
#include <stdio.h>
#include <string.h>
int main()
{
char message[] = "abcyzABCYZ";
const int q = 10;
puts(message);
for(const char *p = message; *p; ++p)
{
int c = (unsigned char)*p;
if (c >= 'A' && c <= 'Z')
{
c -= 'A';
c += q;
c %= ('Z' - 'A' + 1);
c += 'A';
}
else if (c >= 'a' && c <= 'z')
c = ((c - ('a' - q)) % ('z' - 'a' + 1)) + 'a';
// else nothing. keep as-is
fputc(c, stdout);
}
fputc('\n', stdout);
return 0;
}
Output
abcyzABCYZ
klmijKLMIJ

scanning a 128 bit input represented in 32 hex values

I need to scan the 32 hex number from command line and populated it into a uint8_t [16] array, I tried scanning the string and convert it to hex but its really a hassle since i cant find a function that does that, whats the best way to do this?
uint8_t get_int(char c)
{
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'A' && c <= 'F') return 10 + c - 'A';
if (c >= 'a' && c <= 'f') return 10 + c - 'a';
return -1;
}
int main(void)
{
char buff[33];
size_t size;
size_t i;
uint8_t *output;
fgets(buff, sizeof buff, stdin);
size = strlen(buff) / 2;
output = malloc(size);
for (i= 0; i < size; ++i)
output[i] = get_int(buff[2*i]) * 16 + get_int(buff[2*i+1]);
for (i= 0; i < size; ++i)
printf("%u ", output[i]);
return 0;
}
ideone link

Trouble checking a string for numbers in C

I've checked similar questions posted here on the forum, but none of those answers my question.
I have a string (char s []) and I want to 'copy' the numbers in that string to another one (char n []).
Here's my attempt at this:
char s[] = "oa323shsh123383.33hbabsa3€"
int len = strlen(s);
char n[];
int k;
for (k = 0; k <= len; k++){
if( s[k] >= '0' || s[k] <= '9') {
n[k] = s[k] - 48;
}
}
However this is wrong, because it doesn't print out anything. Can anybody help me ?
Use && in your IF.
Allocate your array n. Easy way is to declare n as
char n[] = char[len+1];
Use another variable to count the number being added to n, otherwise you will have n being:
"..323....123383" etc
Should end up with something like
char s[] = "oa323shsh123383.33hbabsa3€"
int len = strlen(s);
char n[] = char[len+1];
int k, j=0;
for (k = 0; k <= len; k++){
if( s[k] >= '0' && s[k] <= '9') {
n[j] = s[k] - 48;
n[j+1] = '\0';
j++;
}
}
char s[] = "oa323shsh123383.33hbabsa3€";
int len = strlen(s);
char* n = (char*) malloc(len+1);
int i,j=0;
for (i = 0; i < len; ++i)
{
if( s[i] >= '0' && s[i] <= '9')
n[j++] = s[i];
}
n[j]=0;
n is now a printable string
dont forget to free it when you are done.

Program prints memory address when converting hexadecimal to an integer

I have seen other solutions to this problem where a pointer is used. I don't understand the workings of a pointer enough to implement them into this program. If the solution requires one, would someone please be able to explain why? I have been trying various things with this program all night and gotten nowhere. I read the relevant text in 'The C Programming Language' book, where the exercise is from. I can't be the only person stumped by this D:
#include <stdio.h>
#include <math.h>
#include <ctype.h>
#define MAX 1000
int htoi(char s[]);
main()
{
char line[MAX];
int i, c;
printf("Enter the strig to convert to an integer:");
for(i=0; i<MAX && (c=getchar())!=EOF && c != '\n'; ++i)
line[i] = c;
int a =0;
a = htoi(line);
printf("%d", a);
}
int htoi(char s[])
{
int i, n, z;
n=0;
int total = 0;
for(i=0; s[i] != '\0'; ++i)
{
if (s[i] == 'a'||s[i] == 'A')
n = 10;
else if(s[i] == 'b'||s[i] == 'B')
n = 11;
else if(s[i] == 'c'||s[i] == 'C')
n = 12;
else if(s[i] == 'd'||s[i] == 'D')
n = 13;
else if(s[i] == 'e'||s[i] == 'E')
n = 14;
else if(s[i] == 'f'||s[i] == 'F')
n = 15;
else
n = s[i];
z = n * pow(16, i);
total = total + z;
}
return total;
}
Someone correct me if I am wrong. But you're not putting a null terminator in your char array:
for(i=0; i<MAX && (c=getchar())!=EOF && c != '\n'; ++i)
line[i] = c;
Later on, you do
for(i=0; s[i] != '\0'; ++i)
But since you never appended a null terminator the above for loop will iterate PAST the bounds of the array until it sees a null somewhere on the stack or it segfaults.
you should be doing the following:
for(i=0; i<(MAX-1) && (c=getchar())!=EOF && c != '\n'; ++i)
line[i] = c;
line[i+1] = '\0';
Note the (MAX-1)
P.S Don't run anything that doesn't require root as root, see: least privilege principle
Your problem is here:
else
n = s[i]; // <- n is getting the character code value of S[i]
To solve, I suggest to do:
else
n = s[i] - '0';
EDITED:
You have two problems else:
You need to null terminate the line char (your string hasn't '\0')
You are inverting the power math (digit more at left are more significants than at right position)
To solve (1), do that:
for(i=0; i<MAX && (c=getchar())!=EOF && c != '\n'; ++i)
line[i] = c;
line[i] = '\0'; // <-- added here
To solve (2), do that:
int total = 0;
int len = strlen(s) - 1; // <- added here
...
z = n * pow(16, len - i); // <- change here
Another way, you can avoid using the expensive pow function by just shifting 4 bits to left as in code bellow:
instead of:
z = n * pow(16, i);
total = total + z;
do:
total <<= 4; // changed here
total += n; // and here

About Rot13-Implementation

I am trying to implement the rot13-algorithm in C.
But since I am not very familiar with that language, I have some problems with my code right here.
Basically, I want to rotate every letter in args[] to 13 positions up.
But this code seems to be pretty sluggish:
#include <stdio.h>
char[] rotate(char c[]) {
char single;
int i;
int alen = sizeof(c)/sizeof(c[0]);
char out[alen];
for(i=0;i<=alen;i+=1) {
if(c[i]>='a' && (c[i]+13)<='z'){
out[i] = c[i]+13;
}
}
return out;
}
int main(int argc, char *argv[]) {
printf("The given args will be rotated\n");
int i;
char rotated[sizeof(argv)/sizeof(argv[0])];
rotated = rotate(argv);
/* printing rotated[] later on */
return 0;
}
I know there a lot of holes here - could you show me how to fix this?
Thanks a lot guys, I solved the problem with this code
#include <stdio.h>
int rot13(int c){
if('a' <= c && c <= 'z'){
return rot13b(c,'a');
} else if ('A' <= c && c <= 'Z') {
return rot13b(c, 'A');
} else {
return c;
}
}
int rot13b(int c, int basis){
c = (((c-basis)+13)%26)+basis;
return c;
}
int main() {
printf("The given args will be rotated");
int c;
while((c = getchar()) != EOF){
c = rot13(c);
putchar(c);
}
return 0;
}
How #Michael said this char out[alen] is not accepted by the compiler because you can't declare an array size with a non constant value. Another problem of your code is the for loop for( i = 0; i < = alen; i+=1 ) the arrays start on 0 so if you do the for until the lenght's position you will be out of the array.
About the code:
You must use a pointer to the start of the string as argument of the function, because You can't return arrays in C (But you can return pointers ).
Your if( str[i] >= 'a' && (str[i]+13) <='z') is incorrect because you will convert some letters into symbols take a look.
________
--------------------------!
void rotate( char * str )
{
int i = 0;
/* You do this until you find a '\0' */
for( i = 0; str[ i ] != '\0' ; i++ ){
/* Use the pointer notation if you passed a pointer. */
/* If the letter is between a and m you can simply sum it. */
if( *( str + i ) >= 'a' && *( str + i ) < 'n')
*( str + i ) += 13;
/* If the letter is between the n and z you have to do the opposite.*/
else if( *( str + i ) >= 'n' && *( str + i ) <= 'z')
*( str + i ) -= 13;
}
}
Size of arrays in C must be set at compile time, so you can't use non constant expression for array size.
Consider the below implementation:
// in place rotate
void rotate(char *str)
// str must be a zero-terminated string
{
int i =0;
// loop until str itself is not NULL and str[i] is not zero
for(i=0;str && str[i]; ++i) // ++i is a pre-increment
{
if(str[i] >= 'a' && (str[i]+13) <='z')
{
str[i] = str[i]+13; // modifying str in place
}
}
}
Then your main() can look like this:
int main(int argc, char *argv[])
{
printf("The given args will be rotated: %s\n", argv[1]);
rotate(argv[1]);
printf("Rotated: %s\n", argv[1]);
return 0;
}
Update More advanced version of the transform that takes care of case when str[i] + 13 > 'z'
for(i=0;str && str[i]; ++i) // ++i is a pre-increment
{
// ignore out of range chars
if (str[i] < 'a' || str[i] > 'z') continue;
// rotate
for (off = 13; off > ('z' - str[i]); )
{
off-= (1 + 'z' - str[i]);
str[i] = 'a';
}
str[i]+=off;
}
This function can encode/decode to/from rot13 string. It's compatible with VIM's g? rot13 encoder.
void rot13 (char *s) {
if (s == NULL)
return;
int i;
for (i = 0; s[i]; i++) {
if (s[i] >= 'a' && s[i] <= 'm') { s[i] += 13; continue; }
if (s[i] >= 'A' && s[i] <= 'M') { s[i] += 13; continue; }
if (s[i] >= 'n' && s[i] <= 'z') { s[i] -= 13; continue; }
if (s[i] >= 'N' && s[i] <= 'Z') { s[i] -= 13; continue; }
}
}

Resources