Treating numerical variables as text - c

I was not sure how to title this question, so I'll go straight to the code for you to see what I mean. Really new into this, so bear with me!
I have this code:
1 #include <cs50.h>
2 #include <stdio.h>
3 #include <string.h>
4
5 int main(int argc, string argv[])
6 {
7
8 if (argc!=2)
9 {
10 printf("error!! Usage: ./caesar k\n");
11 return 1;
12 }
13
14 printf("Plaintext: ");
15 string text=get_string();
16
17 char k=argv[1][0];
18 int n=strlen(text);
19
20
21 for (int i=0; i<n; i++)
22 {
23 if(text[i]>='a' && text[i]<='z')
24 {
25 printf("Cyphertext: %c\n", text[i]+k);
26 }
27 }
28 }
What's its purpose?
Well, given a text, it adds k to every character. Which means that, for abc, and k=1, the output would be bcd; for abc and k=3, output would be def.
Now, it is imperative that k is given as a command line argument.
What do I want to do?
Just take k (which is a number), add it to every character of the input string text, and voilà.
Since every letter is a number in ASCII, adding a number can change the character, so... it should work. [I am still trying to figure out how ASCII works, and when do char show up like charcters and not numbers... but anyway].
What is going on?
First, I am having trouble declaring k as an int or char. In line 17, -and although k is a number(!)- the IDE forces me to declare a string or char*: if I declare k as int I receive an error; if I declare char I receive an error too, unless I declare it not only as k=argv[1] but as k=argv[1][0], as shown in the code above.
Second, executing the code above, this is the input/output (the name of the program is caesar):
$./caesar
error!! Usage: ./caesar k
$./caesar 1
Plaintext: a
Cyphertext: (nothing...)
Third, given the error above, I changed the code in line 25 from this:
printf("Cyphertext: %c\n", text[i]+k);
to this:
printf("Cyphertext: %s\n", text[i]+k);
which returned this error message:
caesar.c:25:38: error: format specifies type 'char *' but the argument has
type 'int' [-Werror,-Wformat]
printf("Cyphertext: %s", text[i]+k);
~~ ^~~~~~~~~
%d`
error message I do not understand, given that neither text nor k are int.
Anyway, changing %c to %s did not work, so I tried with %i instead:
printf("Cyphertext: %i\n", text[i]+k)
which at least returned something:
$./caesar 1
Plaintext: a
Cyphertext: 146
$./caesar 5
Plaintext: a
Cyphertext: 150
So, basically, it is adding k to 150 -which is 'û' in ASCII, so...(?).
And, finally, apart from the fact the program returns a number I do not understand, I thought I could make it show up like letters/non-numerical characters adding this:
printf("Cyphertext: %i\n", (char)text[i]+k);
but it actually does not, the program returns exactly the same last output shown above.
So well, this is a much longer question than I expected, but I hope someone in here has the patence and proficency to answer it.
Thank you very much!

Command line arguments are always passed in as strings. Just because your program expects the first argument to look like a number doesn't necessarily mean that a number gets passed in.
So when you get the first character in the string via argv[1][0], you're not picking up the value 1 but the character 1. Assuming ASCII is used for characters, this character has an ASCII value of 49. So k in this case has the value 49.
You need to convert the argument to a number. You can use the atoi function for this:
int k = atoi(argv[1]);

If you simply want to convert a digit ('0'-'9') to a number, you can simply subtract the Ascii code for '0' from your input.
char digit;
int num = digit - '0';
You should check your input is within the range first.
if (digit < '0' || '9' < digit)
// error!!

The general purpose solution is
int k = atoi(argv[1]);
atoi takes a string and converts it to a number. The subtract solution above only deals with single digits, this will allow k > 9

Related

C fill char array with n values leads to problem

I want to give the program an integer value from 1 to 26 (doesn't need to be hardcoded) that creates a char Array that is filled with the letters from A to letter n.
This is the code:
int main(int argc, char *argv[])
{
int n = atoi(argv[1]);
char comb[n];
for (int i = 0; i < n; i++)
comb[i] = 65 + i;
printf("%s", comb);
}
The problem is, that if i hand over values from 8 - 15 and 24 - 26, the output shows something like this:
ABCDEFGH�������
However, if i hardcode n to be one of the problematic values from above, the output is just right.
Can somebody explain to me, why the program puts out the extra �.
Thanks
The standard way to convert a string to a numeric type in C is to use the strto* family of functions. In your case, you would want something like:
int count = strtol(argv[1], // String
NULL, // Optional output pointer to where the scan stopped
10) // Radix
I'd also check that argc > 2, i.e. that argv[1] was actually passed by the user.
%s expects a pointer to a null terminated string. In other words, printf has no way of knowing where the string argument stops until it sees the '\0', so what you're seeing is some other part of your process memory being printed out as text. To fix: allocate n + 1 for comb, and memset(comb, n + 1, 0); before the loop, or set comb[n] = '\0' right after the loop.

Reading the first line of a txt and converting it to int, but returning another value [C]

I've been trying to read a txt which has a specific structure:
The first line indicates the n-1 lines the whole txt file has.
All the other lines have the "structure" of a card (it's number and it's pattern).
ex: I have a txt which stores 13 cards, so the file in itself has 14 lines:
13
A T
2 P
3 D
13 P
2 P
4 C
8 D
11 T
8 C
9 C
10 T
9 T
7 P
(Note: T stands for clubs, D for diamonds, C for hearts and P for spades, it's in spanish).
I've tried extracting the first line to then create a dynamic array with the number given so that I can store each line in that array, but I fail to get the first value.
My code is:
#include <stdio.h>
#include <stdlib.h>
int leerLinea(){
char contenido[1];
FILE* pArchivo;
pArchivo = fopen("Mazo.txt","r");
if (pArchivo == NULL){
printf("No hay nada aqui!\n");
return 0;
}
else{
fgets(contenido,3,pArchivo);
printf("%s\n", contenido);
}
fclose(pArchivo);
return contenido[0];
}
int main(){
int a;
a = leerLinea();
printf("a's value is: %d\n",a);
return 0;
}
But when I run it I get:
13
a's value is: 49
Why is it returning other value, when it should be returning 13?
With fgets(contenido,3,pArchivo), you read in a string into a buffer that is to small for capturing at least 2 digits and the string termination character; For that statement, it should be at least char contenido[3].
The main issue is, however, that you mix strings with "pure" integral values, i.e. you read in a string but expect it to be converted correctly to a number simply by accessing the first digit of that string; Note that if contenido containded "13", contenido[0] would give character value '1', which in ASCII is 49.
To overcome this, read in the value as a number, i.e. using "%d"-format:
int leerLinea(){
int contenido = 0;
FILE* pArchivo;
pArchivo = fopen("Mazo.txt","r");
if (pArchivo == NULL){
printf("No hay nada aqui!\n");
return 0;
}
else{
fscanf(pArchivo,"%d",&contenido);
printf("%d\n", contenido);
}
fclose(pArchivo);
return contenido;
}
1 - Read a line of text with sufficient space for each character in the line, the line-feed and a null character. The below is 4 characters, so a buffer of 6 is needed.
13 P
Further, there is little gained by being so stingy with line buffers. Suggest 2x the maximize anticipated size to allow for some growth, leading/trailing whitespace.
#define LINE_MAX (4 + 1 + 1)
char contenido[LINE_MAX * 2];
2 - When reading a line, do not hard code in the 3, use sizeof() for consistent, easier to maintain code.
// fgets(contenido,3,pArchivo);
fgets(contenido, sizeof contenido, pArchivo);
3 - Rather than return the first character of a string (the code for the character '1' is 49), convert the string into an int/long with strtol() or atol(), etc. #Nicolas Guerin
// return contenido[0];
return atoi(contenido);
// or
return strtol(contenido, NULL, 10); // better
return atoi(contenido[0]);
The probleme you've got is that you return a char in an int function, every char as an integer value. That's true but not the decimal value of the char, the ascii value.
Atoi convert a char into an int.
ps: the way you do, it will only return 1 in the exemple

Input numbers (may with leading zero ) but output them without leading zero

I need to preserve any leading zeroes in the input, so I take the digits in as chars and then convert them back to integers using the ctoi() function, as shown in this code:
#include<stdio.h>
#define ctoi(a) a-'0'
int main() {
int n;
char ch;
scanf("%c",&n);
ch=ctoi(n);
printf("%d",n);
}
But that code didn't work. What is the problem?
Input:
001
0123
78
000123
Expected Output:
1
123
78
123
But I got:
1
1
7
1
when you store the number as an integer, you only store the actual number, not the formatting used to make that number. If you want to preserve the formatting as is you either need to store it as a string or some other means of storing the original formatting.
int n = 10; // only stores a number in memory
char text[10] = "00010"; // stores any text, but can not be used for number arithmetic as stored here

Why am I getting random numbers when I try to increase the ascii value of a char?

int n = argv[i][j];
n = n + (int)argv[1];
/* I'm pretty sure the above part that is wrong. What I was hoping that this
would do is take the number the person put in and increase n by that number but
it isnt working*/
printf("%d\n", n);
i = the string numbers of the argument
j = the characters of the string
What I want is to make it so when someone types ./123 12 hi I want it to increase the ascii characters of h and i by 12 or whatever number they put in. When I test my code out with
./123 1 hi
I get an output of
-1081510229
-1081510228
instead of
105
106
which is i and j, the next letters of h and i
Libraries I'm using
stdio.h
studio50.h
string.h
argv[1] is a string (i.e, a null-terminated char array), casting it to int doesn't give the result you expected
You should use atoi to do the job. Or better, use strtol to get better stability.

Unexpected output when printing element of array in c

I am creating a simple c program and output of below program should be 2 but i am getting 50 dont know why (i am newbie to c) please let me know where i am missing
#include<stdio.h>
int main(int argc, char** argv) {
int a[4]={'1','2','2','\0'};
printf("The value of a is %d",a[1]);
return 0;
}
here is live output
You initialised the array using ascii character codes. '2' has integer value 50.
Initialise the array as
int a[4]={1,2,2,0};
if you want it to contain integers 1,2,2,0. Or
#include<stdio.h>
int main(int argc, char** argv) {
char a[4]="121";
printf("The value of a is %c",a[1]);
return 0;
}
if you want an array of characters that can be treated as a string. (Note the use of the %c format specifier here.)
50 is the ASCII code of '2'.
Replace '2' with 2 if you want it fixed.
When using character literals like '2' C actually thinks of them as integer types. When you print it using %d format specifier you're telling C to print the value as integer.
If you want to keep the array elements like this: '2', you'll need to change printf format to %c to get a 2 in the console.
When you wrote int a[4]={'1','2','2','\0'}; you actually initialized the array with ASCII Codes of the numbers 1 and 2.
This is because you enclosed them within single quotes thus making them characters instead of integers.
Hence the array actually takes the values int a[4]={49,50,50,0};
To rectify it, you should write the integers without the quotes:
int a[4]={1,2,2,0};
Also note that integer arrays don't need to end with '\0'. That is only for character arrays.
This line
int a[4]={'1','2','2','\0'};
tells the compiler to create an integer array of length 4 and put into it the integers from the curled braces from the right.
Characters in C are 1-byte integers, 1 is a character of 1 and it means integer value of it's ASCII code, i.e. 50. So the first element of an array gets the value of 50.
To fix you should write
int a[4]={1,2,2,0};
remember, that 0 cannot serve as an array end marker, since it is just a number.
If you suppose to get 122 output then do
char a[4]={'1','2','2','\0'};
printf("The value of a is %s",a);
since strings in C are character arrays with 0 as termination symbol.
Also you can let compiler to count values for you
char a[]={'1','2','2','\0'};
You are assigning chars not integers:
note
'2' means char use %c
2 manes int use %d
"2" means string. use %s
all are different:
in your code you can do like to print 2:
int main(int argc, char** argv) {
char a[4]={'1','2','2','\0'};
printf("The value of a is %c",a[1]);
return 0;
}

Resources