This is in Ansi C. I am given a string. I am supposed to create a method that returns an array of character pointers that point to the beginning of each word of said string. I am not allowed to use Malloc, but instead told that the maximum length of input will be 80.
Also, before anyone flames me for not searching the forum, I can't use strtok :(
char input[80] = "hello world, please tokenize this string"
and the output of the method should have 6 elements;
output[0] points to the "h",
output[1] points to the "w",
and so on.
How should I write the method?
Also, I need a similar method to handle input from a file with maximum of 110 lines.
Pseudocode:
boolean isInWord = false
while (*ptr != NUL character) {
if (!isInWord and isWordCharacter(*ptr)) {
isInWord = true
save ptr
} else if (isInWord and !isWordCharacter(*ptr)) {
isInWord = false
}
increment ptr
}
isWordCharacter checks whether the character is part of the word or not. Depending on your definition, it can be only alphabet character (recognize part-time as 2 words), or it may include - (recognize part-time as one word).
Because it's homework here's a part of what you might need:
char* readPtr = input;
char* wordPtr = input;
int wordCount = 0;
while (*readPtr++ != ' ');
/* Here we have a word from wordPtr to readPtr-1 */
output[wordCount++] = /* something... :) */
You'll need that in a loop, and must consider how to move onto the next word, and check for end of input.
Related
I have an array of charracters where I put in information using a gets().
char inname[30];
gets(inname);
How can I add another character to this array without knowing the length of the string in c? (the part that are actual letters and not like empty memmory spaces of romething)
note: my buffer is long enough for what I want to ask the user (a filename, Probebly not many people have names longer that 29 characters)
Note that gets is prone to buffer overflow and should be avoided.
Reading a line of input:
char inname[30];
sscanf("%.*s", sizeof(inname), inname);
int len = strlen(inname);
// Remove trailing newline
if (len > 0 && inname[len-1] == '\n') {
len--;
inname[len] = '\0'
}
Appending to the string:
char *string_to_append = ".";
if (len + strlen(string_to_append) + 1) <= sizeof(inname)) {
// There is enough room to append the string
strcat(inname, string_to_append);
}
Optional way to append a single character to the string:
if (len < sizeof(inname) - 2) {
// There is room to add another character
inname[len++] = '.'; // Add a '.' character to the string.
inname[len] = '\0'; // Don't forget to nul-terminate
}
As you have asked in comment, to determine the string length you can directly use
strlen(inname);
OR
you can loop through string in a for loop until \0 is found.
Now after getting the length of prvious string you can append new string as
strcat(&inname[prevLength],"NEW STRING");
EDIT:
To find the Null Char you can write a for loop like this
for(int i =0;inname[i] != 0;i++)
{
//do nothing
}
Now you can use i direcly to copy any character at the end of string like:
inname[i] = Youe Char;
After this increment i and again copy Null char to(0) it.
P.S.
Any String in C end with a Null character termination. ASCII null char '\0' is equivalent to 0 in decimal.
You know that the final character of a C string is '\0', e.g. the array:
char foo[10]={"Hello"};
is equivalent to this array:
['H'] ['e'] ['l'] ['l'] ['0'] ['\0']
Thus you can iterate on the array until you find the '\0' character, and then you can substitute it with the character you want.
Alternatively you can use the function strcat of string.h library
Short answer is you can't.
In c you must know the length of the string to append char's to it, in other languages the same applies but it happens magically, and without a doubt, internally the same must be done.
c strings are defined as sequences of bytes terminated by a special byte, the nul character which has ascii code 0 and is represented by the character '\0' in c.
You must find this value to append characters before it, and then move it after the appended character, to illustrate this suppose you have
char hello[10] = "Hello";
then you want to append a '!' after the 'o' so you can just do this
size_t length;
length = strlen(hello);
/* move the '\0' one position after it's current position */
hello[length + 1] = hello[length];
hello[length] = '!';
now the string is "Hello!".
Of course, you should take car of hello being large enough to hold one extra character, that is also not automatic in c, which is one of the things I love about working with it because it gives you maximum flexibility.
You can of course use some available functions to achieve this without worrying about moving the '\0' for example, with
strcat(hello, "!");
you will achieve the same.
Both strlen() and strcat() are defined in string.h header.
In one of my assignments, I was required to use linear search to find the last char of a string and set it to a pointer, it is just a simple string eg "blah blah blah". To do this I used
int length = strlen(string);
to find the length, then used a for loop
for (i=1;i<length;i++){
if (string[i]==0){;
end_pointer = &string[i-1];
}
Is there any difference between using linear search for 0 to set the pointer as opposed to using length:
end_pointer = &string[length-1];
I think what your professor is really looking for is:
int i = 0;
while( '\0' != string[i] ) i++;
for the search
Assign after the looping has completed for best efficiency:
char * end_pointer = &string[i - 1];
I think I need to explain how strings are stored in C.
Since strings can, in general, have arbitrary length, there needs to be a way to represent that length along with the content of the string. The two most trivial ways of representing the length are as follows.
explicitly keep track of length
use a special token to denote the end of string
The C language went with the second option. Specifically, '\0' is used to denote the end of the string. So if you have a char * p, then that is a pointer† that points to the first character; the second character in the string is p[1] == *(p+1), and so on.
So how do you get the length of the string? In the first method of representing strings (NOT the C way), it's already explicitly available. With C strings, you have to start at the beginning and count how many characters there are until the special token ('\0' in C). This is called a linear search for the end of string token.
strlen implements such a linear search, but it sounds like you are not supposed to use it. Regardless, strlen doesn't actually give you the pointer to the end of the string; you would have to compute it as
char *endPtr = string + strlen(string);
In this case, endPtr will actually point to the null-termination character, which is just past the end of the string. This is a common paradigm in C for specifying ranges: the start of the range (string in this case) is usually inclusive, and the end of the range (endPtr in this case) is usually exclusive.
†
char * could just be a pointer to a single char and not necessarily a string, but that doesn't concern us here.
The difference between using a linear search for '\0' to set the pointer as opposed to using length derived from strlen() is a slight potential efficiency change.
If one rolls their own code or uses the standard library function strlen(), it is still the same order of complexity O(n). If anything, srtrlen() has potential of being more efficient.
If the goal is to create you own code and point to the last char in a string (not the '\0'), handle "" as a special case, otherwise perform a simple loop;
char *LastCharPointer(char *string) {
if (*string == '\0') {
return NULL;
}
do {
string++;
} while (*string);
return string - 1;
}
If the goal is to point to the null chanracter '\0':
char *NullCharPointer(char *string) {
while (*string) string++;
return string;
}
I am assuming the code you pasted above is not the actual code you wrote, it would be :
for( i = 0; i < strlen( string ); i++ ) {
if( string[ i ] ){
end_pointer = &string[i - 1];
}
}
You can do this in two ways :
char * end_pointer = &string[ strlen( string ) - 1 ]
or
for( i = 0; string[ i ] ; i++ );
char * end_pointer = &string[ i - 1 ]
Effectively when you call strlen( ), it runs in linear time to calculate the length. Once you have the length you can index into the string directly or, you could yourself search for the terminating '\0' character. All this works assuming that your string is null-terminated.
EDIT : The second option had a missing ";".
I am a beginner learning C; so, please go easy on me. :)
I am trying to write a very simple program that takes each word of a string into a "Hi (input)!" sentence (it assumes you type in names). Also, I am using arrays because I need to practice them.
My problem is that, some garbage gets putten into the arrays somewhere, and it messes up the program. I tried to figure out the problem but to no avail; so, it is time to ask for expert help. Where have I made mistakes?
p.s.: It also has an infinite loop somewhere, but it is probably the result of the garbage that is put into the array.
#include <stdio.h>
#define MAX 500 //Maximum Array size.
int main(int argc, const char * argv[])
{
int stringArray [MAX];
int wordArray [MAX];
int counter = 0;
int wordCounter = 0;
printf("Please type in a list of names then hit ENTER:\n");
// Fill up the stringArray with user input.
stringArray[counter] = getchar();
while (stringArray[counter] != '\n') {
stringArray[++counter] = getchar();
}
// Main function.
counter = 0;
while (stringArray[wordCounter] != '\n') {
// Puts first word into temporary wordArray.
while ((stringArray[wordCounter] != ' ') && (stringArray[wordCounter] != '\n')) {
wordArray[counter++] = stringArray[wordCounter++];
}
wordArray[counter] = '\0';
//Prints out the content of wordArray.
counter = 0;
printf("Hi ");
while (wordArray[counter] != '\0') {
putchar(wordArray[counter]);
counter++;
}
printf("!\n");
//Clears temporary wordArray for new use.
for (counter = 0; counter == MAX; counter++) {
wordArray[counter] = '\0';
}
wordCounter++;
counter = 0;
}
return 0;
}
Solved it! I needed to add to following if sentence to the end when I incremented the wordCounter. :)
if (stringArray[wordCounter] != '\n') {
wordCounter++;
}
You are using int arrays to represent strings, probably because getchar() returns in int. However, strings are better represented as char arrays, since that's what they are, in C. The fact that getchar() returns an int is certainly confusing, it's because it needs to be able to return the special value EOF, which doesn't fit in a char. Therefore it uses int, which is a "larger" type (able to represent more different values). So, it can fit all the char values, and EOF.
With char arrays, you can use C's string functions directly:
char stringArray[MAX];
if(fgets(stringArray, sizeof stringArray, stdin) != NULL)
printf("You entered %s", stringArray);
Note that fscanf() will leave the end of line character(s) in the string, so you might want to strip them out. I suggest implementing an in-place function that trims off leading and trailing whitespace, it's a good exercise as well.
for (counter = 0; counter == MAX; counter++) {
wordArray[counter] = '\0';
}
You never enter into this loop.
user1799795,
For what it's worth (now that you've solved your problem) I took the liberty of showing you how I'd do this given the restriction "use arrays", and explaining a bit about why I'd do it that way... Just beware that while I am experienced programmer I'm no C guru... I've worked with guys who absolutely blew me into the C-weeds (pun intended).
#include <stdio.h>
#include <string.h>
#define LINE_SIZE 500
#define MAX_WORDS 50
#define WORD_SIZE 20
// Main function.
int main(int argc, const char * argv[])
{
int counter = 0;
// ----------------------------------
// Read a line of input from the user (ie stdin)
// ----------------------------------
char line[LINE_SIZE];
printf("Please type in a list of names then hit ENTER:\n");
while ( fgets(line, LINE_SIZE, stdin) == NULL )
fprintf(stderr, "You must enter something. Pretty please!");
// A note on that LINE_SIZE parameter to the fgets function:
// wherever possible it's a good idea to use the version of the standard
// library function that allows you specificy the maximum length of the
// string (or indeed any array) because that dramatically reduces the
// incedence "string overruns", which are a major source of bugs in c
// programmes.
// Also note that fgets includes the end-of-line character/sequence in
// the returned string, so you have to ensure there's room for it in the
// destination string, and remember to handle it in your string processing.
// -------------------------
// split the line into words
// -------------------------
// the current word
char word[WORD_SIZE];
int wordLength = 0;
// the list of words
char words[MAX_WORDS][WORD_SIZE]; // an array of upto 50 words of
// upto 20 characters each
int wordCount = 0; // the number of words in the array.
// The below loop syntax is a bit cyptic.
// The "char *c=line;" initialises the char-pointer "c" to the start of "line".
// The " *c;" is ultra-shorthand for: "is the-char-at-c not equal to zero".
// All strings in c end with a "null terminator" character, which has the
// integer value of zero, and is commonly expressed as '\0', 0, or NULL
// (a #defined macro). In the C language any integer may be evaluated as a
// boolean (true|false) expression, where 0 is false, and (pretty obviously)
// everything-else is true. So: If the character at the address-c is not
// zero (the null terminator) then go-round the loop again. Capiche?
// The "++c" moves the char-pointer to the next character in the line. I use
// the pre-increment "++c" in preference to the more common post-increment
// "c++" because it's a smidge more efficient.
//
// Note that this syntax is commonly used by "low level programmers" to loop
// through strings. There is an alternative which is less cryptic and is
// therefore preferred by most programmers, even though it's not quite as
// efficient. In this case the loop would be:
// int lineLength = strlen(line);
// for ( int i=0; i<lineLength; ++i)
// and then to get the current character
// char ch = line[i];
// We get the length of the line once, because the strlen function has to
// loop through the characters in the array looking for the null-terminator
// character at its end (guess what it's implementation looks like ;-)...
// which is inherently an "expensive" operation (totally dependant on the
// length of the string) so we atleast avoid repeating this operation.
//
// I know I might sound like I'm banging on about not-very-much but once you
// start dealing with "real word" magnitude datasets then such habits,
// formed early on, pay huge dividends in the ability to write performant
// code the first time round. Premature optimisation is evil, but my code
// doesn't hardly ever NEED optimising, because it was "fairly efficient"
// to start with. Yeah?
for ( char *c=line; *c; ++c ) { // foreach char in line.
char ch = *c; // "ch" is the character value-at the-char-pointer "c".
if ( ch==' ' // if this char is a space,
|| ch=='\n' // or we've reached the EOL char
) {
// 1. add the word to the end of the words list.
// note that we copy only wordLength characters, instead of
// relying on a null-terminator (which doesn't exist), as we
// would do if we called the more usual strcpy function instead.
strncpy(words[wordCount++], word, wordLength);
// 2. and "clear" the word buffer.
wordLength=0;
} else if (wordLength==WORD_SIZE-1) { // this word is too long
// so split this word into two words.
strncpy(words[wordCount++], word, wordLength);
wordLength=0;
word[wordLength++] = ch;
} else {
// otherwise: append this character to the end of the word.
word[wordLength++] = ch;
}
}
// -------------------------
// print out the words
// -------------------------
for ( int w=0; w<wordCount; ++w ) {
printf("Hi %s!\n", words[w]);
}
return 0;
}
In the real world one can't make such restrictive assumptions about the maximum-length of words, or how many there will be, and if such restrictions are given they're almost allways arbitrary and therefore proven wrong all too soon... so straight-off-the-bat for this problem, I'd be inclined to use a linked-list instead of the "words" array... wait till you get to "dynamic data structures"... You'll love em ;-)
Cheers. Keith.
PS: You're going pretty well... My advise is "just keep on truckin"... this gets a LOT easier with practice.
I've been trying to solve this for hours. Including research, but no go. Basically, we have to create function with :
int reverseSentence(char** sentence, char ** newsentance, int maxWords){
Where it returns the number of words in a sentence.
Here's more information:
You must maintain sentence capitalization, meaning if the sentence was capitalized, keep the
capital. If a word was capitalized, such as a name, retain the capital
The parameter sentence is a reference to a character array with the sentence to
reverse and should not be directly modified by your function. Each word is an array
entry in sentence.
The parameter newsentance is a reference to a character array to hold the new
sentence.
The parameter maxWords is the maximum size of the character array.
Return the number of words in the sentence
Do not copy the strings to temporary storage and replace them in the sentence. Move
the pointers.
ex: “To be, or not to be: that is the question.” becomes ”Question the is that be: to not or be, to.
Now, the problem I have is, currently my code works. But I can't seem to think of a way to capitalize something without getting an error. (Since we can't make a new storage).
What I have here is basically part of my code:
char ** fptr = sentence; //front sentence
char ** lptr = sentence; //last sentence
char ** nptr = newsentance;//front of new sentance
if( isupper(**fptr)){ //if the first letter of the first word is capital set flag
capflag = 1;
}
// find last word before null sentence and also calculate size
while(**(++lptr))
++size;
--lptr;
if(capflag){
*nptr = *lptr;
**nptr = toupper(**lptr); //error here
}
Also, I had to assume that the last "word" in sentence is "" or I can't find a way to calculate the size of the sentence. I hope someone can help me out.
I used this to test:
char ** test = malloc(1000);
*test = "To ";
*(test+1) = "be ";
*(test+2) = "or ";
*(test+3) = "not ";
*(test+4) = "to ";
*(test+5) = "be ";
*(test+6) = "";
char ** ztest = malloc(1000);
int rs = reverseSentence(test, ztest, 1000 );
Your code tries to modify a string literal, which is undefined behavior (you cannot do "ABC"[1] = 48; some implementations put string literals to readonly memory).
Try allocating space using malloc for each individual string and copy data from each string literal using memcpy.
The code below gives me the output:
To be or not to be; that is the question.
Number of words: 10
To be or not to be; that is the question.
question. the is that be; to not or be To
It only shuffles (copies of) pointers around; it does not attempt to modify the capitalization of words. If was going to do that, it would have to work harder, allocating copies of the leading word in the original sentence (but how would you tell whether that was a name or not?) and the last word. Suppose the sentence was "London hosted the 2012 Olympics"; when reversed, you don't want to case-convert the L of London because it is a name that happens to start the sentence (and you don't need to case-convert the O of Olympics either).
You could legitimately decide that the full stop (period) at the end of the sentence should not be included in the data (so my "question." should be replaced by "question"), and then have the sentence printing code add the full stop at the end; it is a trivial modification.
#include <stdio.h>
int reverse_sentence(char **fwd_order, char **rev_order, int max_words)
{
char **end = fwd_order;
int num_words = 0;
for (end = fwd_order; *end != 0 && num_words < max_words; end++)
num_words++;
for (int i = 0; i < num_words; i++)
*rev_order++ = *--end;
*rev_order = 0;
return num_words;
}
static void print_sentence(char **words)
{
const char *pad = "";
while (*words)
{
printf("%s%s", pad, *words++);
pad = " ";
}
putchar('\n');
}
int main(void)
{
char *sentence[] =
{ "To", "be", "or", "not", "to", "be;", "that", "is", "the", "question.", 0 };
enum { NUM_WORDS = sizeof(sentence) / sizeof(sentence[0]) };
char *reversed[NUM_WORDS];
int num_words;
print_sentence(sentence);
num_words = reverse_sentence(sentence, reversed, NUM_WORDS);
printf("Number of words: %d\n", num_words);
print_sentence(sentence);
print_sentence(reversed);
return(0);
}
ex: “To be, or not to be: that is the question.” becomes ”Question the is that be: to not or be, to.
Is this part of the specification or is it your interpretation? If the latter, you should verify whether your interpretation is correct or whether you are to simply reverse the order of the words, which is easily achievable. Do you even know if you are required to handle punctuation? Your code doesn't, and your test doesn't match your example.
First rule of software engineering: nail down the requirements.
Consider a char array like this:
43 234 32 32
I want the last value that is 32 in integer form.
The string size/length is not known. In the above example there are 4 numbers, but the size will vary.
How can this be done?
i have copied these value from the file onto char array.now i want the last number in integer variable
When you were copying,add a counter of # of characters copied. Then do this
int count = 0;
char c;
while(c = readCharFromFile()) {
array[count++] = c;
}
int last = array[count - 1];
There are many ways to solve this.
Convert every token (space delimited string) into a number and when the tokens run out return the last value converted.
Scan the line for tokens until you get to the end and then convert the last token into a number.
Start at the end of the line. Skip spaces and store digits until the first space is encountered and then convert the result to a number.
Split the string into an array of strings and convert the last one into a number.
I could go on and on but you get the idea I hope.
int getLastInt(char *data)
{
size_t i = strlen(data);
if(!i--) return -1; // failure
for(;i;--i)
{
if(data[i] == ' ')
{
return atoi(&data[i+1]);
}
}
return -1; // failure
}
Should work as long as the data has a space + actual text.
You could also skip the strlen and just loop forward, which could be faster depending on your system's strlen.
If there is no trailing whitespace on the line:
int last_int(const char *s)
{
const char *ptr = strrchr(s, ' ');
if (ptr == NULL) {
ptr = s;
} else {
ptr++;
}
return atoi(ptr);
}
If there can be trailing whitespace, then you'll need to do something like what ProdigySim suggested, but with more states, to walk backwards past the trailing whitespace (if any), then past the number, then call atoi(). No matter what you do, you'll need to watch out for boundary conditions and edge cases and decide how you want to handle them.
I guess you want to use a combination of strtok_r and atoi