create new converted string from "toupper()" in c - c

Trying to take a lower case string, and create a new string after making characters uppercase
#include <ctype.h>
#include <cs50.h>
#include <stdio.h>
#include <string.h>
int main (void)
{
string word = "science";
char new_word[] = {};
for (int i = 0, len = strlen(word); i < len; i++)
{
if (islower(word[i]))
{
new_word = new_word + toupper(word[i]);
}
}
}
I am getting "error: array type 'char[0]' is not assignable".
This isn't all, and I am sure with my full program there might be an easier way, but I built out everything else, and the only point that I am struggling with is looping through my string to get a new word that is uppercase.
Any assistance would be greatly appreciated!

char new_word[] = {};
Your new char array has length 0 and any access invokes undefined behaviour (UB) as you access it outside its bounds.
If your compiler supports VLAs:
string word = "science";
char new_word[strlen(word) + 1] = {0,};
if not:
string word = "science";
char *new_word = calloc(1, strlen(word) + 1);
and
new_word[i] = toupper((unsigned char)word[i]);
If you used calloc do not forget to free the allocated memory

Undefined behavior when word[i] < 0
Avoid that by accessing the string as unsigned char
As per C reference about toupper()
int toupper( int ch );
ch - character to be converted. If the value of ch is not representable as >unsigned char and does not equal EOF, the behavior is undefined.
This is not correct, compiler gives error , "error: assignment to expression with array type"
new_word = new_word + toupper(word[i]);
which is not allowed with an array type as LHS of assignment.
changed to
new_word[i] = toupper((unsigned char)word[i]);
#include <ctype.h>
#include <stdio.h>
#include <string.h>
int main (void)
{
char word[] = "science";
char new_word[sizeof word] = "";
int i;
for (i = 0; i < sizeof(word); i++)
{
if (islower(word[i]))
{
new_word[i] = toupper(word[i]);
}
else /* for Upper case latter, simply fill the array */
{
new_word[i] = word[i];
}
}
new_word[i] = '\0';
printf("%s", new_word);
}
OUTPUT:
SCIENCE
EDIT:
Just echo comment from solution given by M.M and comment from
David C. Rankin casting is not necessary for this example. read comment below from M.M and David C. Rankin
Removed unsigned char from islower() and toupper()

This is but one way of accomplishing the task. Make sure to come up with your way of doing.
#include <stdio.h>
#include <string.h>
#define MAX_BUFF 128
char *upperCase(char *c) {
//printf("%s, %d", c, strlen(c));
for(int i=0; i<strlen(c) && i<MAX_BUFF; i++) {
c[i] = c[i] - ' '; // convert char to uppercase
//printf(">> %c", c[i]);
}
return c;
}
int main (void)
{
char word[MAX_BUFF] = "science";
char new_word[MAX_BUFF];
printf("in>> %s \n", word);
strcpy(new_word, upperCase(&word[0]));
printf("out>> %s\n", new_word);
}
Output:
in>> science
out>> SCIENCE

Named arrays cannot be resized in C, you have to set the size correctly to start:
size_t len = strlen(word);
char new_word[len + 1]; // leaving room for null-terminator
Note that no initializer can be used for new_word when its size was determined by a function call (a lame rule but it is what it is); and you can take out the len loop variable since it is now defined earlier.
Then set each character in place:
new_word[i] = toupper(word[i]);
but be careful with the surrounding if statement: if that were false, then you need to set new_word[i] = word[i] instead.
(Pro tip, you can get rid of the if entirely, because toupper is defined to have no effect if the character was not lower case).
Lastly, there should be a null terminator at the end:
new_word[len] = 0;
NB. To be technically correct, the call to toupper should be: toupper((unsigned char)word[i]) -- check the documentation of toupper to understand more about this.

Related

char-array (string) with arbitrary number of elements in c

I have problem with assigning value to string array in c. The code is part of a hangman game
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
int main()
{
srand(time(0));
int random = rand() % 5;
char *sWords[] = {"banana", "apple", "GOAT", "jordan", "zhiki"};
printf("%s\n", sWords[random]);
char *sTempWord = sWords[random];
char *sTempArr;
for (int i = 0; sTempWord[i] != '\0'; i++)
sTempArr[i] = '_';
for (int i = 0; strlen(sTempArr); i++)
printf("%c ", sTempArr[i]);
}
There are no errors, and when I run the program it just exits. The plan is to get random word from the list, create temporary array with the length of the randomly-selected word and assing all elements with value '_'.
Also, when I try to make array with constant value, (like char sTempArr[len] where len=strlen(sTempWord), it says: expression must have a constant value
When declaring an array, the compiler needs to know the length at compile time (e.g. the value can't be a variable).
You can either create an initial empty array with a known number of items (you will need to make sure it's big enough to fit any word from sWords, including null terminator):
char sTempArr[100];
or you can allocate dynamic memory at runtime with something like malloc():
#include <stdlib.h>
int len = strlen(sTempWord) + 1; // +1 for '\0'
char *sTempArr; = malloc(len);
// ...
free(sTempArr); // When you are done using the array
They are not the same.
Not initialized pointer.
char *sTempArr;
You do not null character terminate the string
for (int i = 0; sTempWord[i] != '\0'; i++)
sTempArr[i] = '_';
As the string is null character terminated you can't call strlen
for (int i = 0; strlen(sTempArr); i++)
printf("%c ", sTempArr[i]);
char sTempArr[strlen(sTempWord) + 1];
int i;
for (i = 0; sTempWord[i] != '\0'; i++)
sTempArr[i] = '_';
sTempArr[i] = 0;
for (i = 0; strlen(sTempArr); i++)
printf("%c ", sTempArr[i]);

Getting garbage after reversing string in c

I am trying to reverse a string. scanf is working well but when I use fixed string then it gives garbage value. So where is the fault ?
#include<stdio.h>
#include<string.h>
int main()
{
char s[50]="Hi I Love Programming";
char rev[strlen(s)];
int i,k;
k=strlen(s);
for(i=0; i<strlen(s); i++)
{
rev[k]=s[i];
k--;
}
printf("The reverse string is: %s\n", rev);
}
Your program has two issues:
1.
char rev[strlen(s)];
You forgot to add an element for the string-terminating null character '\0'.
Use:
char rev[strlen(s) + 1];
Furthermore you also forgot to append this character at the end of the reversed string.
Use:
size_t len = strlen(s);
rev[len] = '\0';
Note, my len is the k in your provided code. I use the identifier len because it is more obvious what the intention of that object is. You can use strlen(s) because the string has the same length, doesn´t matter if it is in proper or reversed direction.
2.
k=strlen(s);
for(i=0; i<strlen(s); i++)
{
rev[k]=s[i];
k--;
}
With rev[k] you accessing memory beyond the array rev, since index counting starts at 0, not 1. Thus, the behavior is undefined.
k needs to be strlen(s) - 1.
Three things to note:
The return value of strlen() is of type size_t, so an object of type size_t is appropriate to store the string length, not int.
It is more efficient to rather calculate the string length once, not at each condition test. Use a second object to store the string length and use this object in the condition of the for loop, like i < len2.
char s[50]="Hi I Love Programming"; can be simplified to char s[]="Hi I Love Programming"; - The compiler automatically detects the amount of elements needed to store the string + the terminating null character. This safes unnecessary memory space, but also ensures that the allocated space is sufficient to hold the string with the null character.
The code can also be simplified (Online example):
#include <stdio.h>
#include <string.h>
int main(void)
{
char s[] = "Hi I Love Programming";
size_t len = strlen(s);
char rev[len + 1];
size_t i,j;
for(i = 0, j = (len - 1); i < len; i++, j--)
{
rev[j] = s[i];
}
rev[len] = '\0';
printf("The reverse string is: %s\n", rev);
}
Output:
The reverse string is: pgnimmargorP evoL I iH
your program is hard to understand. Here you have something much simpler (if you want to reverse the string of course)
#include <stdio.h>
#include <string.h>
char *revstr(char *str)
{
char *start = str;
char *end;
if(str && *str)
{
end = str + strlen(str) - 1;
while(start < end)
{
char tmp = *end;
*end-- = *start;
*start++ = tmp;
}
}
return str;
}
int main()
{
char s[50]="Hi I Love Programming";
printf("%s", revstr(s));
}
https://godbolt.org/z/5KX3kP

Get C XOR return value

In the for loop, it prints the correct value 11100001 in each loop, but the main call print char_str is blank.
I hope it can return 11100001 as char.
//xor
char * xorencrypt(char * a, char * b) {
size_t alen = strlen(a);
size_t blen = strlen(b);
char * encrypted = malloc(alen + 1);
int i;
for (i = 0; i < 8; i++) {
encrypted[i] = a[i] ^ b[i];
printf("%s\n", encrypted[i]);
}
encrypted[alen] = '\0';
return encrypted;
}
main {
char * char_str = xorencrypt("11011000", "00111001");
printf("%s\n", char_str);
}
Your code needs a bit of refactoring.
1) You need to include some headers
#include <stdint.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
2) the 'main' function should return an int
int main() {
/* code here */
return 0;
}
3) You should make sure the call to malloc succeeds
char * encrypted = malloc(alen + 1);
assert(encrypted != (char*)0); /* requires #include <assert.h>
4) You should be careful when xor'ing ones and zeros. You are handling chars like integers
you are xoring zeros (value 48 in ascii) with ones (value 49 in ascii)
encrypted[i] = a[i] ^ b[i];
you want something like this instead
int a_i = a[i] - '0';
int b_i = b[i] - '0';
encrypted[i] = (a_i ^ b_i) + '0';
A reworked version of the code that assumes you are dealing exclusively with strings of the binary digits '0' and '1'. If you are dealing with more general strings, you will need a different solution.
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
static
char *xorencrypt(char *a, char *b)
{
size_t alen = strlen(a);
char *encrypted = malloc(alen + 1);
assert(alen == strlen(b));
assert(encrypted != NULL);
for (size_t i = 0; i < alen; i++)
{
assert(a[i] == '0' || a[i] == '1');
assert(b[i] == '0' || b[i] == '1');
encrypted[i] = (a[i] ^ b[i]) + '0';
putchar(encrypted[i]);
}
encrypted[alen] = '\0';
putchar('\n');
return encrypted;
}
int main(void)
{
char *char_str = xorencrypt("11011000", "00111001");
printf("%s\n", char_str);
free(char_str);
return 0;
}
Amongst the changes:
Error check the memory assignment. Using assert() is a bad way to do it in production code, but it does ensure that you check that the memory is allocated.
Check that the strings are the same length.
Remove unused variable blen.
The static is optional; it means the code compiles cleanly under the stringent options I use (which require a prototype declaration of every non-static function before it is defined or used).
The loop index i is of the same type size_t as alen to avoid warnings about comparing signed and unsigned values. I'm using the C99 style 'declare a variable in a for loop' notation.
The upper bound of the loop is based on the measured length of the strings, not a fixed constant.
The original version of the XOR operation either generated a null '\0' or a control-A '\1' for each character.
The revised version of the crucial XOR operation ensures that the result is a printable digit.
The printf("%s\n", encrypted[i]); in the original passed a character to be printed as a string. If your compiler wasn't warning you, turn on the warning options or get a better compiler.
If you'd written printf("%s\n", &encrypted[i]); you would have had problems, potentially, with a string that is not guaranteed to be null terminated inside the loop (though you did null terminate the string after the loop, which was good).
The code in main() frees the allocated memory. It is good practice to ensure there is a free() for every malloc().
I prefer to explicitly return 0 from main(), even though C99 says you don't have to.
This answer was started while the question was active. Then life got in the way.

Strange printf output in C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * reverse(char *string);
int main(int argc, char *argv[])
{
char array[10];
array[0] = 'a';
array[1] = 'b';
array[2] = 'c';
array[3] = 'd';
array[4] = 'e';
printf("1%s\n",array);
char *p = reverse(array);
printf("4%s\n",p);
printf("5%s\n",array);
}
char * reverse(char *string)
{
int size = strlen(string);
char reversed[size];
int i;
int j = 0;
for(i = size-1; i >= 0; i--)
{
reversed[j] = string[i];
j++;
}
printf("2%s\n",reversed);
string = reversed;
printf("3%s\n",string);
return reversed;
}
This code basically just initializes an array of values and passes it into a method that reverses these values.
I am not sure if this is the best way to execute the task, since I am new to pointers and arrays in C.
But the real question is this:
Can anyone figure out why in this line
printf("4%s\n",p);
if you remove the preceding '4', so it looks like so
printf("%s\n",p);
the line won't print at all?
You are returning a pointer to local variable(reversed) in the function reverse the question should actually be: Why did it work in the first place?.
This code string = reversed; will only copy the pointer, and again the local copy of the pointer so it has no effect outside the function.
To reverse a string you don't need additional memory - this can be done in-place.
Strings in C must end with the null character. You're using strlen on a non null-terminated string.
Furthermore, you just a very lucky person, because there is a serious problem with you code: you forget to add \0 symbol at the end of string.
UPD: the main problem is with code line char reversed[size];.
It's a regular local variable, it has automatic duration, which means that it springs into existence when the function is called and disappears when the function returns (see this link).
You need to change it to:
char *reversed = malloc((size+1)*sizeof(char));
UPD-2: another bug fixing will be:
1) add array[5] = '\0'; after all other array initializing lines
2) add reversed[j] = '\0'; after for...loop:
for(i = size-1; i >= 0; i--)
{
reversed[j] = string[i];
j++;
}
reversed[j] = '\0';
UPD-3: But in general it will much more correctly initialize your string in appropriate way:
char array[10] = "abcde";

C Library function for converting a string of hex digits to ints?

I have a variable length string where each character represents a hex digit. I could iterate through the characters and use a case statement to convert it to hex but I feel like there has to be a standard library function that will handle this. Is there any such thing?
Example of what I want to do. "17bf59c" -> int intarray[7] = { 1, 7, 0xb, 0xf, 5, 9, 0xc}
No, there's no such function, probably because (and now I'm guessing, I'm not a C standard library architect by a long stretch) it's something that's quite easy to put together from existing functions. Here's one way of doing it decently:
int * string_to_int_array(const char *string, size_t length)
{
int *out = malloc(length * sizeof *out);
if(out != NULL)
{
size_t i;
for(i = 0; i < length; i++)
{
const char here = tolower(string[i]);
out[i] = (here <= '9') ? (here - '\0') : (10 + (here - 'a'));
}
}
return out;
}
Note: the above is untested.
Also note things that maybe aren't obvious, but still subtly important (in my opinion):
Use const for pointer arguments that are treated as "read only" by the function.
Don't repeat the type that out is pointing at, use sizeof *out.
Don't cast the return value of malloc() in C.
Check that malloc() succeeded before using the memory.
Don't hard-code ASCII values, use character constants.
The above still assumes an encoding where 'a'..'f' are contigous, and would likely break on e.g. EBCDIC. You get what you pay for, sometimes. :)
using strtol
void to_int_array (int *dst, const char *hexs)
{
char buf[2] = {0};
char c;
while ((c = *hexs++)) {
buf[0] = c;
*dst++ = strtol(buf,NULL,16);
}
}
Here's another version that allows you to pass in the output array. Most of the time, you don't need to malloc, and that's expensive. A stack variable is typically fine, and you know the output is never going to be bigger than your input. You can still pass in an allocated array, if it's too big, or you need to pass it back up.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
/* str of length len is parsed to individual ints into output
* length of output needs to be at least len.
* returns number of parsed elements. Maybe shorter if there
* are invalid characters in str.
*/
int string_to_array(const char *str, int *output)
{
int *out = output;
for (; *str; str++) {
if (isxdigit(*str & 0xff)) {
char ch = tolower(*str & 0xff);
*out++ = (ch >= 'a' && ch <= 'z') ? ch - 'a' + 10 : ch - '0';
}
}
return out - output;
}
int main(void)
{
int values[10];
int len = string_to_array("17bzzf59c", values);
int i = 0;
for (i = 0; i < len; i++)
printf("%x ", values[i]);
printf("\n");
return EXIT_SUCCESS;
}
#include <stdio.h>
int main(){
char data[] = "17bf59c";
const int len = sizeof(data)/sizeof(char)-1;
int i,value[sizeof(data)/sizeof(char)-1];
for(i=0;i<len;++i)
sscanf(data+i, "%1x",value + i);
for(i=0;i<len;++i)
printf("0x%x\n", value[i]);
return 0;
}

Resources