Filling a char* in C - c

This is probably a very simple solution, but for the life of me I can't figure it out. I'm trying to create a char array (so a char*) consisting of numbers from 0 to numPlayers - 1, which I will iterate through to access whose turn it is. So, if numPlayers = 10, I want gameState.players to be [0,1,2,3,4,5,6,7,8,9]. What did I do wrong?
printf("How many players will be playing: ");
scanf(" %d", &numPlayers);
gameState.players = (char*) malloc(numPlayers * sizeof(char));
for (int i = 0; i < numPlayers; ++i) {
strcpy(gameState.players[i],(char) i);
}

First off:
gameState.players = (char*) malloc(numPlayers * sizeof(char));
The explicit cast is ill-advised in C (it can hide certain subtle errors) and the multiplication by sizeof(char) is never needed - it's always one.
But the real problem lies here:
strcpy(gameState.players[i],(char) i);
The str* functions are meant to work with C strings (null terminated character arrays). You do not have a string, rather you have a character value, so it should be more along the lines of:
gameState.players[i] = i;
You also need to keep in mind:
Though you're using char variables, the value being put in is not the textual representation of the digit. To get that, you would need to use i + '0'(a). Characters are generally meant to be used for (mostly) printable stuff, you would be better off using a more-specific data type like int or unsigned short` for non-character data.
This scheme (assuming you want textual representation) is going to break horribly if you ever use more than ten items.
(a) There's a big difference between the "characters" 7 and '7'. The former actually has the value 7 (ASCII BEL, if you're using ASCII), the latter has the value 0x37 (again, assuming ASCII/Unicode).
The numeric characters are the only ones guaranteed to be consecutive so you can convert a numeric value 0..9 to the printable character value simply by adding '0'.

Please be careful when calling functions, you have to make sure that you are
using the correct types. If you use an incorrect one, the compiler will warn you
or print an error, you should read the warnings and errors of the compiler. They
tell you what is wrong.
strcpy is used to copy strings. The signature of the functions is
char *strcpy(char *dest, const char *src);
it expects a pointer to char as destination, and a pointer to char as the
source. Also strcpy expects a valid C-String. A C-Strings is a sequence of
char bytes that ends with the value '\0'. If you don't have a valid
C-String, you cannot use strcpy.
strcpy(gameState.players[i],(char) i)
Is wrong on many levels:
The arguments are not pointers of char
You are not dealing with valid C-strings
Casting won't help you here, you even did the wrong casting.
1 is not the same as '1'. The character '1' is actually the vakue 49
(ASCII code). If you want to get the ASCII representation of a digit, you have
to do: '0' + digit.
You should do:
for (int i = 0; i < numPlayers; ++i) {
gameState.players[i] = '0' + i;
}
Note that this would only work for max. 9 players. If you need more, then you
have to use an array of strings.
Also note that gameState.players does not point to a C-String, because it is
not '\0'-terminated. You cannot calls strings functions on it. If you want
to do that, then you have to change your code like this:
printf("How many players will be playing: ");
fflush(stdout);
scanf(" %d", &numPlayers);
if(numPlayers > 9)
{
// error, do not continue
}
gameState.players = calloc(numPlayers + 1, sizeof *gameState.players);
for (int i = 0; i < numPlayers; ++i) {
gameState.players[i] = '0' + i;
}

Related

C - Print ASCII Value for Each Character in a String

I'm new to C and I'm trying to write a program that prints the ASCII value for every letter in a name that the user enters. I attempted to store the letters in an array and try to print each ASCII value and letter of the name separately but, for some reason, it only prints the value of the first letter.
For example, if I write "Anna" it just prints 65 and not the values for the other letters in the name. I think it has something to do with my sizeof(name)/sizeof(char) part of the for loop, because when I print it separately, it only prints out 1.
I can't figure out how to fix it:
#include <stdio.h>
int main(){
int e;
char name[] = "";
printf("Enter a name : \n");
scanf("%c",&name);
for(int i = 0; i < (sizeof(name)/sizeof(char)); i++){
e = name[i];
printf("The ASCII value of the letter %c is : %d \n",name[i],e);
}
int n = (sizeof(name)/sizeof(char));
printf("%d", n);
}
Here's a corrected, annotated version:
#include <stdio.h>
#include <string.h>
int main() {
int e;
char name[100] = ""; // Allow for up to 100 characters
printf("Enter a name : \n");
// scanf("%c", &name); // %c reads a single character
scanf("%99s", name); // Use %s to read a string! %99s to limit input size!
// for (int i = 0; i < (sizeof(name) / sizeof(char)); i++) { // sizeof(name) / sizeof(char) is a fixed value!
size_t len = strlen(name); // Use this library function to get string length
for (size_t i = 0; i < len; i++) { // Saves calculating each time!
e = name[i];
printf("The ASCII value of the letter %c is : %d \n", name[i], e);
}
printf("\n Name length = %zu\n", strlen(name)); // Given length!
int n = (sizeof(name) / sizeof(char)); // As noted above, this will be ...
printf("%d", n); // ... a fixed value (100, as it stands).
return 0; // ALWAYS return an integer from main!
}
But also read the comments given in your question!
This is a rather long answer, feel free to skip to the end for the code example.
First of all, by initialising a char array with unspecified length, you are making that array have length 1 (it only contains the empty string). The key issue here is that arrays in C are fixed size, so name will not grow larger.
Second, the format specifier %c causes scanf to only ever read one byte. This means that even if you had made a larger array, you would only be reading one byte to it anyway.
The parameter you're giving to scanf is erroneous, but accidentally works - you're passing a pointer to an array when it expects a pointer to char. It works because the pointer to the array points at the first element of the array. Luckily this is an easy fix, an array of a type can be passed to a function expecting a pointer to that type - it is said to "decay" to a pointer. So you could just pass name instead.
As a result of these two actions, you now have a situation where name is of length 1, and you have read exactly one byte into it. The next issue is sizeof(name)/sizeof(char) - this will always equal 1 in your program. sizeof char is defined to always equal 1, so using it as a divisor causes no effect, and we already know sizeof name is equal to 1. This means your for loop will only ever read one byte from the array. For the exact same reason n is equal to 1. This is not erroneous per se, it's just probably not what you expected.
The solution to this can be done in a couple of ways, but I'll show one. First of all, you don't want to initialize name as you do, because it always creates an array of size 1. Instead you want to manually specify a larger size for the array, for instance 100 bytes (of which the last one will be dedicated to the terminating null byte).
char name[100];
/* You might want to zero out the array too by eg. using memset. It's not
necessary in this case, but arrays are allowed to contain anything unless
and until you replace their contents.
Parameters are target, byte to fill it with, and amount of bytes to fill */
memset(name, 0, sizeof(name));
Second, you don't necessarily want to use scanf at all if you're reading just a byte string from standard input instead of a more complex formatted string. You could eg. use fgets to read an entire line from standard input, though that also includes the newline character, which we'll have to strip.
/* The parameters are target to write to, bytes to write, and file to read from.
fgets writes a null terminator automatically after the string, so we will
read at most sizeof(name) - 1 bytes.
*/
fgets(name, sizeof(name), stdin);
Now you've read the name to memory. But the size of name the array hasn't changed, so if you used the rest of the code as is you would get a lot of messages saying The ASCII value of the letter is : 0. To get the meaningful length of the string, we'll use strlen.
NOTE: strlen is generally unsafe to use on arbitrary strings that might not be properly null-terminated as it will keep reading until it finds a zero byte, but we only get a portable bounds-checked version strnlen_s in C11. In this case we also know that the string is null-terminated, because fgets deals with that.
/* size_t is a large, unsigned integer type big enough to contain the
theoretical maximum size of an object, so size functions often return
size_t.
strlen counts the amount of bytes before the first null (0) byte */
size_t n = strlen(name);
Now that we have the length of the string, we can check if the last byte is the newline character, and remove it if so.
/* Assuming every line ends with a newline, we can simply zero out the last
byte if it's '\n' */
if (name[n - 1] == '\n') {
name[n - 1] = '\0';
/* The string is now 1 byte shorter, because we removed the newline.
We don't need to calculate strlen again, we can just do it manually. */
--n;
}
The loop looks quite similar, as it was mostly fine to begin with. Mostly, we want to avoid issues that can arise from comparing a signed int and an unsigned size_t, so we'll also make i be type size_t.
for (size_t i = 0; i < n; i++) {
int e = name[i];
printf("The ASCII value of the letter %c is : %d \n", name[i], e);
}
Putting it all together, we get
#include <stdio.h>
#include <string.h>
int main() {
char name[100];
memset(name, 0, sizeof(name));
printf("Enter a name : \n");
fgets(name, sizeof(name), stdin);
size_t n = strlen(name);
if (n > 0 && name[n - 1] == '\n') {
name[n - 1] = '\0';
--n;
}
for (size_t i = 0; i < n; i++){
int e = name[i];
printf("The ASCII value of the letter %c is : %d \n", name[i], e);
}
/* To correctly print a size_t, use %zu */
printf("%zu\n", n);
/* In C99 main implicitly returns 0 if you don't add a return value
yourself, but it's a good habit to remember to return from functions. */
return 0;
}
Which should work pretty much as expected.
Additional notes:
This code should be valid C99, but I believe it's not valid C89. If you need to write to the older standard, there are several things you need to do differently. Fortunately, your compiler should warn you about those issues if you tell it which standard you want to use. C99 is probably the default these days, but older code still exists.
It's a bit inflexible to be reading strings into fixed-size buffers like this, so in a real situation you might want to have a way of dynamically increasing the size of the buffer as necessary. This will probably require you to use C's manual memory management functionality like malloc and realloc, which aren't particularly difficult but take greater care to avoid issues like memory leaks.
It's not guaranteed the strings you're reading are in any specific encoding, and C strings aren't really ideal for handling text that isn't encoded in a single-byte encoding. There is support for "wide character strings" but probably more often you'll be handling char strings containing UTF-8 where a single codepoint might be multiple bytes, and might not even represent an individual letter as such. In a more general-purpose program, you should keep this in mind.
If we need write a code to get ASCII values of all elements in a string, then we need to use "%d" instead of "%c". By doing this %d takes the corresponding ascii value of the following character.
If we need to only print the ascii value of each character in the string. Then this code will work:
#include <stdio.h>
char str[100];
int x;
int main(){
scanf("%s",str);
for(x=0;str[x]!='\0';x++){
printf("%d\n",str[x]);
}
}
To store all corresponding ASCII value of character in a new variable, we need to declare an integer variable and assign it to character. By this way the integer variable stores ascii value of character. The code is:
#include <stdio.h>
char str[100];
int x,ascii;
int main(){
scanf("%s",str);
for(x=0;str[x]!='\0';x++){
ascii=str[x];
printf("%d\n",ascii);
}
}
I hope this answer helped you.....😊

C: How to add char to chars, and when the max char is reached have it loop back to 'a'?

I am creating a simple encryption program.
I am adding chars to chars to create a new char.
As of now the new 'char' is often a represented by a '?'.
My assumption was that the char variable has a max sum and once it was passed it looped back to 0.
assumed logic:
if char a == 1 && char z == 255
then 256 should == a.
This does not apear to be the case.
This snippet adds a char to a char.
It often prints out something like:
for (int i = 0; i < half; ++i) {
halfM1[i] = halfM1[i] + halfP1[i];
halfM2[i] = halfM2[i] + halfP2[(half + i)];
}
printf("\n%s\n", halfM1 );
printf("%s\n", halfM2);
Returns:
a???
3d??
This snippet removes the added char and the strings go back to normal.
for (int i = 0; i < half; ++i) {
halfM1[i] = halfM1[i] - halfP1[i];
halfM2[i] = halfM2[i] - halfP2[(half + i)];
}
printf("\n%s\n", halfM1 );
printf("%s\n", halfM2);
returns:
messagepart1
messagepart2
The code technically works, but I would like the encryption to be in chars.
If question on why 'half' is everywhere.
The message and key are split in half so the first half and second half of message have separate encryption.
First of all, there is no such thing as "wraparound" for common char. A common char is a signed type in x86, and signed integers do not have wraparound. Instead the overflow leads to undefined behaviour. Additionally, the range of chars can be -128 ... 127, or even something
For cryptographic purposes you'd want to use unsigned chars, or even better, raw octets with uint8_t (<stdint.h>).
Second problem is that you're printing with %s. One of the possible 256 resulting characters is \0. If this gets into the resulting string, it will terminate the string prematurely. Instead of using %s, you should output it with fwrite(halfM1, buffer_size, 1, stdout). Of course the problem is that the output is still some binary garbage. For this purposes many Unix encryption programs will write to file, or have an option to output an ASCII-armoured file. A simple ASCII armouring would be to output as hex instead of binary.
The third is that there is an operation that is much better than addition/subtraction for cryptographic purposes: XOR, or halfM1[i] = halfM1[i] ^ halfP1[i]; - the beauty of which is that it is its own inverse!

Convert entire array of characters into integer in C

I'm reading input from a file and trying to create a numerical value from the strings I take in.
I tried simply using the atoi but that doesn't work on characters.
Then I tried using a forloop over my array of characters but then I got error because some characters are actually integers.
Then I tried using ifstatement to check if the characters themselves are integers and just add it to my "sum" manually.
But so far all I get is errors and errors, I'm not sure where my logic is wrong.
In C an array is simply a pointer right? So to access the value at a certain index I use *arr[num] right?
This is my code
char newlineC;
char input[14];
while(fscanf(fp,"%s%c",input, &newlineC)!=EOF){
int val = 0;
int x;
for(x=0; x<14; x++){
if(isdigit(*input[x])){
val = val + input[x];
}else{
int p = atoi(input[x]);
val = val + p;
}
}
I've tried the strol function... didn't work either. I've been at this for so long I feel dumb that I am stumped on something that seems so simple. Any help is appreciated.
You are passing the wrong types all over the place.
char input[14];
this declares an char array of dimension 14. input[i] is the ith char in
the array, it has type char. It's not a pointer, you cannot dereference it,
that's why *input[x] fails. In fact the compiler should have given you an
error there, this error:
invalid type argument of unary β€˜*’ (have β€˜int’)
The same problem with atoi. It expects a pointer to char that points to a
string. input[x] is single char, you cannot pass to atoi. Again the
compiler should have warned you.
fscanf(fp,"%s%c",input, &newlineC)
This is very clumsy. If the input is larger than 13 characters, you will
overflow the buffer. A better way would be:
fscanf(fp, "%13s%c", input, &newline);
Or even better
int val;
fscanf(fp, "%d", &val);
Another error: if you know that input[x] is a digit, then the integer that the
digit represent is input[x] - '0'. So this should be the calculation:
val = val + input[x] - '0';
Overall I would use fgets and strtol:
while(fgets(input, sizeof input, fp))
{
long int val;
char *tmp;
val = strtol(line, &tmp, 0);
if(*tmp == 0 || *tmp == '\n')
printf("An integer was read: %ld\n", val);
else
printf("More than an integer was read: '%s'\n", line);
}
If you are only converting the chars [1..0] to an integer value, all you have to do is
int main(void) {
char input[14];
scanf("%s", input);
if (isdigit(input[0])) {
int num = atoi(input);
printf("%d\n", num);
}
else {
printf("INPUT ERROR\n");
}
}
Are you wanting to process alphabet characters as well and turn them into some integer value?
Arrays in C are based on pointers, but that's not all they are. Arrays in C is just a bunch of those data types in a line in memory. That way you can just access the pointer of the lead variable, than hop down that list in order to get the next iteration of the array.
isdigit(*input[14])
This line will cause issues. Look at what input itself is. input is the pointer to your first element in that array. input is essentially saying char* input = &array[0]; So lets say you dereference that input variable without that 14, you would get the first element. So we can say that *input = array[0]; Do you see the issue here? You basically dereferenced it twice. If you had just done insdigit(input[14]) that would work a bit better.
But onto the bigger issue here. You're taking a char array, that contains only chars, and you're trying to convert them into numbers. Remember that char and int are two different data types. Go ahead and check out this table: https://upload.wikimedia.org/wikipedia/commons/d/dd/ASCII-Table.svg
Recall that chars are basically just numbers that correspond to that ASCII value. For example your computer doesn't read a letter as a D, it reads it as 68 (or the binary format of 68). For numbers it's the same concept, even if it seems like it's just a number and you should be able to add it to val, you'd first have to subtract 48 or use the atoi function on digits.
So what can you do here? I can't say for sure without knowing exactly what you're trying to do as I don't know your specific needs, but just realize that you can already convert char into ints very easily. I believe you can just add a char to an int, although I may be mistaken (I do know there's a very easy way to add a char's value though, maybe you have to cast it first?) However recall that if you want the digits to count for face value, you'd have to subtract 48 from them first.
If you want to use atoi you can, however honestly I don't see the need here, since you're already converting regular chars to numbers here. It'd be sufficient to check to see if the char value is between 48 and 58 (or whatever the actual numbers are) and if they are then you could subtract that.
Hope this helped!

Can i assign a integer to a character pointer array?

int k=5;
char* result = (char *)malloc(100 * sizeof(char));
result[count] = k;
Considering the above code, if I print the contents of result[count] it prints smiley symbols. I tried like below,but of no use.
result[count]=(char)k;
Can anyone help me?
I am percepting that malloc(100*sizeof(char)) will create 100 blocks each of size of character contiguously. Please correct me if I am wrong?
I'll disregard all the fluff about arrays and malloc as it is irrelevant to the problem you describe. You seem to essentially be asking "What will this code print:"
char c = 5;
printf("%c", c);
It will print the symbol 5 in your symbol table, most likely a non-printable character. When encountering non-printable characters, some implementations choose to print non-standard symbols, such as smileys.
If you want to print the number 5, you have to use a character literal:
char c = '5';
printf("%c", c);
or alternatively use poor style with "magic numbers":
char c = 53; // don't write code like this
printf("%c", c);
It is a problem of character representation. Let's begin by the opposite first. A char can be promoted to an int, but if you do you get the representation of the character (its code). Assuming you use ASCII:
char c = '5';
int i = c; // i is now 0x35 or 53 ASCII code for '5'
Your example is the opposite, 5 can be represented by a char, so result[count] = k is defined (even if you should have got a warning for possible truncation), but ASCII char for code 5 is control code ENQ and will be printed as ♣ on a windows system using code page 850 or 437.
A half portable (not specified, but is known to work on all common architectures) way to do the conversion (int) 5 -> (char) '5' is to remember that code '0' to '9' are consecutive (as are 'A' to 'Z' and 'a to 'z'), so I think that what you want is:
result[count] = '0' + k;
First, let's clean up your code a bit:
int k=5;
char* result = malloc(100);
result[count] = k;
sizeof(char) is always equal to 1 under any platform and you don't need to cast the return of malloc() in C.
This said, as long as your count variable contains a value between 0 and 99, you're not doing anything wrong. If you want to print the actual character '5', then you have to assign the ASCII value of that character (53), not just the number 5. Also, remember that if that array of chars has to be interpreted as a string, you need to terminate it with '\0':
int k=5, i;
char* result = malloc(100);
for (i=0; i<98; i++) {
result[i] = ' ';
}
result[98] = 53;
result[99] = '\0';
printf("%s\n", result);
The elements in the array you're trying to allocate are all the size of a char, 1 byte. An int is 4 bytes thus your issues. If you want to store ints in an array you could do:
int result[100];
Followed by storing the value, but honestly from the way your questioned is posed I don't know if that's actually what you're trying to do. Try rephrasing the post with what you're trying to accomplish.
Are you trying to store 5 as a character?

Combine characters from a two dimensional array into a string in C

I'm still new to programming but lets say I have a two dimensional char array with one letter in each array. Now I'm trying to combine each of these letters in the array into one array to create a word.
So grid[2][4]:
0|1|2|3
0 g|o|o|d
1 o|d|d|s
And copy grid[0][0], grid[0][1], grid[0][2], grid[0][3] into a single array destination[4] so it reads 'good'. I have something like
char destination[4];
strcpy(destination, grid[0][1]);
for(i=0; i<4; i++)
strcat(destination, grid[0][i]);
but it simply crashes..
Any step in the right direction is appreciated.
In C, the runtime library functions strcpy and strcat require zero terminated strings. What you're handing to them are not zero terminated, and so these functions will crash due to their dependency on that terminating zero to indicate when they should stop. They are running through RAM until they read a zero, which could be anywhere in RAM, including protected RAM outside your program, causing a crash. In modern work we consider functions like strcpy and strcat to be unsafe. Any kind of mistake in handing them pointers causes this problem.
Versions of strcpy and strcat exist, with slightly different names, which require an integer or size_t indicating their maximum valid size. strncat, for example, has the signature:
char * strncat( char *destination, const char *source, size_t num );
If, in your case, you had used strncat, providing 4 for the last parameter, it would not have crashed.
However, an alternative exists you may prefer to explore. You can simply use indexing, as in:
char destination[5]; // I like room for a zero terminator here
for(i=0; i<4; i++)
destination[i] = grid[0][i];
This does not handle the zero terminator, which you might append with:
destination[4] = 0;
Now, let's assume you wanted to continue, putting both words into a single output string. You might do:
char destination[10]; // I like room for a zero terminator here
int d=0;
for(r=0; r<2; ++r ) // I prefer the habit of prefix instead of postfix
{
for( i=0; i<4; ++i )
destination[d++] = grid[r][i];
destination[d++] = ' ';// append a space between words
}
Following whatever processing is required on what might be an ever larger declaration for destination, append a zero terminator with
destination[ d ] = 0;
strcpy copies strings, not chars. A string in C is a series of chars, followed by a \0. These are called "null-terminated" strings. So your calls to strcpy and strcat aren't giving them the right kind of parameters.
strcpy copies character after character until it hits a \0; it doesn't just copy the one char you're giving it a pointer to.
If you want to copy a character, can just assign it.
char destination[5];
for(i = 0; i < 4; i++)
destination[i] = grid[0][i];
destination[i] = '\0';

Resources