Copying contents from one array to another in c - c

Here is an outline of what my program is suppose to do so far.
While there are more words in inputLine:
take next word from the inputLine
if next word fits in the inputline2
add the nextword to inputline2 (doesn't work and maybe not needed)
add the inputline2 to outputBuffer (doesn't work)
format outputBuffer
Otherwise:
write the outputBuffer to the output file
empty out the outputBuffer (put \0 in position 0)
No matter what I try though, the outputline2 and/or outputBuffer never copy the contents of the inputline properly. The only reason I have inputline2 is because I was originally using fgets and putting the contents from a line in a text file into inputline. However, since my array length is suppose to be 40, it would always cut some of the words in the original line in half. If this could be avoided somehow I wouldn't even need inputline2. Either way, in both cases, the contents from word (which is just a single word from the original inputline) won't ever copy properly.
void format(FILE *ipf, FILE *outf)
{
char inputline[80];
char outputBuffer[MaxOutputLine];
char word[MaxOutputLine];
while(fgets(inputline, 80, ipf) != NULL)
{
int pos = 0;
int i;
int j = 0;
char inputline2[MaxOutputLine] = {'\0'};
while(pos != -1)
{
i=0;
pos = nextword(inputline, word, pos);
if(strlen(word) <= (40 - strlen(inputline2)))
{
while(i < strlen(word))
{
inputline2[j] = word[i];
i++;
j++;
}
j++;
printf("%s", inputline2);
}
}
}
}

int nextword(char *inputline, char *word, int pos1) //takes a word beginning from pos and puts it in word and re\
turns the new position of beginning of the next word
{
int pos2 = 0;
if(inputline[pos1] == '\0')
{
return -1;
}
if(inputline[pos1] == ' ')
{
while(inputline[pos1] == ' ')
{
pos1++;
}
}
else
{
while(inputline[pos1] != ' ' && inputline[pos1] != '\n' && inputline[pos1] != '\0')
{
word[pos2] = inputline[pos1];
pos1++;
pos2++;
}
if(pos1 == '\n' || pos1 == '\0')
{
return -1;
}
pos1++;
}
word[pos2]='\0';
return pos1;
}

As I can't format a code in comment I send it as answer.
First, I guess your nextword() is similar to:
#include <stdio.h>
#include <string.h>
int nextword(char *inputline, char *word, int pos)
{
char *ptr;
int len;
ptr = strchr(&inputline[pos], ' ');
len = ptr ? ptr - &inputline[pos] : strlen(&inputline[pos]);
strncpy(word, &inputline[pos], len);
word[len] = 0;
if (ptr == NULL)
return -1;
return pos + len + 1;
}
To make clear:
#define MaxOutputLine 40
In format() you have missed the line:
if(strlen(word) <= (40 - strlen(inputline2)))
{
while(i < strlen(word))
{
inputline2[j] = word[i];
i++;
j++;
}
inputline2[j] = ' ';/*missed, otherwise undefined, eg. \0 */
j++;
printf("%s", inputline2);
}
Some compilers have problem with long buffers on stack. You can try to add "static" before char buf[] in format().
In nextword() you have the mistake:
if(pos1 == '\n' || pos1 == '\0')
{
return -1;
}
instead of
if(inputline[pos1] == '\n' || inputline[pos1] == '\0')
{
word[pos2]='\0';
return -1;
}
In my opinion nextword() could be simplified to something like that:
int nextword(char *inputline, char *word, int pos1)
{
int pos2 = 0;
while(inputline[pos1] != ' ' && inputline[pos1] != '\n' && inputline[pos1] != '\0')
{
word[pos2] = inputline[pos1];
pos1++;
pos2++;
}
word[pos2]='\0';
if(inputline[pos1] == '\n' || inputline[pos1] == '\0')
{
return -1;
}
return pos1 + 1;
}

Related

How to make the calculator count the expression with spaces in the input?

I tried to make calculator supporting brackets, but
I have no idea how to deal if the user's input includes expression with spaces, for example:
input: (2 + 3) * 2
i got: 2
If it's normally get (2+3)*2, it counts 10
.
My code:
#include <stdio.h>
#define MAX_SIZE 1024
int insert_operand(int *operand, int * top_num, int num) /* data is pushed into the data stack*/
{
(*top_num) ++;
operand[*top_num] = num; /*save data*/
return 0; /*Exit normally*/
}
int insert_oper (char * oper , int *top_oper , char ch)
{
(*top_oper)++;
oper[*top_oper] = ch; /*save operator*/
return 0; /*Exit normally*/
}
int compare(char *oper , int *top_oper , char ch) /* compare the priority of the operating server*/
{
if((oper[*top_oper] == '-' || oper[*top_oper] == '+') /*Determine whether the current priority is higher than the priority of the operator at the top of the stack*/
&& (ch == '*' || ch == '/'))
{
return 0;
}
else if(*top_oper == -1 || ch == '('
|| (oper[*top_oper] == '(' && ch != ')')) /*Determine whether the operator stack is empty; whether the top operator is '('*/
{
return 0;
}
else if (oper[*top_oper] =='(' && ch == ')')
{
(*top_oper)--;
return 1;
}
else
{
return -1; /*Operate the operator*/
}
}
int deal_date(int *operand ,char *oper ,int *top_num, int *top_oper) /*perform data operation*/
{
int num_1 = operand[*top_num]; /*Take out two data from the data stack*/
int num_2 = operand[*top_num - 1];
int value = 0;
if(oper[*top_oper] == '+')
{
value = num_1 + num_2;
}
else if(oper[*top_oper] == '-')
{
value = num_2 - num_1;
}
else if(oper[*top_oper] == '*')
{
value = num_2 * num_1;
}
else if(oper[*top_oper] == '/')
{
value = num_2 / num_1;
}
(*top_num) --; /*Move the top of the data stack down one bit*/
operand[*top_num] = value; /*Push the obtained value into the data stack*/
(*top_oper) --; /*Move the top of the operator stack down one bit*/
}
int main()
{
int operand[MAX_SIZE] = {0}; /*data stack, initialize*/
int top_num = -1;
char oper[MAX_SIZE] = {0}; /*operator stack, initialize*/
int top_oper = -1;
char *str = (char *) malloc (sizeof(char) * 100); /*get expression (without =)*/
scanf("%s", str);
char* temp;
char dest[MAX_SIZE];
int num = 0;
int i = 0;
while(*str != '\0')
{
temp = dest;
while(*str >= '0' && *str <= '9') /*judging whether it is data*/
{
*temp = *str;
str++;
temp++;
} /*Encounter a symbol to exit*/
if(*str != '(' && *(temp - 1) != '\0') /*Determine whether the symbol is '('*/
{
*temp = '\0';
num = atoi(dest); /*convert string to number*/
insert_operand(operand, &top_num,num); /*Push data into the data stack*/
}
while(1)
{
i = compare(oper,&top_oper,*str); /*judgment operator priority*/
if(i == 0)
{
insert_oper(oper,&top_oper,*str); /*press operator*/
break;
}
else if(i == 1) /*judging whether the expression in brackets ends*/
{
str++;
}
else if(i == -1) /* data processing */
{
deal_date(operand,oper,&top_num,&top_oper);
}
}
`
str ++; /* point to the next character of the expression */
}
`
printf("%d\n",operand[0]); /*output result*/
return 0;
I tried to count the equation even if there is a space in it. Can someone please help?
Solving the problem by removing spaces:
So if you're working with equation as string you can simply remove spaces with function like this (there will be probably better way or function in library string.h but this was first guess):
char* DeleteSpaces( char* stringWithSpaces, size_t lengthOfString)
{
char* stringWithoutSpaces = (char*)calloc(lengthOfString + 1, sizeof(char));
if( !stringWithoutSpaces )
return NULL;
for( unsigned int x = 0, y = 0; x <= lengthOfString; x++, y++ )
{
if( stringWithSpaces[x] == ' ' ) // if the character is space
{
while( stringWithSpaces[x] == ' ' && x < lengthOfString ) // skip all the spaces OR go away before you hit '\0'
x++;
stringWithoutSpaces[y] = stringWithSpaces[x]; // then copy next character into new string
}
else // if there's no space just copy the character
stringWithoutSpaces[y] = stringWithSpaces[x];
}
return stringWithoutSpaces;
}
This will basically remove all spaces from your received equation. If you really need the smallest possible memory requirement you can use realloc() at the end of the function for more optimal memory usage.
Here's simple example of how to use the function so you can test it:
int main()
{
char firstString[] = "H e l l o w o r l d\0";
char* secondString;
secondString = DeleteSpaces( firstString, strlen(firstString) );
if( !secondString )
return -1;
printf( "%s", secondString );
free( secondString );
return 0;
}
Don't forget to use free(SecondString). I hope I helped you atleast a little :)
As with the previous answer, I added in a function to remove any spaces from the entered formula in order to process the requested calculation. Also, coupled with that, I revised the "scanf" input to read in all of the entered characters which looked to be another symptom you were facing. With that, following is a refactored version of your program with the additional space compression function.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE 1024
int insert_operand(int *operand, int * top_num, int num) /* data is pushed into the data stack*/
{
(*top_num) ++;
operand[*top_num] = num; /*save data*/
return 0; /*Exit normally*/
}
int insert_oper (char * oper , int *top_oper , char ch)
{
(*top_oper)++;
oper[*top_oper] = ch; /*save operator*/
return 0; /*Exit normally*/
}
int compare(char *oper , int *top_oper , char ch) /* compare the priority of the operating server*/
{
if((oper[*top_oper] == '-' || oper[*top_oper] == '+') /*Determine whether the current priority is higher than the priority of the operator at the top of the stack*/
&& (ch == '*' || ch == '/'))
{
return 0;
}
else if(*top_oper == -1 || ch == '('
|| (oper[*top_oper] == '(' && ch != ')')) /*Determine whether the operator stack is empty; whether the top operator is '('*/
{
return 0;
}
else if (oper[*top_oper] =='(' && ch == ')')
{
(*top_oper)--;
return 1;
}
else
{
return -1; /*Operate the operator*/
}
}
int deal_date(int *operand ,char *oper ,int *top_num, int *top_oper) /*perform data operation*/
{
int num_1 = operand[*top_num]; /*Take out two data from the data stack*/
int num_2 = operand[*top_num - 1];
int value = 0;
if(oper[*top_oper] == '+')
{
value = num_1 + num_2;
}
else if(oper[*top_oper] == '-')
{
value = num_2 - num_1;
}
else if(oper[*top_oper] == '*')
{
value = num_2 * num_1;
}
else if(oper[*top_oper] == '/')
{
value = num_2 / num_1;
}
(*top_num) --; /*Move the top of the data stack down one bit*/
operand[*top_num] = value; /*Push the obtained value into the data stack*/
(*top_oper) --; /*Move the top of the operator stack down one bit*/
return value;
}
void compress(char *stx) /* The additional function */
{
char work[101];
int i = strlen(stx);
strcpy(work, stx);
for (int j = 0; j < i; j++)
{
stx[j] = 0;
}
i = 0;
for (int j = 0; j < (int)strlen(work); j++)
{
if (work[j] != ' ')
{
stx[i] = work[j];
i++;
}
}
}
int main()
{
int operand[MAX_SIZE] = {0}; /*data stack, initialize*/
int top_num = -1;
char oper[MAX_SIZE] = {0}; /*operator stack, initialize*/
int top_oper = -1;
char *str = (char *) malloc (sizeof(char) * 100); /*get expression (without =)*/
//scanf("%s", str);
scanf("%[^\n]", str); /* Refined the scanf call to receive all characters prior to the newline/return character */
compress(str); /* Added this function to remove spaces */
char* temp;
char dest[MAX_SIZE];
int num = 0;
int i = 0;
while(*str != '\0')
{
temp = dest;
while(*str >= '0' && *str <= '9') /*judging whether it is data*/
{
*temp = *str;
str++;
temp++;
} /*Encounter a symbol to exit*/
if(*str != '(' && *(temp - 1) != '\0') /*Determine whether the symbol is '('*/
{
*temp = '\0';
num = atoi(dest); /*convert string to number*/
insert_operand(operand, &top_num,num); /*Push data into the data stack*/
}
while(1)
{
i = compare(oper,&top_oper,*str); /*judgment operator priority*/
if(i == 0)
{
insert_oper(oper,&top_oper,*str); /*press operator*/
break;
}
else if(i == 1) /*judging whether the expression in brackets ends*/
{
str++;
}
else if(i == -1) /* data processing */
{
deal_date(operand,oper,&top_num,&top_oper);
}
}
str ++; /* point to the next character of the expression */
}
printf("%d\n",operand[0]); /*output result*/
return 0;
}
Testing out your sample formula with some additional spacing to ensure the compression function was working properly, following was the terminal output.
#Vera:~/C_Programs/Console/Calculate/bin/Release$ ./Calculate
(2 + 3) * 2
10
Give that a try and see if it meets the spirit of your project.
As pointed out in the comments and other answers, the solution may be to simply "compact" the spaces out of the string before trying to analyse the string's content.
This doesn't require a lot of code:
#include <stdio.h>
char *stripSP( char *src ) {
for( char *d = src, *s = src; ( *d = *s ) != '\0'; s++ )
d += *d != ' ';
return src;
}
int main( void ) {
char *s[] = { "Hello", "H e l l ooo", "(2 + 5) * 3" };
for( int i = 0; i < 3; i++ ) {
printf( "From '%s' ", s[i] );
printf( "'%s'\n", stripSP( s[i] ) );
}
return 0;
}
From 'Hello' 'Hello'
From 'H e l l ooo' 'Hellooo'
From '(2 + 5) * 3' '(2+5)*3'
Even more compact would be to use array indexing:
char *stripSP( char s[] ) {
for( int f=0, t=0; (s[t] = s[f++]) != '\0'; t += s[t] != ' ' ) {}
return s;
}

Segmentation fault error while working with command-line argument, C program

I am working on a program that decodes a message provided as a morse code as a command line argument. If the provided string contains 7 spaces it means that I need to print a space to the decoded string. Currently, my program shows all correct letters, but I cannot overcome the issue with locating 7 spaces in a string and printing one space instead.
Here is the issue and how I pass the encoded string:
e3r2p2% ./morse "..- -.. .-. .. .-- --. ..- ....."
udriwg zsh: segmentation fault ./morse "..- -.. .-. .. .-- --. ..- ....."
Program works fine and prints all the decrypted letters (udriwg) till it meets the first (or maybe second) space out of 7;
Here is the code of my program:
int find_morse(const char *s);
bool count_spaces(char *s);
bool is_valid_char(char *s);
bool is_valid_params(int argc, char *argv[]);
void mx_printchar(char c);
void mx_printerr(const char *s);
int mx_strcmp(const char *first, const char *second);
char* mx_strcpy(char* dest, const char* source);
int mx_strlen(const char *s)
int main(int argc, char *argv[]){
if (!is_valid_params(argc, argv)){
mx_printerr("usage: ./morse \"str\"\n");
exit(1);
}
char *output[27]= {"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o",
"p","q","r","s","t","u","v","w","x","y","z","."};
char *copy;
copy = malloc(mx_strlen(argv[1]) + 1);
if (copy != NULL) {
mx_strcpy(copy, argv[1]);
} else {
mx_printerr("usage: ./morse \"str\"\n");
exit(1);
}
int buff = 0;
char temp[5];
int index;
int space = 0;
int j;
for (int i = 0, n = mx_strlen(copy); i < n; i++) {
if (copy[i] == '.' && copy[i + 1] == '.' && copy[i + 2] == '.'
&& copy[i + 3] == '.' && copy[i + 4] == '.') {
mx_printchar(*output[26]);
}
if (copy[i] != ' ') {
temp[buff] = copy[i];
buff++;
}
if (copy[i] == ' ') {
index = find_morse(temp);
//print letter converted from morse to ENG
mx_printchar(*output[index]);
j = i;
while (copy[j] == ' ') {
space++;
j++;
if (space == 7) {
mx_printchar(' ');
space = 0;
break;
}
}
temp[buff] = '\0';
buff = 0;
for(int j = 0; j <4; j++) {
temp[j] ='\0';
}
}
}
mx_printchar('\n');
free(copy);
return 0;
}
int find_morse(const char *s) {
char *input[27]={".-","-...","-.-.","-..",".","..-.","--.", "....", "..",
".---","-.-",".-..","--","-.", "---",".--.","--.-",".-.",
"...","-","..-", "...-",".--","-..-","-.--","--..","....."};
for (int i = 0; i < 27; i++) {
if (mx_strcmp(s, input[i]) == 0) {
return i;
}
}
return -1;
}
bool count_spaces(char *s) {
int space = 0;
for (int i = 0; s[i] != '\0'; i++) {
if (s[i] == ' ') {
space++;
if (s[i + 1] != ' ') {
if (space != 1 && space != 7) {
return false;
} else {
space = 0;
}
}
}
}
return true;
}
bool is_valid_char(char *s){
int i = 0;
while (s[i] != '\0'){
if (s[i] != ' ' && s[i] != '-' && s[i] != '.') {
return false;
}
i++;
}
return true;
}
bool is_valid_params(int argc, char *argv[]){
if (argc != 2) {
return false;
}
if (!is_valid_char(argv[1])){
return false;
}
if (!count_spaces(argv[1])){
return false;
}
return true;
}
void mx_printchar(char c){
write(1, &c, 1);
}
void mx_printerr(const char *s){
write(2, s, mx_strlen(s));
}
int mx_strcmp(const char *first, const char *second) {
while (*first) {
if (*first != *second) break;
first++;
second++;
}
return *(const unsigned char*)first - *(const unsigned char*)second;
}
char* mx_strcpy(char* dest, const char* source){
if (dest == NULL) {
return NULL;
}
char *ptr = dest;
while (*source != '\0') {
*dest = *source;
dest++;
source++;
}
*dest = '\0';
return ptr;
}
int mx_strlen(const char *s){
int length = 0;
while (s[length] != '\0'){
length++;
}
return length;
}
I believe the issue starts here:
j = i;
while (copy[j] == ' ') {
space++;
j++;
if (space == 7) {
mx_printchar(' ');
space = 0;
break;
}
}
Program prints the decripted letter, then tries to check those spaces but somethis go wrong.
I'd appreciate any suggestions as how to resolve it
When using a program from command line you always put a space as a delimiter between your program name and the parameters and other parameters. So, in your case if there are 7 spaces then a extra space will be added as delimiter between your program name and 7 spaces making it to 8 spaces like this ./morse. So, I'd rather suggest to use any other symbol like ! or any other symbol.
Now for the Segmentation fault error I think that's not happening because of that space counter section that's happening because of this line copy = malloc(mx_strlen(argv[1]) + 1); as you must know that malloc() returns a void * to the allocated space.Now here I don't know what those mx_ functions are. Also some questions popped out in my mind while I was debugging your code those answers are included in the modified code(at somewhat satisfying level) i'm putting below. Please answer them in comments.
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Questions
** 1. What are these mx_ functions?
** 2. What is is_valid_params?
** 3. Can't we define *output[27] as *output = "abcdef...z." ?
** 4. In " for(j = 0; j < 4; j++) temp[j] ='\0'; " why j < 4 instead of j < 5?
*/
// Function Prototype
int find_morse(const char *s);
//main()
int main(int argc, char *argv[])
{
char *output[27]= {"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","."};
char *copy, temp[5];
int buff = 0, index, space = 0, i, j, n;
// Checking for valid parameters.
if (argc != 2)
{
printf("usage: ./morse \"Invalid Parameters.\"\n");//mx_printerr("usage: ./morse \"str\"\n");
exit(1);
}
copy = (char *)malloc(strlen(argv[1]) + 1);
if (copy != NULL)
strcpy(copy, argv[1]);
else
{
printf("usage: ./morse \"Memory Unavailable.\"\n");
exit(2);
}
for (i = 0, n = strlen(copy); i < n; i++)
{
if (copy[i] == '.' && copy[i + 1] == '.' && copy[i + 2] == '.' && copy[i + 3] == '.' && copy[i + 4] == '.')
putchar(*output[26]);
if (copy[i] != ' ')
temp[buff++] = copy[i];
else
{
j = i;
while (copy[j] == ' ')
{
space++;
j++;
if (space == 7)
{
putchar(' ');
space = 0;
break;
}
}
temp[buff] = '\0';
buff = 0;
// Emptying temp[5]
//for(j = 0; j < 5; j++)
temp[0] = '\0'; // Rest elements will automatically be assigned to \0 by compiler.
}
if(index = find_morse(temp) != -1)
putchar(*output[index]); //print letter converted from morse to ENG
}
putchar('\n');
free(copy);
return 0;
}
int find_morse(const char *s)
{
char *input[27] = {".-","-...","-.-.","-..",".","..-.","--.", "....", "..",".---","-.-",".-..","--","-.", "---",".--.","--.-",".-.","...","-","..-", "...-",".--","-..-","-.--","--..","....."};
for (int i = 0; i < 27; i++)
{
if (strcmp(s, input[i]) == 0)
return i;
}
return -1;
}
Here in this program I didn't understand that how the user will enter morse code one by one or as a string. Because, when matching those morse code entries, I'm sure a logical error would occur.

Splitting a string to an array of strings

I'm trying to split a sentence the user inputs to an array of words so I can later manipulate the words separately as strings.
The code is compiling but prints only garbage after the user input.
I tried debugging but don't see the problem. Can someone help me fix it?
#include <stdio.h>
#include <string.h>
int main() {
char str[1000];
int i = 0;
char rev[1000][1000];
int r = 0;
puts("Enter text:");
gets(str);
int k, length = 0;
printf_s("So the words are:\n");
while (str[i] != '\0') {
if (str[i] == ' ') {
k = i - length;
do {
rev[r][k] = (str[k]);
k++;
} while (str[k] != ' ');
printf(" ");
length = (-1);
r++;
} else
if (str[i + 1] == '\0') {
k = i - length;
do {
rev[r][k] = (str[k]);
k++;
} while (str[k] != '\0');
length = 0;
r++;
}
length++;
i++;
}
for (int r = 0; r < 1000; r++)
printf("%s ", rev[r]);
return 0;
}
fix like this
#include <stdio.h>
int main(void) {
char str[1000];
char rev[1000][1000];
puts("Enter text:");
fgets(str, sizeof str, stdin);//Use fgets instead of gets. It has already been abolished.
int r = 0;
int k = 0;
for(int i = 0; str[i] != '\0'; ++i){
if (str[i] == ' ' || str[i] == '\n'){//is delimiter
if(k != 0){
rev[r++][k] = '\0';//add null-terminator and increment rows
k = 0;//reset store position
}
} else {
rev[r][k++] = str[i];
}
}
if(k != 0)//Lastly there was no delimiter
rev[r++][k] = '\0';
puts("So the words are:");
for (int i = 0; i < r; i++){
printf("%s", rev[i]);
if(i < r - 2)
printf(", ");
else if(i == r - 2)
printf(" and ");
}
return 0;
}
Replace you declaration
char rev[1000][1000];
with
char * rev[1000]; // We will need pointers only
int i = 0; // Index to previous array
and all your code after
puts( "Enter text:" );
with this:
fgets( str, 998, stdin ); // Safe way; don't use gets(str)
const char delim[] = ",; "; // Possible delimiters - comma, semicolon, space
char *word;
/* Get the first word */
word = strtok( str, delim );
rev[i++] = word;
/* Get the next words */
while( word != NULL )
{
word = strtok( NULL, delim );
rev[i++] = word;
}
/* Testing */
for (int r = 0; r < i - 1; r++)
printf( "%s\n", rev[r] );
return 0
}
As you can see, all dirty work is done with the strtok() function ("string to tokens") which walks through other and other words ("tokens"), recognizing them as delimited by one or more characters from the string delim.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int count_spaces(char *str)
{
if (str == NULL || strlen(str) <= 0)
return (0);
int i = 0, count = 0;
while (str[i])
{
if (str[i] == ' ')
count++;
i++;
}
return (count);
}
int count_char_from_pos(char *str, int pos)
{
if (str == NULL || strlen(str) <= 0)
return 0;
int i = pos, count = 0;
while (str[i] && str[i] != ' ')
{
count++;
i++;
}
return count;
}
char **get_words(char *str)
{
if (str == NULL || strlen(str) <= 0)
{
printf("Bad string inputed");
return NULL;
}
int i = 0, j = 0, k = 0;
char **dest;
if ((dest = malloc(sizeof(char*) * (count_spaces(str) + 1))) == NULL
|| (dest[0] = malloc(sizeof(char) * (count_char_from_pos(str, 0) + 1))) == NULL)
{
printf("Malloc failed\n");
return NULL;
}
while (str[i])
{
if (str[i] == ' ') {
dest[j++][k] = '\0';
if ((dest[j] = malloc(sizeof(char) * (count_char_from_pos(str, i) + 1))) == NULL)
{
printf("Malloc failed\n");
return NULL;
}
k = 0;
}
else {
dest[j][k++] = str[i];
}
i++;
}
dest[j][k] = 0;
dest[j + 1] = NULL;
return dest;
}
int main(void) {
char *line = NULL;
size_t n = 0;
getline(&line, &n, stdin);
printf("%s\n", line);
line[strlen(line) - 1] = 0;
printf("%s\n", line);
char **tab = get_words(line);
int i = 0;
while (tab[i])
{
printf("%s\n", tab[i++]);
}
}
here is a long but fully working example
get the user input
then send it to get_words function. It will get the number of words, the number of characters for each words, allocate everything in memory and writes chars then return it. You get a char ** and prints it just tested it it works
If you wish to split a string into an array of strings, you should consider the strtok function from #include <string.h>. The strtok function will the split the string on the given delimiter(s). For your case, it would the " ".
Using the strtok example from Tutorials Point:
#include <string.h>
#include <stdio.h>
int main(){
char str[80] = "This is - www.tutorialspoint.com - website";//The string you wish to split
const char s[] = "-";//The thing you want it to split from. But there is no need to this.
char *token;//Storing the string
/* get the first token */
token = strtok(str, s);//Split str one time using the delimiter s
/* walk through other tokens */
while( token != NULL )
{
printf( " %s\n", token );//Print the string
token = strtok(NULL, s);//Split the string again using the delimiter
}
return(0);
}

splitting a string by white spaces

Before reading this question please note that my question pertains to a school assignment. For this assignment the only function we are allowed to use is malloc(). Everything else must be done without the use of other libraries.
I'm calling a function ft_split_whitespaces. This function takes a string as input and "splits" it into words. Words are separated spaces, tabs and line breaks.
#include <stdio.h>
char **ft_split_whitespaces(char *str);
int main(void)
{
char *str = "what is";
char **test = ft_split_whitespaces(str);
}
With respect to the example above the result at each index should be
test[0] = "what"
test[1] = "is"
test[2] = NULL
However, I am only able to print the results of test[0]. All other indices do not get printed to display. Heres an example of some code that I assume should print the results of my function.
int i = 0;
while(test[i] != NULL)
{
printf("%s", test[i]);
i++;
}
When this portion of code is ran, only test[0] is printed to the output. I've been sitting here trying to debug my code for hours. If anyone has some spare time and doesn't mind looking over my code, I'd appreciate it tremendously. I have a feeling it may be an issue with how I'm using malloc, but I still cant figure it out.
#include <stdlib.h>
#include <stdio.h>
int count_whitespaces(char *str)
{
int space_count;
int i;
space_count = 0;
i = 0;
while(str[i] != '\0')
{
if(str[i] == ' ' || str[i] == 9 || str[i] == '\n')
{
if(str[i+1] != ' ' && str[i+1] != 9 && str[i+1] != '\n')
space_count++;
}
i++;
}
return (space_count);
}
int check_whitespace(char c)
{
if (c == ' ' || c == 9 || c == '\n' || c == '\0')
{
return (1);
}
else
return(0);
}
int count_characters(char *str, int i)
{
int char_count;
char_count = 0;
while(str[i])
{
if(str[i+1] != ' ' && str[i+1] != 9 && str[i+1] != '\n')
char_count++;
else
break;
i++;
}
return (char_count);
}
char **ft_split_whitespaces(char *str)
{
int i;
int j;
int k;
char **word;
int space;
i = 0;
j = 0;
k = 0;
word = (char**)malloc(sizeof(char*)*(count_whitespaces(str) + 2));
while(str[i] != '\0')
{
if (check_whitespace(str[i]) == 1)
i++;
else
{
if((word[j] = malloc(sizeof(char) * (count_characters(str, i) + 1))) == NULL)
return (NULL);
while (check_whitespace(str[i]) == 0)
{
word[j][k] = str[i];
i++;
k++;
}
j++;
}
}
j++;
word[j] = NULL;
j = 0
return word;
}
You forgot to reset k. The outer while loop in ft_split_whitespaces should look like that
while (str[i] != '\0') {
if (check_whitespace(str[i]) == 1){
i++;
}
else {
if ((word[j] =
malloc(sizeof(char) * (count_characters(str, i) + 1))) == NULL){
return (NULL);
}
while (check_whitespace(str[i]) == 0) {
word[j][k] = str[i];
i++;
k++;
}
word[j][k] = '\0';
j++;
k = 0; // reset k
}
}
So I actually figured out what was going wrong with my code as I finished typing this question (thanks stack overflow!). I decided to post it anyways, because I thought it might be a good learning experience for coding newbies such as myself.
This is where my issue was occurring.
word = (char**)malloc(sizeof(char*)*(count_whitespaces(str) + 2));
while(str[i] != '\0')
{
if (check_whitespace(str[i]) == 1)
i++;
else
{
if((word[j] = malloc(sizeof(char) * (count_characters(str, i) + 1))) == NULL)
return (NULL);
while (check_whitespace(str[i]) == 0)
{
word[j][k] = str[i];
i++;
k++;
}
j++;
}
}
I malloc'd my char **word outside of the while loop using the following code
word = (char**)malloc(sizeof(char*)*(count_whitespaces(str) + 2));
And then within the actual while loop I malloc'd it again using
word = (char**)malloc(sizeof(char*)*(count_whitespaces(str) + 2));
Using malloc multiple times on the same variable was causing all sorts of weird issues. So within the while loop I ended up using a new variable I declared as char *words. Here is that portion of the while loop with the correct code.
word = (char**)malloc(sizeof(char*)*(count_whitespaces(str) + 2));
while(str[i] != '\0')
{
if (check_whitespace(str[i]) == 1)
i++;
else
{
words = malloc(sizeof(char) * (count_characters(str, i) + 1));
k = 0;
while (check_whitespace(str[i]) == 0)
{
words[k] = str[i];
i++;
k++;
}
words[k] = '\0';
word[j] = words;
j++;
}
}

C --- Remove all extra spaces in string excluding chars between specified characters

I have this string: print "Foo cakes are yum"
I need to somehow strip all extra whitespace but leave text between quotes alone. This is what i have so far:
char* clean_strip(char* string)
{
int d = 0, c = 0;
char* newstr;
while(string[c] != '\0'){
if(string[c] == ' '){
int temp = c + 1;
if(string[temp] != '\0'){
while(string[temp] == ' ' && string[temp] != '\0'){
if(string[temp] == ' '){
c++;
}
temp++;
}
}
}
newstr[d] = string[c];
c++;
d++;
}
return newstr;
}
This returns this string: print "Foo cakes are yum"
I need to be able to skip text between thw quotes so i get this: print "Foo cakes are yum".
Here is the same question but for php, i need a c answer: Remove spaces in string, excluding these in specified between specified characters
Please help.
Try this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* clean_strip(char* string)
{
int d = 0, c = 0;
char* newstr = malloc(strlen(string)+1);
int quoted = 0;
while(string[c] != '\0'){
if (string[c] == '"') quoted = !quoted;
if(!quoted && string[c] == ' '){
int temp = c + 1;
if(string[temp] != '\0'){
while(string[temp] == ' ' && string[temp] != '\0'){
if(string[temp] == ' '){
c++;
}
temp++;
}
}
}
newstr[d] = string[c];
c++;
d++;
}
newstr[d] = 0;
return newstr;
}
int main(int argc, char *argv[])
{
char *input = "print \"Foo cakes are yum\"";
char *output = clean_strip(input);
printf(output);
free(output);
return 0;
}
This will produce the output:
print "Foo cakes are yum"
It works by looking for the " character. If it's found it toggles the variable quoted. If quoted is true, then the whitespace removal is skipped.
Also, your original function never allocates memory for newstr. I added the newstr = malloc(...) part. It is important to allocate memory for strings before writing to them.
I simplified your logic a little.
int main(void)
{
char string[] = "print \"Foo cakes are yum\"";
int i = 0, j = 1, quoted=0;
if (string[0] == '"')
{
quoted=1;
}
for(i=1; i< strlen(string); i++)
{
if (string[i] == '"')
{
quoted = 1-quoted;
}
string[j] = string[i];
if (string[j-1]==' ' && string[j] ==' ' && !quoted)
{
;
}
else
{
j++;
}
}
string[j]='\0';
printf("%s\n",string);
return 0;
}

Resources