split string value in arrays - c

I have to split a string-input value where-ever there is a blankspace and output the result.
eg: input:
I am a noob at C
output:
>>I
>>am
>>a
>>noob
>>at
>>C
Code:
void splitText(){
char str[100];
char sep[] = " \r\n";
char *res; //if i remove this
fgets(str,sizeof str,stdin);
if (fgets(str, sizeof str, stdin) == NULL) {
printf("error");
}
char *p = strchr(str, '\n');
if (p) *p = 0;
res = strtok(str, sep); //and this
printf("%s\n",res); //and change this to str
}
Working code for anyone encountering the same problem:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void splitText() {
char str[100];
char sep[] = " \n";
char *res;
fgets(str,sizeof str, stdin);
if ( fgets(str, sizeof str, stdin) == NULL ) {
printf("Error");
break;
}
res = strtok(str, sep);
while(res != NULL){
printf("Splitted String: \"%s\"\n",res);
res = strtok(NULL,sep);
}
}
Thanks to everyone who contributed in helping me with this issue!

The problem with
char str[100] = scanf("%s",str);
is that you are assigning an int to a char array.
scanf() returns the number of items successfully scanned. The actual reading of chars into the array is done by scanf() itself. So you just need to call scanf() separately.
if (scanf("%s",str) != 1) { /* error */}
But scanf() is not the right tool here since you want to read a whole line. scanf() would stop at the first whitespace (after reading non-whitespace chars).
So when you type "I am a noob at C", scanf() will only read the I and ignore the rest.
What you want is to use the fgets() function to read a line:
char str[100];
if (fgets(str, sizeof str, stdin) == NULL) {
/* error */
}
/* rest of the code */
fgets() would read the newline as well if there's space in the buffer. If this is undesirable, then you can remove it:
char *p = strchr(str, '\n');
if (p) *p = 0; //remove the trailing newline.
Note: strtok() is not a thread safe function. POSIX provides strtok_r() as a thread-safe alternative. This is something to be aware of even if it doesn't matter in this specific case.
Here's a self contained example:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void) {
char str[100];
char sep[] = " \n";
char *res;
if ( fgets(str, sizeof str, stdin) == NULL ) {
exit(1);
}
res = strtok(str, sep);
while(res != NULL){
printf("Splitted String: \"%s\"\n",res);
res = strtok(NULL,sep);
}
return 0;
}

That is not how scanf() works.
Change the code to
char str[100];
scanf("%s",str);
A little note about scanf()
You should check for return values, like here for scanf().
if (scanf("%s", str) != 1)
{
printf("scanf failed");
exit(0);
}
You should also mention the number of chars to be read by scanf() to avoid buffer overflow.
scanf("%99s", str)
For a char str[100] of size 100, one should give 99 to keep place for the null character \0.

Related

Efficient Memory allocation and freeing question

I am writing a program that prints a string having been removed white space.
At this time, in the removeWhiteSpace function, I would like to know if memory allocation and freeing are used efficiently.
If not, can you suggest appropriate improvements:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *removeWhiteSpace();
int main()
{
char *inputString = malloc(sizeof(char) * 100);
scanf(" %[^\n]s", inputString);
removeWhiteSpace(inputString);
printf("%s\n", inputString);
free(inputString);
return 0;
}
char *removeWhiteSpace(char *inputString)
{
char *tempArray = malloc(sizeof(char) * 100);
char *tempPointer = strtok(inputString, " ");
while (tempPointer != NULL)
{
strcat(tempArray, tempPointer);
tempPointer = strtok(NULL, " ");
}
strcpy(inputString, tempArray);
free(tempArray);
return tempArray;
}
I would do a tortoise and hare algorithm.
Copy only characters that are not space.
char *removeWhiteSpace(char *inputString) {
char *in = inputString;
char *out = inputString;
// small optimization - do not copy to itself
while (*in != '\0' && *in != ' ') {
in++;
out++;
}
for (; *in != '\0'; in++) {
if (*in != ' ') {
*out++ = *in;
}
}
*out = '\0';
return inputString;
}
Dynamic allocation takes some cost. Dynamically allocating such small fixed-size arrays doesn't look efficient. Also the return value of removeWhiteSpace is meaningless because it refers to a buffer that is already freed.
Simply allocate the arrays statically and have removeWhiteSpace return nothing.
Also note that:
You should declare arguments of functions to avoid mistakes.
You have to initialize the array tempArray before using strcat for that. Using initializer won't be efficient because it wll initialize all elements while only initializing the first element is required for strcat().
You should limit the maximum length to read via scanf() to avoid buffer overrun.
You won't need s in the scanf() format because input is specified by [ and there are no scanf() after that. The s is telling scanf() to consume s after the string.
Try this:
#include <stdio.h>
#include <string.h>
void removeWhiteSpace(char*);
int main()
{
char inputString[100];
scanf(" %99[^\n]", inputString);
removeWhiteSpace(inputString);
printf("%s\n", inputString);
return 0;
}
void removeWhiteSpace(char *inputString)
{
char tempArray[100];
char *tempPointer = strtok(inputString, " ");
tempArray[0] = '\0';
while (tempPointer != NULL)
{
strcat(tempArray, tempPointer);
tempPointer = strtok(NULL, " ");
}
strcpy(inputString, tempArray);
}

printing after splitting a line of text at delimiters

I am having trouble printing this. When I requested the user to insert an int it worked, but when attempting to switch it over to a char input it got screwy and won't print anything.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
const char delim[2] = ",";
char *token;
int j = 0;
char *hh;
FILE *ptr_file;
char buf[1000];
ptr_file = fopen("input.txt", "r");
if (!ptr_file)
return 1;
char *pt[] = { "H", "He", "Li", "Be", "B", "C", "N", "O", "F", "Ne", "Na" };
printf("what element do you want(Use atomic number)");
scanf("%s", &hh);
for (j = 0; j <= 3; j++) {
if (hh == pt[j]) {
fgets(buf, 1000, ptr_file);
token = strtok(buf, delim);
while (token != NULL) {
printf("%s\n", token);
token = strtok(NULL, delim);
}
break;
} else {
fgets(buf, 1000, ptr_file);
continue;
}
}
fclose(ptr_file);
return 0;
}
The major problem here is, you are passing scanf() the address of an uninitialized pointer hh. scanf invokes undefined behavior trying to store the word at that address.
You should make hh an array, like char hh[8] = {0}; and use scanf() this way:
scanf("%7s", hh); // to avoid buffer overflow
That said,
if(hh == pt[j]) is not the way to compare strings. You need to use strcmp() to do that, and write if (strcmp(hh, pt[j]) == 0).
you should also check the return value of scanf() to verify if input was correctly converted.
The code
char *hh;
//...
scanf("%s", &hh);
it is UB due to hh uninitialized: it is pointing to garbage.
Furthermore "%s" format specifier wants char * as passed parameter: you are passing char **
should be
char *hh = malloc(MAX_STRING_LEN);
if (hh != NULL)
{
//...
scanf("%s", hh);
}
free(hh);
or simply
char hh[MAX_STRING_LEN] = {0};
//...
scanf("%s", hh);
Into both examples MAX_STRING_LEN expresses the maximum accepted length of string + 1 for null terminator.
Using c you cannot compare strings using logical operator ==, so the code
if(hh == pt[j])
is comparing addresses not the strings.
You can use strcmp to do that.

How to split string input?

This is part of my main function, the problem is: if my input for translation is given more than one word the program doesn't work properly, any idea about how can I fix that?
int main() {
struct node *temp;
char str[1000];
char word[MAXP];
char translation[MAXT];
char option[15];
while (1) {
str[0] = '\0';
word[0] = '\0';
translation[0] = '\0';
scanf("%[^\n]%*c", str);
sscanf(str, "%s %s %s", option, word, translation);
}
...
You can use fgets to read each input. Then sscanf to scan for the first two sub-strings. Using the %n specifier, the number of characters scanned can be captured to allow you to use strcpy from that index.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char end = '\0';
char str[1000];
char word[1000];
char translation[1000];
char option[15];
int used = 0;
int scanned = 0;
while(1){
str[0]='\0';
word[0]='\0';
translation[0]='\0';
fgets ( str, sizeof ( str), stdin);
str[strcspn ( str, "\n")] = '\0';//remove newline
scanned = sscanf(str, "%14s%999s%c%n", option, word, &end, &used);
if ( scanned >= 1) {//one sub string scanned
printf ( "%s\n", option);
}
if ( scanned >= 2) {//two sub strings scanned
printf ( "%s\n", word);
}
if ( scanned == 3) {//two sub strins and a character scanned
strcpy ( translation, &str[used]);
printf ( "%s\n", translation);
}
}
return 0;
}

Function to delete all occurrences of a word in a sentence in C

I have this code which will remove the first occurrence of the word from the sentence:
#include "stdio.h"
#include "string.h"
int delete(char *source, char *word);
void main(void) {
char sentence[500];
char word[30];
printf("Please enter a sentence. Max 499 chars. \n");
fgets(sentence, 500, stdin);
printf("Please enter a word to be deleted from sentence. Max 29 chars. \n");
scanf("%s", word);
delete(sentence, word);
printf("%s", sentence);
}
int delete(char *source, char *word) {
char *p;
char temp[500], temp2[500];
if(!(p = strstr(source, word))) {
printf("Word was not found in the sentence.\n");
return 0;
}
strcpy(temp, source);
temp[p - source] = '\0';
strcpy(temp2, p + strlen(word));
strcat(temp, temp2);
strcpy(source, temp);
return 1;
}
How would I modify it to delete all occurrences of the word in the given sentence? Can i still use the strstr function in this case?
Thanks for the help!
Open to completely different ways of doing this too.
P.S. This might sound like a homework question, but it's actually a past midterm question which I'd like to resolve to prepare for my midterm!
As a side question, if I use fgets(word, 30, stdin) instead of scanf("%s", word), it no longer works and tells me that the word was not found in the sentence. Why?
Try the following
#include <stdio.h>
#include <string.h>
size_t delete( char *source, const char *word )
{
size_t n = strlen( word );
size_t count = 0;
if ( n != 0 )
{
char *p = source;
while ( ( p = strstr( p, word ) ) != NULL )
{
char *t = p;
char *s = p + n;
while ( ( *t++ = *s++ ) );
++count;
}
}
return count;
}
int main( void )
{
char s[] = "abxabyababz";
printf( "%zu\n", delete( s, "ab" ) );
puts( s );
return 0;
}
The output is
4
xyz
As for the question about fgets then it includes the new line character in the string. You have to remove it from the string.
How would I modify it to delete all occurrences of the word in the given sentence?
There are many ways, as you have suggested, and since you are Open to completely different ways of doing this too...
Here is a different idea:
A sentence uses white space to separate words. You can use that to help solve the problem. Consider implementing these steps using fgets(), strtok() and strcat() to break apart the string, and reassemble it without the string to remove.
0) create line buffer sufficient length to read lines from file
(or pass in line buffer as an argument)
1) use while(fgets(...) to get new line from file
2) create char *buf={0};
3) create char *new_str; (calloc() memory to new_str >= length of line buffer)
4) loop on buf = strtok();, using " \t\n" as the delimiter
Inside loop:
a. if (strcmp(buf, str_to_remove) != 0) //approve next token for concatenation
{ strcat(new_str, buf); strcat(new_str, " ");}//if not str_to_remove,
//concatenate token, and a space
5) free allocated memory
new_str now contains sentence without occurrences of str_to_remove.
Here is a demo using this set of steps (pretty much)
int delete(char *str, char *str_to_remove)
{
char *buf;
char *new_str;
new_str = calloc(strlen(str)+1, sizeof(char));
buf = strtok(str, " \t\n");
while(buf)
{
if(strcmp(buf, str_to_remove) != 0)
{
strcat(new_str, buf);
strcat(new_str, " ");
}
buf = strtok(NULL, " \t\n");
}
printf("%s\n", new_str);
free(new_str);
getchar();
return 0;
}
int main(void)
{
delete("this sentence had a withh bad withh word", "withh");
return 0;
}

is there an any way to discard '\n'?

I am trying to to record response by the user(using getchar()). I am having issues with '\n' sticking in buffer. If I use fgets(char* buf, .. , ..), '\n' again goes into buf and you have to include '\n' at the end of the test string. when using string.h functions (like strcmp()). Is there any clean way of writing code for such purposes.
#include<stdio.h>
#include<string.h>
int main()
{
char buf[100];
fgets(buf, 3, stdin);
puts(buf);
int i = strcmp("p\n", buf);
printf("%d", i);
//if (!strcmp("CLock to random\n", buf))
//{
//puts("sucess");
//}
char c;
c = getchar();
putchar(c);
return 0;
}
Now I want to record response(single character 'p'). If I use getchar(), in place of fgets(), program skips second getchar()( c = '\n'). If I use the current code, i have to include \n in strcmp() every time.
If you want to discard the \n:
char buf[0x1000];
fgets(buf, sizeof(buf), stdin);
char *p = strchr(buf, '\n');
if (p) *p = 0;
#include <stdio.h>
#include <string.h>
char* chomp(char* str){
size_t len = strlen(str);
if(len>0 && str[len-1] == '\n')
str[len-1] = '\0';
return str;
}
int main(void){
char buf[128];
fgets(buf, sizeof(buf), stdin);
printf("<%s>\n", buf); //include newline
printf("<%s>\n", chomp(buf));//drop tail newline
printf("<%s>\n", chomp(buf));//NC
return 0;
}

Resources