Using C, I am trying to implement a function that converts word into mutated_word according to the key string_word. eg: when word is "HE", with the key "QWERTYUIOPASDFGHJKLZXCVBNM", the mutated_word should become "IT". But it keeps giving segmentation fault, not sure how to improve.
#include <cs50.h>
#include <stdio.h>
#include <string.h>
int main(void) {
string word = "HE" ;
string string_word = "QWERTYUIOPASDFGHJKLZXCVBNM";
char mutated_word[strlen(word)];
for (int i = 0; word[i] != '\0'; i++) {
string_word[(int)word[i] - 65] = mutated_word[i];
}
printf("%s", mutated_word);
}
You need to terminate the new string with null character.
Your array is too small
Use the correct type for indexes (int is not the correct one)
Check if the character is the letter. If not decide what to do (in my example I convert all letters to uppercase, other chars are left as they are)
Do not use magic numbers. Instead of 65 use 'A'
Your assignment is wrong, you actually want something right opposite.
It will not work with all character encoding.
#include <ctype.h>
#include <stdio.h>
int main (void)
{
string word = "HE" ;
string string_word = "QWERTYUIOPASDFGHJKLZXCVBNM" ;
char mutated_word [strlen(word) + 1];
size_t i;
for (i = 0; word[i] != '\0'; i++)
{
if(isalpha((unsigned char)word[i]))
{
mutated_word[i] = string_word[toupper((unsigned char)word[i]) - 'A'];
}
else
{
mutated_word[i] = word[i];
}
}
mutated_word[i] = 0;
printf("%s", mutated_word);
}
https://godbolt.org/z/4zqq98Y3n
To make it more portable:
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stddef.h>
ptrdiff_t findIndex(const char ch, const char * restrict dict)
{
char *result = strchr(dict, ch);
if(!result) return -1;
return result - dict;
}
int main (void)
{
string word = "He124" ;
string string_word = "QWERTYUIOPASDFGHJKLZXCVBNM" ;
string dict = "ABCDEFGHIJKLMNOPQRSTUVXYWZ";
ptrdiff_t index;
char mutated_word [strlen(word) + 1];
size_t i;
for (i = 0; word[i] != '\0'; i++)
{
if(isalpha((unsigned char)word[i]))
{
index = findIndex(toupper((unsigned char)word[i]), dict);
}
else index = -1;
mutated_word[i] = index == -1 ? word[i] : string_word[index];
}
mutated_word[i] = 0;
printf("%s", mutated_word);
}
https://godbolt.org/z/KW8TxxEvq
You program crashes because the assignment is in the wrong order: string_word[(int)word[i] - 65] = mutated_word[i]; is attempting to modify a string literal, which has undefined behavior. Note also that the destination string must be 1 byte longer for the null terminator, which you must set explicitly.
Here is a more portable version:
#include <ctype.h>
#include <stdio.h>
#include <string.h>
int main(void) {
const char *word = "HE";
const char *normal_word = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const char *string_word = "QWERTYUIOPASDFGHJKLZXCVBNM";
char mutated_word[strlen(word) + 1];
unsigned char c;
const char *p;
size_t i;
for (i = 0; (c = word[i]) != '\0'; i++) {
if (isupper(c) && (p = strchr(normal_word, c)) != NULL) {
c = string_word[p - normal_word];
} else
if (islower(c) && (p = strchr(normal_word, toupper(c))) != NULL) {
c = string_word[p - normal_word];
c = tolower(c);
}
mutated_word[i] = c;
}
mutated_word[i] = '\0';
printf("%s\n", mutated_word);
return 0;
}
Related
This is my program:
Does anyone know why it doesn't work?
My professor asked me to remove a character at an index using pointers, I'm also not allowed to use a for - loop so I'm kind of lost.
int count = 0;
int strl = strlen(s);
char s2 [strl-1];
if (index >= 0 && index < strl){
while(count < strl){
if (count == index){
*(s+index) == *s;
strl--;
}
count++;
}
printString(s);
}
}
Your program won't work because your program don't modify strings.
You can use memmove() to shift the string after the character to be removed left by one character to remove a character. (Pointers are used as the arguments of memmove())
#include <stdio.h>
#include <string.h>
void removeAt(char* str, int idx) {
size_t len = strlen(str);
memmove(str + idx, str + idx + 1, len - idx);
}
int main(void) {
char target[] = "0123456789";
printf("before removing : %s\n", target);
removeAt(target, 5);
printf("after removing : %s\n", target);
return 0;
}
Output:
before removing : 0123456789
after removing : 012346789
In order to remove a character at index i from a string you need to move every character after it one space back:
void remove_at(char* s, size_t i) {
if (!s) return;
while (s[i]) {
s[i] = s[i+1];
i++;
}
}
It's undefined behavior to pass an i >= strlen(s), so beware.
Here is an example using pointers to delete a character at a specific index in a string:
#include <assert.h>
#include <stdio.h>
#include <string.h>
void DeleteChar(int index, char string[])
{
char *ptr;
assert(index >= 0);
assert(index < strlen(string));
ptr = string + index;
while (*ptr != '\0') {
*ptr = *(ptr + 1);
ptr++;
}
}
int main(void)
{
char string[] = "hello world";
DeleteChar(9, string);
puts(string);
return 0;
}
Note, however, that it is safer and simpler to use only indices instead of pointers.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int toggleChars (char* string, char* letters){
int count = 0;
char* scurrent = string;
while(*scurrent != '\0'){
char* lcurrent = letters;
while(*lcurrent != '\0'){
if(*scurrent == *lcurrent){
*scurrent = '0';
count += 1;
}
lcurrent += 1;
}
scurrent += 1;
}
return count;
}
int main(){
char* str = malloc(50);
char* letters = malloc(20);
str = "Hi how R U today?";
letters = "HhiR";
int x = toggleChars(str, letters);
printf("str: %s\ncount: %d", str, x);
return 0;
}
This is just a testing function I made to study for an upcoming exam in C programming. When I compile this and run it, it gives me a segfault. I have deduced with some testing that it is caused by the line
*scurrent = '0';
So it means that I should not change the character at that memory location. But then if I do want to change it, what would I have to do?
There is a problem with your code, the line str = "Hi how R U today?"; will not copy the string to the character array you dynamically allocated, instead it will point to the const char* (read only copy).
So because of this when you are trying to change the contents of str through the toggleChars() function it is throwing a segmentation fault.
You can edit your code as follows:
#include <stdio.h>
int toggleChars (char* string, char* letters){
int count = 0;
char* scurrent = string;
while(*scurrent != '\0'){
char* lcurrent = letters;
while(*lcurrent != '\0'){
if(*scurrent == *lcurrent){
*scurrent = '0';
count += 1;
}
lcurrent += 1;
}
scurrent += 1;
}
return count;
}
int main(){
char str[] = "Hi how R U today?";
char letters[] = "HhiR";
int x = toggleChars(str, letters);
printf("str: %s\ncount: %d", str, x);
return 0;
}
Instead of this, if you want to use dynamic memory allocation you can use strcpy() function from standard library. https://www.geeksforgeeks.org/strcpy-in-c-cpp/
Thanks, hope this helps,
-Rajkumar
I'm trying to write a function which changes letters into two asterisks (*) using pointers.
For example:
Input: hello12345good++//--ok
Output: **********123456********++//--****
I've writen one that changes letters into two of the same letters, but couldn't write the same for *.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int points_converter(char str[])
{
char *s, *s1;
int f = 0;
for (s = str; *s; s++)
{
if(isalpha(*s))
{
f = 1;
s1 = s;
s = s + strlen(s);
while(s != s1 - 1)
*(s+1) = *(s--);
s = s + 2;
}
}
return f;
}
int main()
{
char str[81];
int f;
puts("Input string:");
while (strlen(gets(str)) >= 81);
f = points_converter(str);
if (f == 0)
{
puts("No latin letters in string.");
}
else
{
puts("New string: ");
puts(str);
}
return 0;
}
like this
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdbool.h>
bool points_converter(char str[]){
bool f = false;
char *temp = malloc(strlen(str)*2+1);
char *s = str, *d = temp;
if(!temp){
perror("malloc:");
return f;//no change
}
for (; *s; s++){
if(isalpha((unsigned char)*s)){
f = true;
*d++ = '*';
*d++ = '*';
} else {
*d++ = *s;
}
}
*d = 0;
strcpy(str, temp);//`str` must have enough spaces.
free(temp);
return f;
}
#define MAX_LENGTH 40
int main(void){
char str[MAX_LENGTH * 2 + 1];
while(true){
puts("Input string:");
fgets(str, MAX_LENGTH+1+1, stdin);//+1:newline, +1:NUL. Use fgets instead of gets
char *p = strchr(str, '\n');
if(p){
*p = '\0';//chomp newline
break;
} else {
while (getchar() != '\n');//Input too long, clear input
}
}
if (points_converter(str)) {
puts("New string: ");
puts(str);
} else {
puts("No latin letters in string.");
}
return 0;
}
how about:
static const int MAXINPUTLEN=81;
int points_converter(const char* input, char *output)
{
int count = 0; // initialize counter to zero
while (*input) { // while input is not pointing to zero
if (isalpha(*input)) { // if input is pointing to alpha
output[0] = '*'; // replace first byte pointed to by output with '*'
output[1] = '*'; // replace 2nd byte pointed to by output with '*'
output += 2; // increment output by 2
count++; // increment counter
} else {
*output = *input; // copy non-alpha to output
output++; // increment output by one
}
input++; // increment input pointer by one
}
*output = 0; // terminate output with zero byte
return count; // return count
}
int main()
{
char input[MAXINPUTLEN + 1];
char output[2 * MAXINPUTLEN + 1];
gets(input); // not checking for input overflow!
points_converter(input, output);
}
I wanna ask how it can not get integer from a string
for example, here are my code:
int main() {
char str[] = "ababbababa-1998";
int nr = atoi(str);
printf("%d\n", nr);
return (EXIT_SUCCESS);
}
when running, it print out 0 but not 1998, how can I fix it ?
In your case you can use strtok.
int main() {
char str[] = "ababbababa-1998";
char * const first_part = strtok(str, "-");
if (first_part == NULL) {
return 1;
}
char * const second_part = strtok(NULL, "-");
if (second_part == NULL) {
return 1;
}
int nr = atoi(second_part);
printf("%d\n", nr);
return 0;
}
You can look at Why is there no strtoi in stdlib.h? for error check atoi.
Keep walking down str() until code finds something numeric using strtol().
int main() {
char str[] = "ababbababa-1998";
char *p = str;
char *endptr;
while (*p) {
long number = strtol(p, &endptr, 10);
// Was conversion successful?
if (endptr != p) {
printf("%ld\n", number);
return EXIT_SUCCESS;
}
p++;
}
puts("No conversion");
return EXIT_FAILURE;
}
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define ASCII '0'
int
main(void) {
char const str[] = "ababbababa-1998";
int i, result = 0;
for (i = 0; str[i]; i++) {
if (isdigit(str[i])) {
result *= 10;
result += str[i] - ASCII;
}
}
printf("number = %d\n", result);
return 0;
}
If you want to extract all the numeric digits from a string you could use this function I created.
You will need these header files for this function to work.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
void getNumbers(char data[]) {
int index = 0;
char current;
for( int i = 0; i < strlen(data); ++i ) {
current = data[i];
if (current >= 48 && current <= 57) {
data[index++] = current;
}
}
data[index] = '\0';
}
You can use the above function like this.
char foobar[] = "1A2B3C4D5E6F7G8H9I";
getNumbers(foobar);
printf("%s", foobar);
The above code will output 123456789
I wanted to split an array to 2 arrays that the first one contains the lowercased letters of the original array and the second one contains the uppercased letters and from some reason it prints some unrelated chars.
#include <stdio.h>
#include <string.h>
#define LEN 8
int main(void)
{
char str[] = "SHaddOW";
char smallStr[LEN], bigStr[LEN];
int i = 0;
int indexSmall = 0;
int indexBig = 0;
for (i = 0; i <= LEN; i++)
{
if (str[i] <= 'Z')
{
smallStr[indexSmall] = str[i];
indexSmall++;
}
if (str[i] >= 'Z')
{
bigStr[indexBig] = str[i];
indexBig++;
}
}
printf("1: ");
puts(smallStr);
printf("2: ");
puts(bigStr);
system("PAUSE");
return 0;
}
Don't define length before you create the string to test.
Create it's length after defining the string to test.
Copy the characters as you encounter them, but as #Ed Heal says you must add a null terminator so that you can print out the two strings (they aren't really strings until they are null terminated).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main (void)
{
char str[] = "SHaddOW";
int len = strlen(str) +1;
char smallStr[len], bigStr[len];
char term[] = {'\0'};
int n, s, b;
s=0;
b=0;
for(n=0; n<len; n++) {
if(islower(str[n])) {
memcpy(smallStr +s, str +n, 1);
s++;
} else if (isupper(str[n])){
memcpy(bigStr +b, str +n, 1);
b++;
}
}
memcpy(smallStr + s, term, 1);
memcpy(bigStr + b , term, 1 );
printf("Upper: %s\n", bigStr);
printf("Lower: %s\n", smallStr);
}
Output:
Upper: SHOW
Lower: add
Add this to the if structure (and other code to support it)
} else {
memcpy(anyStr +a, str +n, 1);
a++;
}
then:
char str[] = ".S1H2a3d4d5O6W.";
and:
printf("Anything else: %s\n", anyStr);
returns:
Upper: SHOW
Lower: add
Anything else: .123456.
A more compact approach with (perhaps) more meaningful variable names:
#include <stdio.h>
#include <ctype.h>
#include <stdint.h>
#include <string.h>
int main ( void ) {
const char str[] = "SHaddOW";
size_t len = strlen(str); /* better to get actual length */
char lowers[len + 1]; /* add one for the nul char */
char uppers[len + 1]; /* (see below) */
int c;
int i = 0;
int n_upper = 0;
int n_lower = 0;
while ((c = str[i++]) != '\0') {
if (isupper(c)) uppers[n_upper++] = c; /* no need to reinvent */
if (islower(c)) lowers[n_lower++] = c; /* the wheel here */
}
uppers[n_upper] = '\0'; /* the nul char ('\0') marks */
lowers[n_lower] = '\0'; /* the end of a C "string" */
printf("1: %s\n", lowers);
printf("2: %s\n", uppers);
return 0;
}
Notes
If you are super concerned about efficiency you could add an else before if (islower...
Adding const means you "promise" the characters in the array won't be changed.
The type size_t is an integer type, but may be larger than int. It is the correct type for the return of strlen(). It is defined in <stdint.h>. None the less, using int will almost always work (on most systems a string would have to be 'yooooge' for its length to be bigger than an int can hold).
The variable c is declared as int instead of char because int is the proper type for the isXXXXX() functions (which are defined in <ctype.h>). It is also a good habit to get into because of the parallels between this loop and another common idiom while ((c = fgetc(fp)) != EOF) ....
You should consider using isupper() and islower() functions. Code would be cleaner. And what if you have some non alpha characters? Your conditions won't work.
for (i = 0; i < LEN; i++)
{
if (islower(str[i]))
{
smallStr[indexSmall] = str[i];
indexSmall++;
}
else if (isupper(str[i]))
{
bigStr[indexBig] = str[i];
indexBig++;
}
}
As #Ed Heal mention. To avoid printing rubbish, after for loopt you should add a null characters to arrays.
smallStr[indexSmall] = '\0';
bigStr[indexBig] = '\0';