I'm trying to write code to append two strings without the function strcat, but it doesn't work. It only works when the inputs are a single char.
Here's the code:
#include <stdio.h>
#include <string.h>
/*
Return the result of appending the characters in s2 to s1.
Assumption: enough space has been allocated for s1 to store the extra
characters.
*/
char* append (char s1[], char s2[]) {
int s1len = strlen (s1);
int s2len = strlen (s2);
int k;
for (k=0; k<s2len; k++) {
s1[k+s1len] = s2[k];
}
return s1;
}
int main ( ) {
char str1[10];
char str2[10];
while (1) {
printf ("str1 = ");
if (!gets(str1)) {
return 0;
};
printf ("str2 = ");
if (!gets(str2)) {
return 0;
};
printf ("The result of appending str2 to str1 is %s.\n",
append (str1, str2));
}
return 0;
}
How can I fix it?
You have some errors in your code:
Do not use gets. This function is dangerous because it doesn't take the
size of the buffer into account. Use fgets instead.
Your append function does not write the '\0'-terminating byte. It should
be
char* append (char s1[], char s2[]) {
int s1len = strlen (s1);
int s2len = strlen (s2);
int k;
for (k=0; k<s2len; k++) {
s1[k+s1len] = s2[k];
}
s1[k+s1len] = 0; // writing the 0-terminating byte
return s1;
}
str1 may be to short for holding both strings. If str2 contains "Hello"
and str2 contains "World!", you are going to overflow the buffer. Make the
buffer larger.
If you writing your own strcat, I would pass the size of the destination
buffer as well, so that you don't overflow the buffers:
char *mystrcat(char *t1, const char *t2, size_t maxsize)
{
if(t1 == NULL || t2 == NULL)
return NULL;
size_t s1 = strlen(t1);
size_t s2 = strlen(t2);
size_t i;
for(i = 0; i < s2 && (s1 + i) < maxsize - 1 ; ++i)
t1[i + s1] = t2[i];
t1[i + s1] = 0; // terminating the
return t1;
}
int main(void)
{
char str1[30] = "Hello ";
char str2[30] = "World!";
printf("mystrcat(\"%s\", \"%s\") = %s\n", str1, str2,
mystrcat(str1, str2, sizeof str1));
char str3[100] = "This is a long sentence";
printf("mystrcat(\"%s\", \"%s\") = %s\n", str1, str3,
mystrcat(str1, str3, sizeof str1));
char line[100];
printf("Enter some text: ");
fflush(stdout);
fgets(line, sizeof line, stdin);
line[strcspn(line, "\n")] = 0; // removing possible newline
strcpy(str3, "User input was: ");
printf("mystrcat: %s\n", mystrcat(str3, line, sizeof str3));
return 0;
}
That would return
mystrcat("Hello World!", "World!") = Hello World!
mystrcat("Hello World!This is a long se", "This is a long sentence") = Hello World!This is a long se
Enter some text: ABC DEF user input is great
mystrcat: User input was: ABC DEF user input is great
Your resulting string is not properly terminated.
Strings in C are always terminated with a NUL (0) character.
gets is unsafe, use fgets instead.
Get in the habit to check buffer sizes.
To give you an idea, here a minimalistic implementation using fgets + buffer size checks:
#include <stdio.h> // fprintf, fgets
#include <string.h> // strlen
const char *concatenate(char *dst, size_t sz, const char *s1, const char *s2) {
size_t l1 = strlen(s1);
size_t l2 = strlen(s2);
// Check for overflow
if ((l1 + l2 + 1) > sz) {
return NULL;
}
// Copy first string
for (size_t i = 0; i < l1; ++i) {
dst[i] = s1[i];
}
// Copy second string
for (size_t i = 0; i < l2; ++i) {
dst[l1 + i] = s2[i];
}
// Add NUL terminator
dst[l1 + l2 + 1] = 0;
return dst;
}
int main() {
// Allocate two strings (9 chars max.)
char first_string[10];
char second_string[10];
char concatenated_string[20];
// Read first string from stdin
fprintf(stdout, "str1 = ");
// !!! fgets return value check omitted for simplicity.
fgets(first_string, sizeof(first_string), stdin);
// Read second string from stdin
fprintf(stdout, "str2 = ");
// !!! fgets return value check omitted for simplicity.
fgets(second_string, sizeof(second_string), stdin);
const char *tmp = concatenate(concatenated_string, sizeof(concatenated_string), first_string, second_string);
if (!tmp) {
fprintf(stderr, "would overflow\n");
} else {
fprintf(stdout, "concatenated: %s\n", concatenated_string);
}
return 0;
}
Related
Required use of the function that returns the length of the string.
Write a function that receives two character chains (n1, n2). The function of the function is to check if the string n2 is the subscription of the string n1. The function returns the index of the first occurrence of the string n2 in the string n1 (if n2 is the string n1) or -1 (if n2 is not the string n1). assumption: the inscription n2 is shorter than the inscription n1.
Example: inscription n1: "Computer" inscription n2: "er" Function returns: 6
i did it and it work
#include <stdio.h>
#define LIMIT 50
char * string_in(char *string, char *substring);
char * get(char *string, int n);
int main(void)
{
// test string_in()
char string[LIMIT];
char substring[LIMIT];
char *substr_loc;
printf("Enter a string: ");
get(string, LIMIT);
while (string[0] != '\0')
{
printf("Enter a substring to look for: ");
get(substring, LIMIT);
substr_loc = string_in(string, substring);
if (substr_loc == NULL)
printf("%s not in %s\n", substring, string);
else
printf("%s found in %s at index %lu\n",
substring, string, substr_loc - string);
printf("Enter a string (empty line to quit): ");
get(string, LIMIT);
}
puts("Bye");
return 0;
}
char * string_in(char *string, char *substring)
{
// checks if substring is in string
// returns pointer to first location of substring
// in string or NULL if substring not in string
int i;
while (*string != '\0')
{
i = 0;
// check for substring at current location
while (*(string + i) == *(substring + i))
{
i++;
// if next char in substring is null, then match
// is found. return current location
if (*(substring + i) == '\0')
return string;
}
string++;
}
// no match
return NULL;
}
char * get(char *string, int n)
{
// wrapper for fgets that replaces first newline with null
char *return_value = fgets(string, n, stdin);
while (*string != '\0')
{
if (*string == '\n')
{
*string = '\0';
break;
}
string++;
}
return return_value;
}
the next step is
Write a part of the program that will replace all occurrences of the n2 string in the string n1 with the string (the character '*'). Use the function from a task point. Please tell me how to write this function
Example: n1: "Spectacle" n2: "c" string n1 after change. "Spe*ta*le"
void function(char * get, char * string_in)
int i = 0;
for ( i = 0; get[i]=!'\0';i++){
if (get[i] == string_in[o]
get[i] = '*';}
dont work;<
it is a bit more complicated if you the string which replaces another string is longer. Here you have simple functions.
size_t strstrIndex(const char *heap, const char *needle) // returns SIZE_MAX if not found
{
char *result = strstr(heap,needle);
return result ? result - heap : SIZE_MAX;
}
char *replace(const char *heap, const char *needle, const char *rep)
{
size_t pos = 0, nocc = 0;
size_t len = strlen(heap), nlen = strlen(needle), rlen = strlen(rep);
char *string;
char *wstr = (char *)heap;
while((pos = strstrIndex(wstr, needle)) != SIZE_MAX)
{
nocc++;
wstr += pos + nlen;
}
string = calloc(1, len + ((rlen > nlen) ? (rlen - nlen) * nocc : 0) + 1);
if(string)
{
wstr = string;
while((pos = strstrIndex(heap, needle)) != SIZE_MAX)
{
strncpy(wstr, heap, pos);
heap += pos + nlen;
wstr += pos;
strcpy(wstr, rep);
wstr += rlen;
}
if(*heap)
{
strcpy(wstr, heap);
}
}
return string;
}
int main()
{
char *heap = "Spectaclec";
printf("%s\n", replace(heap, "c", "*"));
printf("%s\n", replace(heap, "c", "*****"));
printf("%s\n", replace("ccSpecctaccleccX", "cc", "*****"));
}
This task is easy if you use the functions that comes with the C library:
void ReplaceString(char *pTarget, const char *pPattern)
{
char *p;
size_t PatternLength = strlen(pPattern);
// for all occurances of the pattern..
while (p = strstr(pTarget, pPattern))
{
// The function strstr found an occurance of the pattern.
// So it must be sufficient space in the target starting at the pointer p..
// replace the characters in the target
memset(p, '*', PatternLength);
}
}
If you should avoid functions for some academic purposes, you can implement your own versions of strlen, strstr, and memset. Your example shows a function string_in that looks like such version of `strstr.
This question already has answers here:
What is a debugger and how can it help me diagnose problems?
(2 answers)
Closed 4 years ago.
I tried to develop a function which take a string reverse letters and return pointer to string.
char *reverseStr(char s[])
{
printf("Initial string is: %s\n", s);
int cCounter = 0;
char *result = malloc(20);
while(*s != '\0')
{
cCounter++;
s++;
}
printf("String contains %d symbols\n", cCounter);
int begin = cCounter;
for(; cCounter >= 0; cCounter--)
{
result[begin - cCounter] = *s;
s--;
}
result[13] = '\0';
return result;
}
in main function I invoke the function and tried to print the result in this way:
int main()
{
char testStr[] = "Hello world!";
char *pTestStr;
puts("----------------------------------");
puts("Input a string:");
pTestStr = reverseStr(testStr);
printf("%s\n", pTestStr);
free(pTestStr);
return 0;
}
but the result is unexpected, there is no reverse string.
What is my fault?
There are multiple mistakes in the shared code, primarily -
s++; move the pointer till '\0'. It should be brought back 1 unit to
point to actual string by putting s--. Other wise the copied one will start with '\0' that will make it empty string.
Magic numbers 20 and 13. where in malloc() 1 + length of s should be
sufficient instead or 20. For 13 just move a unit ahead and put '\0'
However, using string.h library functions() this can be super easy. But I think you are doing it for learning purpose.
Therefore, Corrected code without using string.h lib function() should look like this:
char *reverseStr(char s[])
{
printf("Initial string is: %s\n", s);
int cCounter = 0;
while(*s != '\0')
{
cCounter++;
s++;
}
s--; //move pointer back to point actual string's last charecter
printf("String contains %d symbols\n", cCounter);
char *result = (char *) malloc(sizeof(char) * ( cCounter + 1 ));
if( result == NULL ) /*Check for failure. */
{
puts( "Can't allocate memory!" );
exit( 0 );
}
char *tempResult = result;
for (int begin = 0; begin < cCounter; begin++)
{
*tempResult = *s;
s--; tempResult++;
}
*tempResult = '\0';
//result[cCounter+1] = '\0';
return result;
}
Calling from main
int main()
{
char testStr[] = "Hello world!";
char *pTestStr;
puts("----------------------------------");
puts("Input a string:");
pTestStr = reverseStr(testStr);
printf("%s\n", pTestStr);
free(pTestStr);
}
Output
----------------------------------
Input a string:
Initial string is: Hello world!
String contains 12 symbols
!dlrow olleH
As per WhozCraig suggestion just by using pointer arithmetic only -
char *reverseStr(const char s[])
{
const char *end = s;
while (*end)
++end;
char *result = malloc((end - s) + 1), *beg = result;
if (result == NULL)
{
perror("Failed to allocate string buffer");
exit(EXIT_FAILURE);
}
while (end != s)
*beg++ = *--end;
*beg = 0;
return result;
}
Your code can be simplified using a string library function found in string.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *reverseStr(char s[])
{
printf("Initial string is: %s\n", s);
int cCounter = strlen(s);
char *result = malloc(cCounter + 1);
printf("String contains %d symbols\n", cCounter);
int begin = cCounter;
for(; cCounter > 0; cCounter--)
{
result[begin - cCounter] = s[cCounter - 1];
}
result[begin] = '\0';
return result;
}
int main()
{
char testStr[] = "Hello world!";
char *pTestStr;
puts("----------------------------------");
puts("Input a string:");
pTestStr = reverseStr(testStr);
printf("%s\n", pTestStr);
free(pTestStr);
return 0;
}
Output:
----------------------------------
Input a string:
Initial string is: Hello world!
String contains 12 symbols
!dlrow olleH
I want to write a program in C that displays each word of a whole sentence (taken as input) at a seperate line. This is what I have done so far:
void manipulate(char *buffer);
int get_words(char *buffer);
int main(){
char buff[100];
printf("sizeof %d\nstrlen %d\n", sizeof(buff), strlen(buff)); // Debugging reasons
bzero(buff, sizeof(buff));
printf("Give me the text:\n");
fgets(buff, sizeof(buff), stdin);
manipulate(buff);
return 0;
}
int get_words(char *buffer){ // Function that gets the word count, by counting the spaces.
int count;
int wordcount = 0;
char ch;
for (count = 0; count < strlen(buffer); count ++){
ch = buffer[count];
if((isblank(ch)) || (buffer[count] == '\0')){ // if the character is blank, or null byte add 1 to the wordcounter
wordcount += 1;
}
}
printf("%d\n\n", wordcount);
return wordcount;
}
void manipulate(char *buffer){
int words = get_words(buffer);
char *newbuff[words];
char *ptr;
int count = 0;
int count2 = 0;
char ch = '\n';
ptr = buffer;
bzero(newbuff, sizeof(newbuff));
for (count = 0; count < 100; count ++){
ch = buffer[count];
if (isblank(ch) || buffer[count] == '\0'){
buffer[count] = '\0';
if((newbuff[count2] = (char *)malloc(strlen(buffer))) == NULL) {
printf("MALLOC ERROR!\n");
exit(-1);
}
strcpy(newbuff[count2], ptr);
printf("\n%s\n",newbuff[count2]);
ptr = &buffer[count + 1];
count2 ++;
}
}
}
Although the output is what I want, I have really many black spaces after the final word displayed, and the malloc() returns NULL so the MALLOC ERROR! is displayed in the end.
I can understand that there is a mistake at my malloc() implementation, but I do not know what it is.
Is there another more elegant or generally better way to do it?
http://www.cplusplus.com/reference/clibrary/cstring/strtok/
Take a look at this, and use whitespace characters as the delimiter. If you need more hints let me know.
From the website:
char * strtok ( char * str, const char * delimiters );
On a first call, the function expects a C string as argument for str, whose first character is used as the starting location to scan for tokens. In subsequent calls, the function expects a null pointer and uses the position right after the end of last token as the new starting location for scanning.
Once the terminating null character of str is found in a call to strtok, all subsequent calls to this function (with a null pointer as the first argument) return a null pointer.
Parameters
str
C string to truncate.
Notice that this string is modified by being broken into smaller strings (tokens).
Alternativelly [sic], a null pointer may be specified, in which case the function continues scanning where a previous successful call to the function ended.
delimiters
C string containing the delimiter characters.
These may vary from one call to another.
Return Value
A pointer to the last token found in string.
A null pointer is returned if there are no tokens left to retrieve.
Example
/* strtok example */
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] ="- This, a sample string.";
char * pch;
printf ("Splitting string \"%s\" into tokens:\n",str);
pch = strtok (str," ,.-");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, " ,.-");
}
return 0;
}
For the fun of it here's an implementation based on the callback approach:
const char* find(const char* s,
const char* e,
int (*pred)(char))
{
while( s != e && !pred(*s) ) ++s;
return s;
}
void split_on_ws(const char* s,
const char* e,
void (*callback)(const char*, const char*))
{
const char* p = s;
while( s != e ) {
s = find(s, e, isspace);
callback(p, s);
p = s = find(s, e, isnotspace);
}
}
void handle_word(const char* s, const char* e)
{
// handle the word that starts at s and ends at e
}
int main()
{
split_on_ws(some_str, some_str + strlen(some_str), handle_word);
}
malloc(0) may (optionally) return NULL, depending on the implementation. Do you realize why you may be calling malloc(0)? Or more precisely, do you see where you are reading and writing beyond the size of your arrays?
Consider using strtok_r, as others have suggested, or something like:
void printWords(const char *string) {
// Make a local copy of the string that we can manipulate.
char * const copy = strdup(string);
char *space = copy;
// Find the next space in the string, and replace it with a newline.
while (space = strchr(space,' ')) *space = '\n';
// There are no more spaces in the string; print out our modified copy.
printf("%s\n", copy);
// Free our local copy
free(copy);
}
Something going wrong is get_words() always returning one less than the actual word count, so eventually you attempt to:
char *newbuff[words]; /* Words is one less than the actual number,
so this is declared to be too small. */
newbuff[count2] = (char *)malloc(strlen(buffer))
count2, eventually, is always one more than the number of elements you've declared for newbuff[]. Why malloc() isn't returning a valid ptr, though, I don't know.
You should be malloc'ing strlen(ptr), not strlen(buf). Also, your count2 should be limited to the number of words. When you get to the end of your string, you continue going over the zeros in your buffer and adding zero size strings to your array.
Just as an idea of a different style of string manipulation in C, here's an example which does not modify the source string, and does not use malloc. To find spaces I use the libc function strpbrk.
int print_words(const char *string, FILE *f)
{
static const char space_characters[] = " \t";
const char *next_space;
// Find the next space in the string
//
while ((next_space = strpbrk(string, space_characters)))
{
const char *p;
// If there are non-space characters between what we found
// and what we started from, print them.
//
if (next_space != string)
{
for (p=string; p<next_space; p++)
{
if(fputc(*p, f) == EOF)
{
return -1;
}
}
// Print a newline
//
if (fputc('\n', f) == EOF)
{
return -1;
}
}
// Advance next_space until we hit a non-space character
//
while (*next_space && strchr(space_characters, *next_space))
{
next_space++;
}
// Advance the string
//
string = next_space;
}
// Handle the case where there are no spaces left in the string
//
if (*string)
{
if (fprintf(f, "%s\n", string) < 0)
{
return -1;
}
}
return 0;
}
you can scan the char array looking for the token if you found it just print new line else print the char.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *s;
s = malloc(1024 * sizeof(char));
scanf("%[^\n]", s);
s = realloc(s, strlen(s) + 1);
int len = strlen(s);
char delim =' ';
for(int i = 0; i < len; i++) {
if(s[i] == delim) {
printf("\n");
}
else {
printf("%c", s[i]);
}
}
free(s);
return 0;
}
char arr[50];
gets(arr);
int c=0,i,l;
l=strlen(arr);
for(i=0;i<l;i++){
if(arr[i]==32){
printf("\n");
}
else
printf("%c",arr[i]);
}
Here is the demo code I am using to construct string from char arrays, Is there any better way to construct String *RV200# *FV200# ??
int main()
{
char String4H1[10] = "*FV";
char String4H3[10] = "*RV";
char String4H2[10] = "#";
char data1[10];
char data2[10];
snprintf(data1,4, "%03d", 200); //Convert integer to string function
snprintf(data2,4, "%03d", 200); //Convert integer to string function
ConvertToString(String4H1,data1, 3); //*FV200
ConvertToString(String4H3,data2, 3); //*RV200
ConvertToString(String4H1,String4H2,6); //*FV200#
ConvertToString(String4H3,String4H2,6); //*RV200#
//Display String4H1 And String 4H3
}
void ConvertToString(char subject[], const char insert[], int pos)
{
char buf[100] = {};
strncpy(buf, subject, pos); // copy at most first pos characters
int len = strlen(buf);
strcpy(buf+len, insert); // copy all of insert[] at the end
len += strlen(insert); // increase the length by length of insert[]
strcpy(buf+len, subject+pos); // copy the rest
strcpy(subject, buf); // copy it back to subject
// deallocate buf[] here, if used malloc()
}
The number 200 is not known at the start of the program, it is fetched from memory using the IDE function to get value from particular memory address.
like this :-
unsigned short BUF = GetWord(#FrontVIB#,0);
unsigned short BUF1 = GetWord(#RearVIB#,0);
//BUF and BUF1 stores the value of address #FrontVIB# and #RearVIB# respectively
**structure** :-
unsigned short GetWord( #Address Alias#, Address Offset );
That's a simple example. Probably I'll be down-voted :)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
bool concatenateString(char **dest, size_t *size, char *stringToAdd)
{
bool retVal = true;
char *dest_old = *dest;
*size += strlen(stringToAdd);
if (*dest == NULL)
{
*size += 1; // to add null terminator of string
*dest = calloc(1, size);
}
else
{
*dest = realloc(*dest, size);
}
if (dest == NULL)
{
free(dest_old);
retVal = false;
}
else
{
strcat(*dest, stringToAdd);
}
return retVal;
}
int main()
{
char newString[32] = {0};
int number;
size_t size = 0;
char *data1 = NULL;
printf("Insert a string:");
scanf(" %s", newString);
if (concatenateString(&data1, &size, newString))
{
printf("Insert a number:");
scanf(" %d", &number);
sprintf(newString, "%03d", number);
if (concatenateString(&data1, &size, newString) )
{
printf("Insert a string:");
scanf(" %s", newString);
if (concatenateString(&data1, &size, newString))
printf("%s\n", data1);
}
}
free(data1);
}
Without using dynamic allocation
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
bool concatenateString(char *dest, size_t size_of_dest, char *stringToAdd)
{
bool retVal = true;
size_t new_size = strlen(dest) + strlen(stringToAdd);
if (new_size < size_of_dest)
{
strcat(dest, stringToAdd);
}
else
{
retVal = false;
}
return retVal;
}
int main()
{
char result[128] = {0};
char newString[32] = {0};
int number;
printf("Insert a string:");
scanf(" %s", newString);
printf("%s\n", newString);
if (concatenateString(result, sizeof(result), newString))
{
printf("Insert a number:");
scanf(" %d", &number);
sprintf(newString, "%03d", number);
if (concatenateString(result, sizeof(result), newString) )
{
printf("Insert a string:");
scanf(" %s", newString);
if (concatenateString(result, sizeof(result), newString))
printf("%s\n", result);
}
}
}
INPUT
Insert a string: *RV
Insert a number: 200
Insert a string: #
OUTPUT
*RV200#
A number of issues, I am only tackling ConvertToString()
Although some attempts made at coping with string buffer issues, too many holes exist in OP's code. Consider the following.
void ConvertToString(char subject[], const char insert[], int pos) {
char buf[100] = {};
strncpy(buf, subject, pos); // copy at most first pos characters
int len = strlen(buf);
...
What is the impact of pos == 100?
strlen(buf) may attempt to find the length of a character array with no null character --> UB.
What is the impact of pos > 100?
strncpy() attempts to write data outside the bonds of buf.
Pedantic: What is the impact of pos < 0?
strncpy() attempts to write data outside the bonds of buf as pos is converted into an excessive large unsigned number.
Concerning strcpy(buf+len, subject+pos);
What is the impact if pos exceeds strlen(subject)
UB as code attempts to read outside subject.
Re-write attempt. The key elements: include the size available for the expanded subject is passed in and determine string lengths. Then test for acceptability. After all that, shift the end of subject to make room for insert.
void ConvertToString(char subject[], size_t subject_size, const char *insert,
size_t pos) {
size_t insert_length = strlen(insert);
size_t subject_length = strlen(subject);
// Insure pos does not exceed subject_length,
// this critical part missing in OP code
if (pos > subject_length) {
pos = subject_length;
}
// Insure we have enough space
size_t buf_size = subject_length + insert_length + 1;
if (buf_size > subject_size) {
Handle_Insufficent_subject_size();
return;
}
// Move end portion of `subject` over to the right `insert_length` places.
memmove(subject + pos + insert_length, subject + pos, subject_length - pos + 1);
memcpy(subject + pos, insert, insert_length); // copy insert
}
I want to write a program in C that displays each word of a whole sentence (taken as input) at a seperate line. This is what I have done so far:
void manipulate(char *buffer);
int get_words(char *buffer);
int main(){
char buff[100];
printf("sizeof %d\nstrlen %d\n", sizeof(buff), strlen(buff)); // Debugging reasons
bzero(buff, sizeof(buff));
printf("Give me the text:\n");
fgets(buff, sizeof(buff), stdin);
manipulate(buff);
return 0;
}
int get_words(char *buffer){ // Function that gets the word count, by counting the spaces.
int count;
int wordcount = 0;
char ch;
for (count = 0; count < strlen(buffer); count ++){
ch = buffer[count];
if((isblank(ch)) || (buffer[count] == '\0')){ // if the character is blank, or null byte add 1 to the wordcounter
wordcount += 1;
}
}
printf("%d\n\n", wordcount);
return wordcount;
}
void manipulate(char *buffer){
int words = get_words(buffer);
char *newbuff[words];
char *ptr;
int count = 0;
int count2 = 0;
char ch = '\n';
ptr = buffer;
bzero(newbuff, sizeof(newbuff));
for (count = 0; count < 100; count ++){
ch = buffer[count];
if (isblank(ch) || buffer[count] == '\0'){
buffer[count] = '\0';
if((newbuff[count2] = (char *)malloc(strlen(buffer))) == NULL) {
printf("MALLOC ERROR!\n");
exit(-1);
}
strcpy(newbuff[count2], ptr);
printf("\n%s\n",newbuff[count2]);
ptr = &buffer[count + 1];
count2 ++;
}
}
}
Although the output is what I want, I have really many black spaces after the final word displayed, and the malloc() returns NULL so the MALLOC ERROR! is displayed in the end.
I can understand that there is a mistake at my malloc() implementation, but I do not know what it is.
Is there another more elegant or generally better way to do it?
http://www.cplusplus.com/reference/clibrary/cstring/strtok/
Take a look at this, and use whitespace characters as the delimiter. If you need more hints let me know.
From the website:
char * strtok ( char * str, const char * delimiters );
On a first call, the function expects a C string as argument for str, whose first character is used as the starting location to scan for tokens. In subsequent calls, the function expects a null pointer and uses the position right after the end of last token as the new starting location for scanning.
Once the terminating null character of str is found in a call to strtok, all subsequent calls to this function (with a null pointer as the first argument) return a null pointer.
Parameters
str
C string to truncate.
Notice that this string is modified by being broken into smaller strings (tokens).
Alternativelly [sic], a null pointer may be specified, in which case the function continues scanning where a previous successful call to the function ended.
delimiters
C string containing the delimiter characters.
These may vary from one call to another.
Return Value
A pointer to the last token found in string.
A null pointer is returned if there are no tokens left to retrieve.
Example
/* strtok example */
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] ="- This, a sample string.";
char * pch;
printf ("Splitting string \"%s\" into tokens:\n",str);
pch = strtok (str," ,.-");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, " ,.-");
}
return 0;
}
For the fun of it here's an implementation based on the callback approach:
const char* find(const char* s,
const char* e,
int (*pred)(char))
{
while( s != e && !pred(*s) ) ++s;
return s;
}
void split_on_ws(const char* s,
const char* e,
void (*callback)(const char*, const char*))
{
const char* p = s;
while( s != e ) {
s = find(s, e, isspace);
callback(p, s);
p = s = find(s, e, isnotspace);
}
}
void handle_word(const char* s, const char* e)
{
// handle the word that starts at s and ends at e
}
int main()
{
split_on_ws(some_str, some_str + strlen(some_str), handle_word);
}
malloc(0) may (optionally) return NULL, depending on the implementation. Do you realize why you may be calling malloc(0)? Or more precisely, do you see where you are reading and writing beyond the size of your arrays?
Consider using strtok_r, as others have suggested, or something like:
void printWords(const char *string) {
// Make a local copy of the string that we can manipulate.
char * const copy = strdup(string);
char *space = copy;
// Find the next space in the string, and replace it with a newline.
while (space = strchr(space,' ')) *space = '\n';
// There are no more spaces in the string; print out our modified copy.
printf("%s\n", copy);
// Free our local copy
free(copy);
}
Something going wrong is get_words() always returning one less than the actual word count, so eventually you attempt to:
char *newbuff[words]; /* Words is one less than the actual number,
so this is declared to be too small. */
newbuff[count2] = (char *)malloc(strlen(buffer))
count2, eventually, is always one more than the number of elements you've declared for newbuff[]. Why malloc() isn't returning a valid ptr, though, I don't know.
You should be malloc'ing strlen(ptr), not strlen(buf). Also, your count2 should be limited to the number of words. When you get to the end of your string, you continue going over the zeros in your buffer and adding zero size strings to your array.
Just as an idea of a different style of string manipulation in C, here's an example which does not modify the source string, and does not use malloc. To find spaces I use the libc function strpbrk.
int print_words(const char *string, FILE *f)
{
static const char space_characters[] = " \t";
const char *next_space;
// Find the next space in the string
//
while ((next_space = strpbrk(string, space_characters)))
{
const char *p;
// If there are non-space characters between what we found
// and what we started from, print them.
//
if (next_space != string)
{
for (p=string; p<next_space; p++)
{
if(fputc(*p, f) == EOF)
{
return -1;
}
}
// Print a newline
//
if (fputc('\n', f) == EOF)
{
return -1;
}
}
// Advance next_space until we hit a non-space character
//
while (*next_space && strchr(space_characters, *next_space))
{
next_space++;
}
// Advance the string
//
string = next_space;
}
// Handle the case where there are no spaces left in the string
//
if (*string)
{
if (fprintf(f, "%s\n", string) < 0)
{
return -1;
}
}
return 0;
}
you can scan the char array looking for the token if you found it just print new line else print the char.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *s;
s = malloc(1024 * sizeof(char));
scanf("%[^\n]", s);
s = realloc(s, strlen(s) + 1);
int len = strlen(s);
char delim =' ';
for(int i = 0; i < len; i++) {
if(s[i] == delim) {
printf("\n");
}
else {
printf("%c", s[i]);
}
}
free(s);
return 0;
}
char arr[50];
gets(arr);
int c=0,i,l;
l=strlen(arr);
for(i=0;i<l;i++){
if(arr[i]==32){
printf("\n");
}
else
printf("%c",arr[i]);
}