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';
Related
#include <stdio.h>
#include <string.h>
int main(void) {
char string[1024];
int len = 0;
int i = 0;
while (fgets(string, sizeof(string), stdin) != 0);
len = strlen(string) - 1;
if (len % 2 == 0) {
printf("%s", string);
}
}
The aim of this code is to print out inputs that have an even number of characters and omit anything else (will not print it). The program works when there is no space in the string however once I place a space it counts it as the length which I'm trying to stop. How do I make this program omit spaces when counting the length of the string?
How do I make the strlen() function not count spaces?
The standard function strlen() simple does not do that. Easy to code a new function that does.
#include <ctype.h>
#include <stddef.h>
size_t spaceless_strlen(const char *s) {
size_t len = 0;
const unsigned char *us = (const unsigned char *) s;
while (*us) {
if (*us != ' ') len++;
// Or if not counting white-spaces
if (!isspace(*us)) len++;
us++;
}
return len;
}
Best to pass unsigned char values to is...() functions so a unsigned char * pointer was used.
The trick is to only count characters you want. strlen() counts all characters. Write yourself a function:
#include <string.h>
size_t count( const char * s, int (*f)( int ) )
//
// Return the number of elements in the c-string
// `s` that satisfy the predicate function `f()`.
// The function type matches the Standard Library
// character classification functions in <ctype.h>.
{
size_t result = 0;
while (*s) result += f( *s++ );
return result;
}
With that in hand, you need a predicate function that will return 1 for non-whitespace characters, and 0 for whitespace characters. Easy enough:
#include <ctype.h>
int not_isspace( int c )
{
return !isspace( c );
}
Now you can totally count the number of non-whitespace characters in your string:
int length = count( s, ¬_isspace );
That’s it!
Regarding how you can achieve counting characters that are not spaces, you can try this.
#include <stdio.h>
#include <string.h>
int main(void) {
char string[1024];
int len;
int count=0;
int i;
while (fgets(string, sizeof(string), stdin) != 0){
len = strlen(string) ;
for (i=0; i<len;i++)
{
if (string[i]!=' ')
count++;
}
if (count % 2 == 0)
{
printf("%s", string);
}
}
return 0;
}
Note: In my opinion, this isn't the most optimal way to achieve so but I tried to keep it based on your code and logic!
This seems better :
EDIT : it is if you replace the get function with fgets as you initially did!
#include <stdio.h>
#include <stdlib.h>
int main()
{
char str[1024];
int i=0,count=0;
printf("Enter a String\n");
gets(str);
while(str[i]!='\0')
{
if(str[i]!=' ')
{
count++;
}
i++;
}
if(count% 2 ==0)
{
printf("%s ",str,);
}
return 0;
}
It is possible to make a dedicated function using fgetc() instead of calling fgets() which returns the read string and its length (without counting the spaces):
#include <stdio.h>
#include <string.h>
#include <ctype.h>
static int my_fgets(char *s, int size, FILE *stream)
{
char c;
int len;
char *in;
if (!s || (size <= 0)) {
return 0;
}
len = 0;
in = s;
do {
c = fgetc(stream);
if ((len < (size - 1)) && (c != EOF) && (c != '\n')) {
if (!isspace(c)) {
len ++;
}
*(in ++) = c;
}
} while ((len < (size - 1)) && (c != EOF) && (c != '\n'));
*in = '\0';
return len;
}
int main(void) {
char string[1024];
int len = 0;
int i = 0;
len = my_fgets(string, sizeof(string), stdin);;
if (len % 2 == 0) {
printf("%s, len=%d\n", string, len);
}
}
If you aren't super-concerned about performance, the easiest to read version might be to call strchr repeatedly in a loop, count the spaces and then subtract them from the string length. Example:
size_t spaceout (const char* original)
{
size_t spaces = 0;
for(char* str=strchr(original,' '); str!=NULL; str=strchr(str+1,' '))
{
spaces++;
}
return strlen(original) - spaces;
}
This only looks for ' ' and it actually iterates over the string twice because of the final strlen call. But the code is quite easy to read.
A possible micro-optimization would be to pass the string length as parameter in case the caller already knows it.
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;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char first[15];
printf("\n\tWrite here your code");
scanf("%s",first);
if()//there is "n" in the char
//change n with 1
else
//quit
return 0;
}
Replace character with character
This code will replace every occurrence of the character 'n' with the character '1'.
#include <stdio.h>
int main(void)
{
char str[15];
printf("Input: ");
scanf("%14s", str); // prevent buffer overflow
for (int i = 0; str[i]; ++i) { // iterate over str
if (str[i] == 'n')
str[i] = '1';
}
printf("Modified: %s\n", str);
return 0;
}
Replace character with string
This code will replace every occurrence of the character 'n' with the string "1+k" using the function strcat. The modified string is saved to char mod[].
#include <stdio.h>
#include <string.h>
#include <stdio.h>
int main(void)
{
char str[15];
printf("Input: ");
scanf("%14s", str); // prevent buffer overflow
char mod[] = "";
for (int i = 0; str[i]; ++i) { // iterate over str
if (str[i] == 'n') {
char *repl = "1+k";
strcat(mod, repl); // add "1+k" to mod
} else {
strncat(mod, &str[i], 1); // add str[i] to mod
}
}
printf("Modified: %s\n", mod);
return 0;
}
Such a trivial question deserves a non trivial answer
Note that this approach with branching, demonstrated by #Andy Sukowski-Bang, is - when compiled with -O3 - roughly 6.5x time slower than my approach, illustratating the efficiency of bitwise operations over branching instructions (not to mention Meltdown and Spectre vulnerabilities and its on branching if mitigations are enabled).
The following program will convert every occurence of the letter from to the designated letter.
It is able to replace all characters from 'A' to 'z' to '8' in a string of 8,286,208 bytes in only 0.07s:
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <time.h>
// gcc -O3 replace.c && ./a.out
void replace(char *s, char from, char to, long n) {
char eq;
while (n--) {
eq = !(*s ^ from);
*s = !eq * *s + eq * to;
s++;
}
}
void replace_branching(char *s, char from, char to, long n) {
while (n--) {
if (*s == from)
*s = to;
s++;
}
}
void read_file_to_buffer(FILE *f, long length) {
char buffer[length + 1];
fseek(f, 0, SEEK_SET);
void (*fptr[2]) (char *s, char from, char to, long n) = {replace_branching, replace};
if (fread (buffer, 1, length, f) ) {
buffer[length] = '\0';
fclose (f);
char subbuff[33];
subbuff[32] = '\0';
char from = 'A';
char to = '8';
clock_t start, end;
double cpu_time_used[2];
for (int j = 0; j < 2; j++){
start = clock();
for (int i = 0; i < 0x20 + 26; i++) {
fptr[j](buffer, from + i, to, length);
//memcpy( subbuff, &buffer[0], 32 );
//printf("Modified: %s\n", subbuff);
}
end = clock();
cpu_time_used[j] = ((double) (end - start)) / CLOCKS_PER_SEC;
printf("Time: %fs\n", cpu_time_used[j]);
}
printf("Without branching it is %fx faster\n", cpu_time_used[0] / cpu_time_used[1]);
}
}
int main(void)
{
FILE * f;
long length;
if ((f = fopen ("test.txt", "rb"))) // NB: test.txt is a file of 8,286,208 bytes
{
fseek (f, 0, SEEK_END);
read_file_to_buffer(f, ftell(f));
}
return 0;
}
/*
Time: 0.475005s
Time: 0.070859s
Without branching it is 6.703524x faster
*/
Some explanations
eq = !(*s ^ from); // eq will equal 0 if letters are same, else it will equal 1
*s = !eq * *s + eq * to; // we assign to the pointer its same old value with !eq if the character 'from' was absent, else we will assign the character 'to'.
PS: No malloc were used, I used VLA and it is bad, very bad, don't do this at home!
I've got a block of strings, say "aaa\0bbbb\0ccccccc\0"
and I want to turn them into an array of strings.
I've tried to do so using the following code:
void parsePath(char* pathString){
char *pathS = malloc(strlen(pathString));
strcpy(pathS, pathString);
printf(1,"33333\n");
pathCount = 0;
int i,charIndex;
printf(1,"44444\n");
for(i=0; i<strlen(pathString) ; i++){
if(pathS[i]=='\0')
{
char* ith = malloc(charIndex);
strcpy(ith,pathS+i-charIndex);
printf(1,"parsed string %s\n",ith);
exportPathList[pathCount] = ith;
pathCount++;
charIndex=0;
}
else{
charIndex++;
}
}
return;
}
exportPathList is a global variable defined earlier in the code by
char* exportPathList[32];
when using that function exportPathList[i] contains garbage.
What am I doing wrong?
The answer to this SO question:
Parse string into argv/argc
deals with a similar issue, you might have a look.
You need to know how many strings are there or agree for an "end of strings". The simplest would be to have an empty string at the end:
aaa\0bbbb\0ccccccc\0\0
^^
P.S. is this homework?
First of all, since your strings are delimited by a null char, '\0', strlen will only report the size of the string up to the first '\0'. strcpy will copy until the first null character as well.
Further, you cannot know where the input string ends with this information. You either need to pass in the whole size or, for example, end the input with double null characters:
#include <stdio.h>
#include <string.h>
void parsePath(const char* pathString){
char buf[256]; // some limit
while (1) {
strcpy(buf, pathString);
pathString+=strlen(buf) + 1;
if (strlen(buf) == 0)
break;
printf("%s\n", buf);
}
}
int main()
{
const char *str = "aaa\0bbbb\0ccccccc\0\0";
parsePath(str);
return 0;
}
And you need some realloc's to actually create the array.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXSIZE 16
char* exportPathList[MAXSIZE] = {0};
size_t pathCount = 0;
void parsePath(char* pathString){
char *ptop, *pend;
ptop=pend=pathString;
while(*ptop){
while(*pend)++pend;
exportPathList[pathCount++]=strdup(ptop);
pend=ptop=pend+1;
}
}
int main(){
char textBlock[]= "aaa\0bbbb\0ccccccc\0";
//size_t size = sizeof(textBlock)/sizeof(char);
int i;
parsePath(textBlock);
for(i=0;i<pathCount;++i)
printf("%s\n", exportPathList[i]);
return 0;
}
The solution I've implemented was indeed adding double '\0' at the end of the string and using that in order to calculate the number of strings.
My new implementation (paths is the number of strings):
void parsePath(char* pathString,int paths){
int i=0;
while (i<paths) {
exportPathList[i] = malloc(strlen(pathString)+1);
strcpy(exportPathList[i], pathString);
pathString+=strlen(pathString);
i++;
}
}
I'd like to thank everyone that contributed.
My Implementation looks like this -> it follows the idea of argv and argc in a main funtion:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void){
char **args = (char**)malloc(100*sizeof(char));
char buff[100], input_string[100], letter;
for(int i = 0; i < 100; i++){
buff[i] = '\0';
input_string[i] = '\0';
}
for(int i = 0; (letter = getchar())!='\n'; i++){
input_string[i] = letter;
}
int args_num = 0;
for(int i = 0, j = 0; i < 100;i++){
if((input_string[i] == ' ')||(input_string[i]=='\0')){
//reset j = 0
j = 0;
args[args_num] = malloc(strlen(buff+1));
strcpy(args[args_num++],buff);
for(int i = 0; i < 100; i++)buff[i] = '\0';
}else buff[j++] = input_string[i];
}
for(int i = 0; i < args_num; i++){
printf("%s ",args[i]);
}
}
-> Every single word in your string can then be accessed with args[i]
I'm parsing a text file:
Hello, this is a text file.
and creating by turning the file into a char[]. Now I want to take the array, iterate through it, and create an array of arrays that splits the file into words:
string[0] = Hello
string[1] = this
string[2] = is
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "TextReader.h"
#include <ctype.h>
void printWord(char *string) {
int i;
for (i = 0; i < strlen(string); i ++)
printf("%c", string[i]);
printf("\n");
}
void getWord(char *string) {
char sentences[5][4];
int i;
int letter_counter = 0;
int word_counter = 0;
for (i = 0; i < strlen(string); i ++) {
// Checks if the character is a letter
if (isalpha(string[i])) {
sentences[word_counter][letter_counter] = string[i];
letter_counter++;
} else {
sentences[word_counter][letter_counter + 1] = '\0';
word_counter++;
letter_counter = 0;
}
}
// This is the code to see what it returns:
i = 0;
for (i; i < 5; i ++) {
int a = 0;
for (a; a < 4; a++) {
printf("%c", sentences[i][a]);
}
printf("\n");
}
}
int main() {
// This just returns the character array. No errors or problems here.
char *string = readFile("test.txt");
getWord(string);
return 0;
}
This is what it returns:
Hell
o
this
is
a) w
I suspect this has something to do with pointers and stuff. I come from a strong Java background so I'm still getting used to C.
With sentences[5][4] you're limiting the number of sentences to 5 and the length of each word to 4. You'll need to make it bigger in order to process more and longer words. Try sentences[10][10]. You're also not checking if your input words aren't longer than what sentences can handle. With bigger inputs this can lead to heap-overflows & acces violations, remember that C does not check your pointers for you!
Of course, if you're going to use this method for bigger files with bigger words you'll need to make it bigger or allocate it dymanically.
sample that do not use strtok:
void getWord(char *string){
char buff[32];
int letter_counter = 0;
int word_counter = 0;
int i=0;
char ch;
while(!isalpha(string[i]))++i;//skip
while(ch=string[i]){
if(isalpha(ch)){
buff[letter_counter++] = ch;
++i;
} else {
buff[letter_counter] = '\0';
printf("string[%d] = %s\n", word_counter++, buff);//copy to dynamic allocate array
letter_counter = 0;
while(string[++i] && !isalpha(string[i]));//skip
}
}
}
use strtok version:
void getWord(const char *string){
char buff[1024];//Unnecessary if possible change
char *p;
int word_counter = 0;
strcpy(buff, string);
for(p=buff;NULL!=(p=strtok(p, " ,."));p=NULL){//delimiter != (not isaplha(ch))
printf("string[%d] = %s\n", word_counter++, p);//copy to dynamic allocate array
}
}