I am trying to read the command line arguments that are separated by a semicolon with a blank space front and back (such as ls ; date ; cal), but the separation part has been difficult. My codes are working when I simply put an individual command line (such as ls or date), but whenever I put the semicolon, it does not work (such as ls ; date)
Here is my C code:
void parse(char *userInput, char **splitInput)
{
//read until userInput is not end of line
while (*userInput != '\0')
{
//replace any space in userInput as '\0'
while (*userInput == ';')
{
*userInput++ = '\0';
}
//save the argument position
*splitInput++ = userInput;
//if userinput is not equal to space, read next userInput
while (*userInput != ' ' && *userInput != ';' && *userInput != '\0')
{
userInput++;
}
}
}
void execute(char **splitInput)
{
pid_t pid = fork();
if (pid > 0) //parent process
{
pid_t parent_pid;
parent_pid = wait(NULL);
}
else if (pid == 0) //child process
{
if (execvp(*splitInput, splitInput) < 0)
{
printf("%s: command not found\n", *splitInput);
exit(1);
}
}
else //error
{
perror("fort error");
}
}
void main(void)
{
char userInput[100]; //execvp's first argument
char *splitInput[100]; //execvp's second argument
while(strcmp(userInput,"quit") != 0)
{
//ask for a user input
printf("group 10> ");
//read the entire line of input
scanf("%[^\n]", userInput);
//get characters from input; stop the loop problem
getchar();
//quit if user input is equal to quit
if (strcmp(userInput, "quit") == 0)
{
exit(0);
}
//parse the input
parse(userInput, splitInput);
//execute fork
execute(splitInput);
}
}
There are a number of ways to do this. string.h provides several functions that can be used, strtok(), strsep(), strchr(), or a combination of strcspn() and strspn() depending on your needs. You can also always walk-a-pointer down the string picking out the wanted tokens from the string and ignoring whitespace and multiple-included-delimiters. There is actually good pointer learning value in approaching it this way from an education standpoint.
Any time you are looping over anything picking out various pieces, instead of trying to include multiple nested while loops, each designed to scan-forward to either skip or find a certain class of characters, it is often more advantageous to use a state-loop where you use one of more flags to keep track of differing states. (line in-word reading character, or between words reading delimiters or whitespace, etc..). That way no nested loops are required and you simply use a single loop to loop over each character responding accordingly depending on your current state.
Putting that in work to scan down your string and pick out each of the words terminated by a delimiter ';' or by whitespace, and keeping a single state flag int in; to track whether you are in-word reading characters (in = 1;) or between words handling spaces and delimiters (in = 0;) and use char *sp as the start-pointer pointing to the beginning of each word and userInput as the end-pointer pointing to the current character being read, you could do:
void parse(char *userInput, char **splitInput, char delim, size_t nptrs)
{
int in = 0; /* simple in-word flag 0-false/1-true */
size_t n = 0; /* counter to protect splitInput bounds */
char *sp = userInput; /* start-pointer initialized to userInput */
while (n < nptrs - 1) { /* loop while pointers remain unfilled */
/* if at end, is whitespace or a delimiter */
if (!*userInput || isspace(*userInput) || *userInput == delim) {
if (in) { /* if in word */
splitInput[n++] = sp; /* set pointer to start-pointer */
splitInput[n] = NULL; /* set next pointer NULL */
}
in = 0; /* reset in flag zero */
if (*userInput) /* if space or delim, nul-terminate */
*userInput = 0;
else /* otherwise */
return; /* at end-of-string */
}
else { /* normal char */
if (!in) { /* if not in-word */
sp = userInput; /* set start-pointer to 1st good char */
in = 1; /* set in-word flag true */
}
}
userInput++; /* advance to next char */
}
}
(note: above the delim character is passed as a parameter along with nptrs to pass the number of pointers you have available so you can protect your pointer array bounds while filling pointers. Also note, the function always sets the next pointer in your array to NULL as a sentinel allowing you to loop over the pointers in your array in main() until NULL is reached since you don't return the number of pointers used, either as the function return or through a pointer parameter)
A simple example that parses the words from " my; ; ; dog ;;; has;fleas ;" using ';' or whitespace as delimiters could be:
#include <stdio.h>
#include <ctype.h>
#define NPTR 32 /* if you need a constant, #define one (or more) */
void parse(char *userInput, char **splitInput, char delim, size_t nptrs)
{
int in = 0; /* simple in-word flag 0-false/1-true */
size_t n = 0; /* counter to protect splitInput bounds */
char *sp = userInput; /* start-pointer initialized to userInput */
while (n < nptrs - 1) { /* loop while pointers remain unfilled */
/* if at end, is whitespace or a delimiter */
if (!*userInput || isspace(*userInput) || *userInput == delim) {
if (in) { /* if in word */
splitInput[n++] = sp; /* set pointer to start-pointer */
splitInput[n] = NULL; /* set next pointer NULL */
}
in = 0; /* reset in flag zero */
if (*userInput) /* if space or delim, nul-terminate */
*userInput = 0;
else /* otherwise */
return; /* at end-of-string */
}
else { /* normal char */
if (!in) { /* if not in-word */
sp = userInput; /* set start-pointer to 1st good char */
in = 1; /* set in-word flag true */
}
}
userInput++; /* advance to next char */
}
}
int main (void) {
char s[] = " my; ; ; dog ;;; has;fleas ;", *split[NPTR] = { NULL }, **p = split;
parse (s, split, ';', NPTR);
while (*p)
printf ("'%s'\n", *p++);
}
(note: the header ctype.h is included to make use of the isspace() function to test for whitespace rather than stringing together if() statements checking for space, '\t' or '\n'directly. This is generally good practice.)
Example Use/Output
$ ./bin/split_ptr_arr3
'my'
'dog'
'has'
'fleas'
Note in the output above all included whitespace is removed.
Look things over and let me know if you have questions. There are literally dozens of way to approach splitting strings, this is just one common and basic approach.
Related
Swap 2 first character to second last character and so on like 3 first character to third last character
untill character to middle of the word.
Input:
I love programming
Output:
i lvoe pnimmargorg
I tried to do
#include <stdio.h>
#include <string.h>
int main(){
int t;
scanf("%d",&t);
char s[105+t];
getchar();
for(int i=0;i<t;i++){
scanf("%[^\n]",s);
int len = strlen(s);
char temp[105+t];
getchar();
for(int i=0;i<len/2;i++){
strcpy(temp,s);
s[i] = s[len-i-1];
s[len-i-1] = temp;
}
for(int i=0;i<len/2;i++){
printf("%c",s[i]);
}
}
return 0;
}
This should do for swapping
for(int i=0;i<len/2;i++)
{
temp = s[i];
s[i] = s[len-i-1];
s[len-i-1] = temp;
}
There are a number of ways to approach this. The key is you want to be able to locate the beginning and end of each word in a line. (actually the 2nd and next to last character in each word). You cannot use strtok() or strsep() as both write nul-terminating characters in place of delimiters in your string. What you need is some way to manually advance though your line to locate the beginning and ending of each word.
One way is to use a pair of pointers and nested loops, with the outer loop advancing the start-pointer until the beginning of the next word is found. Then setting the end-pointer equal to the start-pointer and looping with a nested loop moving the end pointer until the next space or end-of-line is found. You know what lies between the two pointers will be your word.
Advance the start-pointer by one to the 2nd character and decrement the end-pointer by two to locate the next to last character (you subtract 2, one because you currently point to the next space after the word -- to find the last char, and then subtract again for the next-to-last char)
Another option is to use strspn() and strcspn() to take the place of the nested loops. strspn() returns the number of left-most characters in the string made up of only characters in the accept parameter (use " \t\n" to cause it to skip over spaces to the start of the next word) and strcspn() which returns the left-most number of character not including the characters in the reject parameter. (use the same " \t\n" to cause it to skip over all characters in the work to the next space returning the length of the word).
Writing a simple function to apply the logic to each word in the given string and swapping from the 2nd to next-to-last character in each word could be done as:
char *outsidein (char *s)
{
char *p = s; /* pointer to position in s to work toward end */
while (1) {
size_t offset = strspn (p, " \t\n"), /* find 1st non-space */
length = strcspn (p + offset, " \t\n"); /* find next space */
if (!length) /* at end, break */
break;
char *sp = p + offset + 1, /* start pointer to 2nd char in word */
*ep = p + offset + length - 2; /* end pointer to next to last char */
while (sp < ep) { /* loop toward middle */
int tmp = *ep; /* swap chars at sp & ep */
*ep-- = *sp;
*sp++ = tmp;
}
p += offset + length; /* update pointer to space following word */
}
return s; /* for convenience, return a pointer to s for immediate use */
}
(note: the string passed as the parameter s must be a mutable string)
Above the pointer p is advanced down the string saving the beginning location of each word, and then the number of spaces (offset) and length is added to it to advance to the next space after the word you processed.
A short example program that puts it altogether could be:
#include <stdio.h>
#include <string.h>
#define MAXC 1024 /* if you need a constant, #define one (or more) */
char *outsidein (char *s)
{
char *p = s; /* pointer to position in s to work toward end */
while (1) {
size_t offset = strspn (p, " \t\n"), /* find 1st non-space */
length = strcspn (p + offset, " \t\n"); /* find next space */
if (!length) /* at end, break */
break;
char *sp = p + offset + 1, /* start pointer to 2nd char in word */
*ep = p + offset + length - 2; /* end pointer to next to last char */
while (sp < ep) { /* loop toward middle */
int tmp = *ep; /* swap chars at sp & ep */
*ep-- = *sp;
*sp++ = tmp;
}
p += offset + length; /* update pointer to space following word */
}
return s; /* for convenience, return a pointer to s for immediate use */
}
int main (void) {
char line[MAXC];
while (fgets (line, MAXC, stdin)) { /* read each line */
line[strcspn (line, "\n")] = 0; /* trim \n character from end */
printf ("%s\n", outsidein (line)); /* output modified line */
}
}
Example Use/Output
$ echo "I love programming" | ./bin/str_outsidein
I lvoe pnimmargorg
There are a number of ways to do it. Look things over and let me know if you have questions.
That's a nice little exercise, that seems tricky at frst, but keeping it simple keeps the bugs away.
Things to look out for (aka traps for young players)
multiple spaces between words.
input strings that start with spaces.
input strings that end with a space.
See comments in code below.
#include <stdio.h>
#include <string.h>
void scramble(char* str)
{
char *p, *q, *word_start;
char c;
if (str == NULL)
return;
while (*str != 0)
{
// skip spaces, you could also use while (isspace(*str & 0xFF))
// which would suddenly make this function much more
// versatile and interesting.
while (*str == ' ')
++str;
// keep track of the start of the word
word_start = str;
// find end of word, you could also use isspace() here,
// if you decide to go that route.
while (*str != ' ' && *str != 0)
++str;
// str now points to one character past the last char of word
// swap the letters we want, from second to second to last,
// leave the others untouched. Note that the p < q test
// automatically skips processing of words of 3 bytes or less.
// so this takes also care of strings ending with a space
// which ould give us an empty word (when str == word_start)
for (p = word_start + 1, q = str - 2; p < q; ++p, --q)
{
c = *p;
*p = *q;
*q = c;
}
}
}
const char input_string[] = "I love programming";
int main()
{
char output_string[sizeof(input_string)];
strcpy(output_string, input_string);
printf("input: %s\n", input_string);
scramble(output_string);
printf("output: %s\n", output_string);
return 0;
}
Try it, and step through it: https://onlinegdb.com/SkxKerFYP
beginner here. So I'm trying to write some code that take a sentence and returns the longest word. When I debugg the program everything looks correct as I'd expect including the char array. However when I come to print the output I invariably get a NULL...
I've put in the entire code because I think one of the loops must be effecting the array string pointer in some way?
#include <stdio.h>
#include <string.h>
void LongestWord(char sen1[500]) {
/*
steps:
1. char pointer. Each Byte holds array position of each space or return value Note space = 32 & return = 10.
2. Once got above asses biggest word. Biggest word stored in short int (starting position)
3. Once got biggest word start - move to sen using strncpy
*/
char sen[500];
char *ptr = sen;
int i = 0;
int space_position[500];
int j = 0;
int k = 0;
int word_size_prior_to_each_position[500];
int l = 0;
int largest = 0;
int largest_end_position = 0;
int largest_start_position =0;
memset(&sen[0], 0, 500);
memset(&space_position[0], 0, 2000);
memset(&word_size_prior_to_each_position[0], 0, 2000);
while (i < 500) { //mark out where the spaces or final return is
if ((sen1[i] == 0b00100000) ||
(sen1[i] == 0b00001010))
{
space_position[j] = i;
j = j+1;
}
i = i+1;
}
while (k < 500) {
if (k == 0) {
word_size_prior_to_each_position[k] = (space_position[k]);
}
//calculate word size at each position
if ((k > 0) && (space_position[k] != 0x00)) {
word_size_prior_to_each_position[k] = (space_position[k] - space_position[k-1]) -1;
}
k = k+1;
}
while (l < 500) { //find largest start position
if (word_size_prior_to_each_position[l] > largest) {
largest = word_size_prior_to_each_position[l];
largest_end_position = space_position[l];
largest_start_position = space_position[l-1];
}
l = l+1;
}
strncpy(ptr, sen1+largest_start_position+1, largest);
printf("%s", *ptr);
return 0;
}
int main(void) {
char stringcapture[500];
fgets(stringcapture, 499, stdin);
LongestWord(stringcapture); //this grabs input and posts into the longestword function
return 0;
}
In the function LongestWord replace
printf("%s", *ptr);
with
printf("%s\n", ptr);
*ptr denotes a single character, but you want to print a string (see %s specification), so you must use ptr instead. It makes sense to also add a line break (\n).
Also remove the
return 0;
there, because it's a void function.
Returning the longest word
To return the longest word from the function as pointer to char, you can change the function signature to
char *LongestWord(char sen1[500])
Since your pointer ptr points to a local array in LongestWord it will result in a dangling reference as soon as the function returns.
Therefore you need to do sth like:
return strdup(ptr);
Then in main you can change your code to:
char *longest_word = LongestWord(stringcapture);
printf("%s\n", longest_word);
free(longest_word);
Some more Hints
You have a declaration
int space_position[500];
There you are calling:
memset(&space_position[0], 0, 2000);
Here you are assuming that an int is 4 bytes. That assumption leads to not-portable code.
You should rather use:
memset(&space_position[0], 0, sizeof(space_position));
You can even write:
memset(space_position, 0, sizeof(space_position));
since space_position is the address of the array anyway.
Applied to your memsets, it would look like this:
memset(sen, 0, sizeof(sen));
memset(space_position, 0, sizeof(space_position));
memset(word_size_prior_to_each_position, 0, sizeof(word_size_prior_to_each_position));
Instead of using some binary numbers for space and return, you can alternatively use the probably more readable notation of ' ' and '\n', so that you could e.g. write:
if ((sen1[i] == ' ') ||
(sen1[i] == '\n'))
instead of
if ((sen1[i] == 0b00100000) ||
(sen1[i] == 0b00001010))
The variable largest_end_position is assigned but never used somewhere. So it can be removed.
The following line
strncpy(ptr, sen1 + largest_start_position + 1, largest);
would omit the first letter of the word if the first word were also the longest. It seems largest_start_position is the position of the space, but in case of the first word (largest_start_position == 0) you start to copy from index 1. This special case needs to be handled.
You have a local array in main that is not initialized.
So instead of
char stringcapture[500];
you must write
char stringcapture[500];
memset(stringcapture, 0, sizeof(stringcapture));
alternatively you could use:
char stringcapture[500] = {0};
Finally in this line:
largest_start_position = space_position[l - 1];
You access the array outside the boundaries if l==0 (space_position[-1]). So you have to write:
if (l > 0) {
largest_start_position = space_position[l - 1];
}
else {
largest_start_position = 0;
}
While Stephan has provided you with a good answer addressing the problems you were having with your implementation of your LongestWord function, you may be over-complicating what your are doing to find the longest word.
To be useful, think about what you need to know when getting the longest word from a sentence. You want to know (1) what the longest word is; and (2) how many characters does it contain? You can always call strlen again when the function returns, but why? You will have already handled that information in the function, so you might as well make that information available back in the caller.
You can write your function in a number of ways to either return the length of the longest word, or a pointer to the longest word itself, etc. If you want to return a pointer to the longest word, you can either pass an array of sufficient size as a parameter to the function for filling within the function, or you can dynamically allocate storage within the function so that the storage survives the function return (allocated storage duration verses automatic storage duration). You can also declare an array static and preserve storage that way, but that will limit you to one use of the function in any one expression. If returning a pointer to the longest word, to also make the length available back in the caller, you can pass a pointer as a parameter and update the value at that address within your function making the length available back in the calling function.
So long as you are simply looking for the longest word, the longest word in the unabridged dictionary (non-medical) is 29-characters (taking 30-characters storage total), or for medical terms the longest word is 45-character (taking 46-characters total). So it may make more sense to simply pass an array to fill with the longest word as a parameter since you already know what the max-length needed will be (an array of 64-chars will suffice -- or double that to not skimp on buffer size, your call).
Rather than using multiple arrays, a simple loop and a pair of pointers is all you need to walk down your sentence buffer bracketing the beginning and end of each word to pick out the longest one. (and the benefit there, as opposed to using a strtok, etc. is the original sentence is left unchanged allowing it to be passed as const char * allowing the compiler to further optimize the code)
A longest_word function that passes the sentence and word to fill as parameters returning the length of the longest string is fairly straight forward to do in a single loop. Loosely referred to as a State Loop, where you use a simple flag to keep track of your read state, i.e. whether you are in a word within the sentence or whether you are in whitespace before, between or after the words in the sentence. A simple In/Out state flag.
Then you simply use a pointer p to locate the beginning of each word, and an end-pointer ep to advance down the sentence to locate the end of each word, checking for the word with the max-length as you go. You can use the isspace() macro provided in ctype.h to locate the spaces between each word.
The loop itself does nothing more than loop continually while you keep track of each pointer and then check which word is the longest by the simple pointer difference ep - p when the end of each word is found. If a word is longer than the previous max, then copy that to your longest word array and update max with the new max-length.
A short implementation could be similar to:
size_t longest_word (const char *sentence, char *word)
{
const char *p = sentence, *ep = p; /* pointer & end-pointer */
size_t in = 0, max = 0; /* in-word flag & max len */
if (!sentence || !*sentence) /* if NULL or empty, set word empty */
return (*word = 0);
for (;;) { /* loop continually */
if (isspace (*ep) || !*ep) { /* check whitespace & end of string */
if (in) { /* if in-word */
size_t len = ep - p; /* get length */
if (len > max) { /* if greater than max */
memcpy (word, p, len); /* copy to word */
word[len] = 0; /* nul-terminate word */
max = len; /* update max */
}
p = ep; /* update pointer to end-pointer */
in = 0; /* zero in-word flag */
}
if (!*ep) /* if end of word, bail */
break;
}
else { /* non-space character */
if (!in) { /* if not in-word */
p = ep; /* update pointer to end-pointer */
in = 1; /* set in-word flag */
}
}
ep++; /* advance end-pointer */
}
return max; /* return max length */
}
A complete example taking the sentence to be read as user-input could be similar to:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAXWRD 64 /* longest word size */
#define MAXC 2048 /* max characters in sentence */
size_t longest_word (const char *sentence, char *word)
{
const char *p = sentence, *ep = p; /* pointer & end-pointer */
size_t in = 0, max = 0; /* in-word flag & max len */
if (!sentence || !*sentence) /* if NULL or empty, set word empty */
return (*word = 0);
for (;;) { /* loop continually */
if (isspace (*ep) || !*ep) { /* check whitespace & end of string */
if (in) { /* if in-word */
size_t len = ep - p; /* get length */
if (len > max) { /* if greater than max */
memcpy (word, p, len); /* copy to word */
word[len] = 0; /* nul-terminate word */
max = len; /* update max */
}
p = ep; /* update pointer to end-pointer */
in = 0; /* zero in-word flag */
}
if (!*ep) /* if end of word, bail */
break;
}
else { /* non-space character */
if (!in) { /* if not in-word */
p = ep; /* update pointer to end-pointer */
in = 1; /* set in-word flag */
}
}
ep++; /* advance end-pointer */
}
return max; /* return max length */
}
int main (void) {
char buf[MAXC], word[MAXWRD];
size_t len;
if (!fgets (buf, MAXC, stdin)) {
fputs ("error: user canceled input.\n", stderr);
return 1;
}
len = longest_word (buf, word);
printf ("longest: %s (%zu-chars)\n", word, len);
return 0;
}
Example Use/Output
Entered string has 2-character leading whitespace as well as 2-characters trailing whitespace:
$ ./bin/longest_word
1234 123 12 123456 1234 123456789 12345678 1 1234
longest: 123456789 (9-chars)
This isn't intended to be a substitute for Stephan's answer helping with the immediate issues in your implementation, rather this is an example providing you with an alternative way to think about approaching the problem. Generally the simpler you can keep any coding task, the less error prone it will be. Look it over and let me know if you have any further questions about the approach.
I have a pointer char * c = "I - need - to - do - this - break". I need to break it according to the '-' such that in each iteration I get an output as "I" then "I -need" then " I - need - to" and so on till the whole string.
Any help?
The simple way is to make c mutable and not a pointer to a String Literal. That way all you need to do is work down the string (either using a pointer or an index) and keep track of whether you are in a word or not in a word. When you hit a space (or hyphen if you get rid of the spaces), if you are in a word, save the current char, overwrite the current char in the array with '\0' to terminate the string at the current character and print it. Restore the current character in the array and repeat until you run out of characters, e.g.
#include <stdio.h>
int main (void) {
char c[] = "I - need - to - do - this - break", /* an array */
*p = c; /* pointer to current char */
int in = 0; /* flag for in/out of word */
while (*p) { /* loop over each char */
if (*p == ' ' || *p == '-') { /* if a space or hyphen */
if (in) { /* if in a word */
char current = *p; /* save current char */
*p = 0; /* nul-terminate array at current */
puts (c); /* print array */
*p = current; /* restore current in array */
in = 0; /* set flag out of word */
}
}
else { /* otherwise, not a space or hyphen */
in = 1; /* set flag in word */
}
p++; /* advance to next char */
}
if (in) /* if in word when last char reached */
puts (c); /* output full string */
}
Example Use/Output
$ ./bin/incremental
I
I - need
I - need - to
I - need - to - do
I - need - to - do - this
I - need - to - do - this - break
Using a Non-Mutable String Literal
If you must use a non-mutable String Literal, then the approach is largely the same. The only difference being you cannot nul-terminate the original string, so you are left using another pointer (or index) to output each character from the beginning until you reach the current using putchar (or getting the number of characters from p - c and then copying to a buffer to nul-terminate and output all at once). Simply looping until you reach the current and using putchar for output is about as easy as anything else, e.g.
#include <stdio.h>
int main (void) {
char *c = "I - need - to - do - this - break", /* string literal */
*p = c; /* pointer to current char */
int in = 0; /* flag for in/out of word */
while (*p) { /* loop over each char */
if (*p == ' ' || *p == '-') { /* if a space or hypen */
if (in) { /* if in a word */
char *wp = c; /* get pointer to start */
while (wp < p) /* loop until you reach current */
putchar (*wp++); /* output each char & increment */
putchar ('\n'); /* tidy up with newline */
in = 0; /* set flag out of word */
}
}
else { /* otherwise, not a space or hyphen */
in = 1; /* set flag in word */
}
p++; /* advance to next char */
}
if (in) /* if in word when last char reached */
puts (c); /* output full string */
}
(the output is the same)
Look things over and let me know if you have questions.
I've tried to run this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char a[1000];
void eliminatesp() {
char buff1[1000], buff2[1000];
LOOP: sscanf(a,"%s %s",buff1,buff2);
sprintf(a,"%s%s", buff1, buff2);
for(int i=0; i<strlen(a); ++i) {
if(a[i]==' ') goto LOOP;
}
}
void eliminateline() {
char buff1[1000]; char buff2[1000];
LOOP: sscanf(a,"%s\n\n%s",buff1,buff2);
sprintf(a,"%s\n%s", buff1, buff2);
for(int i=0; i<strlen(a)-1; ++i) {
if(a[i]=='\n'&&a[i+1]=='\n') goto LOOP;
}
}
int main() {sprintf(a,"%s\n\n%s", "hello world","this is my program, cris");
eliminatesp();
eliminateline();
printf("%s",a); return 0;
return 0;
}
but the output was:
hello world
world
How can I correct it? I was trying to remove spaces and empty lines.
Going with your idea of using sscanf and sprintf you can actually eliminate both spaces and newlines in a single function, as sscanf will ignore all whitespace (including newlines) when reading the input stream. So something like this should work:
void eliminate() {
char buff1[1000], buff2[1000], b[1000];
char* p = a, *q = b, *pq = b;
sprintf(q, "%s", p);
while (q != NULL && *q != '\0')
{
if (iswspace(*q))
{
sscanf(pq, "%s %s", buff1, buff2);
sprintf(p, "%s%s", buff1, buff2);
p += strlen(buff1);
pq = ++q;
}
q++;
}
}
Pedro, while the %s format specifier does stop conversion on the first encountered whitespace, it isn't the only drawback to attempting to parse with sscanf. In order to use sscanf you will also need to use the %n conversion specifier (the number of characters consumed during conversion to the point the %n appears) and save the value as an integer (say offset). Your next conversion will begin a a + offset until you have exhausted all words in 'a'. This can be a tedious process.
A better approach can simply be to loop over all characters in 'a' copying non-whitespace and single-delimiting whitespace to the new buffer as you go. (I often find it easier to copy the full string to a new buffer (say 'b') and then read from 'b' writing the new compressed string back to 'a').
As you work your way down the original string, you use simple if else logic to determine whether to store the current (or last) character or whether to just skip it and get the next. There are many ways to do this, no one way more right than the other as long as they are reasonably close in efficiency. Making use of the <ctype.h> functions like isspace() makes things easier.
Also, in your code, avoid the use of global variables. There is no reason you can't declare 'a' in main() and pass it as a parameter to your eliminate functions. If you need a constant in your code, like 1000, then #define a constant and avoid sprinkling magic numbers throughout your code.
Below is an example putting all those pieces together, and combining both your eliminatesp and eliminateline functions into a single eliminatespline function that does both trim whitespace and eliminate blank lines. This will handle blank lines and considers lines containing only whitespace characters as blank.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAXL 1000 /* if you need a constant, define one (or more) */
/** trim leading, compress included, and trim trailing whitespace.
* given non-empty string 'a', trim all leading whitespace, remove
* multiple included spaces and empty lines, and trim all trailing
* whitespace.
*/
void eliminatespline (char *a)
{
char b[MAXL] = "", /* buffer to hold copy of a */
*rp = b, /* read pointer to copy of a */
*wp = a, /* write pointer for a */
last = 0; /* last char before current */
if (!a || !*a) /* a NULL or empty - return */
return;
strcpy (b, a); /* copy a to b */
while (isspace (*rp)) /* skip leading whitespace */
rp++;
last = *rp++; /* fill last with 1st non-whitespace */
while (*rp) { /* loop over remaining chars in b */
/* last '\n' and current whitespace - advance read pointer */
if (last == '\n' && isspace(*rp)) {
rp++;
continue;
} /* last not current or last not space */
else if (last != *rp || !isspace (last))
*wp++ = last; /* write last, advance write pointer */
last = *rp++; /* update last, advance read pointer */
}
if (!isspace (last)) /* if last not space */
*wp++ = last; /* write last, advance write pointer */
*wp = 0; /* nul-terminate at write pointer */
}
int main() {
char a[] = " hello world\n \n\nthis is my program, cris ";
eliminatespline (a);
printf ("'%s'\n", a);
return 0;
}
note: the line being trimmed has both leading and trailing whitespace as well as embedded blank lines and lines containing only whitespace, e.g.
" hello world\n \n\nthis is my program, cris "
Example Use/Output
$ ./bin/elimspaceline
'hello world
this is my program, cris'
(note: the printf statements wraps the output in single-quotes to confirm all leading and trailing whitespace was eliminated.)
If you did want to use sscanf, you could essentially do the same thing with sscanf (using the %n specifier to report characters consumed) and a array of two-characters to treat the next character as a string, and do something like the following:
void eliminatespline (char *a)
{
char b[MAXL] = "", /* string to hold build w/whitespace removed */
word[MAXL] = "", /* string for each word */
c[2] = ""; /* string made of char after word */
int n = 0, /* number of chars consumed by sscanf */
offset = 0; /* offset from beginning of a */
size_t len; /* length of final string in b */
/* sscanf each word and char that follows, reporting consumed */
while (sscanf (a + offset, "%s%c%n", word, &c[0], &n) == 2) {
strcat (b, word); /* concatenate word */
strcat (b, c); /* concatenate next char */
offset += n; /* update offset with n */
}
len = strlen (b); /* get final length of b */
if (len && isspace(b[len - 1])) /* if last char is whitespace */
b[len - 1] = 0; /* remove last char */
strcpy (a, b); /* copy b to a */
}
Look things over, try both approaches and let me know if you have further questions.
I am trying to delete the blank space between a string and print out the first word with isalpha() function.
When I print out, only the first letter prints out. exempel "hello big panda" I get "hhhhh" but I want the hole word "hello" instead
int main()
{
char inputString[]={"hello big panda"};
int k=0;
int i=0;
do
{
inputString[i];
i++;
}
while (inputString[i]=isalpha(inputString[i]));
for(i=0; inputString[i] !='\0' ;i++)
{
for (k=i; inputString[k] != '\0'; k++)
{
inputString[k] =inputString[i];
}
}
printf("%s", inputString);
return 0;
}
done this:
int printfirstword(char sentence[])
{
int k=0;
int i=0;
while (isalpha(sentence[i])) //checking for the first blank space
{
i++;
}
sentence[i] = '\0';
printf("%s\n", sentence);
return 0;
}
int main()
{
char sentence[100];
int wordNumber;
char answer;
printfirstword("Hello there")
return0;
}
But I don't want to change the string that is passed to it
What you can simply do is use a while loop instead of your do-while. You can simply increment i until you find the index of first blank space. Then using the value of i you can insert '\0' in your string. Output it and you are done. :)
#include <stdio.h>
#include<ctype.h>
int main()
{
char inputString[]={"hello big panda"};
int k=0;
int i=0;
while (isalpha(inputString[i])) //checking for the first blank space
{
i++;
}
inputString[i] = '\0';
printf("%s", inputString);
return 0;
}
If you would like to keep the original string then you could simply make a new string say newStr and then
while (isalpha(inputString[i])) //checking for the first blank space
{ newStr[i]=inputString[i]; //copy first word into newStr
i++;
}
newStr[i] = '\0';
printf("%s", newStr);
Your function must do 3 things as it works through the sentence finding words. (1) always check for the end of the string to prevent an attempted read beyond the end of the sentence; and (2) locate and print the requested word at the index given; and (3) handle the condition where the user requests a word index greater than that available.
(you should always test the sentence you are passed in the function to make sure the pointer isn't a NULL pointer, and that the contents of the sentence is simply the '\0' character indicating an empty-string)
An easy way to do this (after you have tested the input string), is to set up a continual loop, that repeatedly read the characters of a word, checks if it is the word to print (if so it prints), and if not read and discard all the non-alpha characters before the next word, and then repeats.
Something simple like the following works. It takes the sentence (or updated position within the sentence) and the index for the word to print zero-indexed, e.g. (0, 1, 2, ...) and then loops a described above.
(note: you can change the zero-index scheme to a 1, 2, 3, ... word-number scheme by initializing n=1; instead of 0 -- but since everything in C is zero indexed, that is left to you)
#include <stdio.h>
#include <ctype.h>
int prnword (const char *s, int nwrd)
{
int n = 0; /* word counter */
char *p = s; /* pointer to s */
if (!s || !*s) { /* test s not NULL and not empty */
fprintf (stderr, "error: string NULL, empty or at end.\n");
return 0;
}
for (;;) { /* loop continually until exit condition reached */
while (*p && isalpha(*p)) { /* loop over chars in s */
if (n == nwrd) /* if requested index */
putchar (*p); /* print all chars */
p++; /* increment pointer */
}
while (*p && !isalpha(*p)) /* iterate find next alpha */
p++;
if (++n > nwrd) /* if past our word, break */
break;
if (!*p) /* if end reached, break */
break;
}
if (n <= nwrd) { /* check request exceeds avaialble words */
fprintf (stderr, "error: request word '%d' "
"exceeds available wprds indexes.\n", nwrd);
return 0;
}
putchar ('\n'); /* tidy up with new line */
return p - s; /* return number of chars to next alpha */
}
int main (void) {
char str[] = "hello big panda";
int nchars = 0;
/* example -- all words in order
* passing update string position
*/
nchars = prnword (str, 0);
nchars += prnword (str + nchars, 0);
nchars += prnword (str + nchars, 0);
putchar ('\n');
/* request exceed available zero-based word indexes */
nchars = 0;
nchars += prnword (str, 3);
putchar ('\n');
/* print 2nd word only */
nchars = 0;
nchars = prnword (str, 1);
putchar ('\n');
return 0;
}
Example Use/Output
Note the first block of calls to prnword print each of the words in the sentence, saving the number of characters returned by prior calls and using that to start the function reading the 1st character of the desired word, meaning you are always looking for word index 0.
The second call intentionally gives an index one past the last word to force handling the error.
And finally, the last call simply says "Go print word 2" (index 1) starting from scratch.
Example Use/Output
$ ./bin/words
hello
big
panda
error: request word '3' exceeds available wprds indexes.
big
Look things over and let me know if you have questions.