String compare and length - c

Hi I am trying to right a program but am having so much difficulty. The program is a challenge I made up myself. I want to read in 6 strings from the user. Then I want to create a function that will allow me to compare those strings to find which string is different in size. Then I want to pass this info to another function that will determine the string length of the string that is different. Finally print the value. Here is what I have done thus far (many many errors).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* diffFun(char* ,char*,char * ,char *,char * ,char *)
{
char *s1;
char *s2;
char *s3;
char *s4;
char *s5;
char *s6;
char *result;
if (strcmp(s2,s3,s4,s5,s6)<strcmp(s1))
result = s1;
else if (strcmp(s1,s3,s4,s5,s6)<strcmp(s2))
result s2;
return result;
}
int main()
{
char *str1;
char *str2;
char *str3;
char *str4;
char *str5;
char *str6;
printf("Give me a string1:\n");
str1 = readString(stdin);
printf("Give me a string2:\n");
str2 = readString(stdin);
printf("Give me a string3:\n");
str3 = readString(stdin);
printf("Give me a string4:\n");
str4 = readString(stdin);
printf("Give me a string5:\n");
str5 = readString(stdin);
printf("Give me a string6:\n");
str6 = readString(stdin);
char *cond;
cond = diffFun((char* str1,char* str2,char* str3,char* str4,char* str5,char* str6);
printf("%ls",cond);
return 0;
}

I do not understand well, but I feel like the following...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* diffFun(int n, char *s[n]){
int i, j;
char *result = s[0];
size_t result_len = strlen(result);
for(i = 1; i < n; ++i){
size_t len = strlen(s[i]);
if(result_len < len){
result = s[i];
result_len = len;
} else if(result_len == len && strcmp(result, s[i]) < 0){
result = s[i];
}
}
return result;
}
int main(void){
char *str[6];
int i;
for(i=0;i<6; i++){
printf("Give me a string%d:\n", i+1);
str[i] = readString(stdin);
}
char *cond = diffFun(6, str);
printf("%s",cond);
return 0;
}

Related

Passing char * to function returns different results than passing char []?

I am writing a function in C to get the next word from a string (*s) and copy it into the buffer (*w). It returns the first char of the word.
It works fine when the input string is a char pointer (char *text), but when I change the type to a char array (char [MAXTEXT]) the program crashes.
This is confusing me, as I thought the compiler 'decayed' char arrays into char pointers anyway. To my belief, whether the input is a char pointer or a char array shouldn't make a difference?
(The declaration is at line 10 char *text = "This should return the first word";, which crashes when changed to char text[MAXTEXT] = "This should return the first word";)
#include <stdio.h>
#include <ctype.h>
#define MAXTEXT 1000
int getword(char *inp, char *out, int lim);
void main()
{
char *text = "This should return the first word";
char *word;
int i, c;
printf("%c", getword(text, word, MAXTEXT));
printf("%s", word);
}
int getword(char *s, char *w, int lim)
{
static int bufp = 0;
char c;
char *word = w;
while (isspace(c = s[bufp++]));
if (c != EOF)
*w++ = c;
else if (!isalpha(c))
{
*w = '\0';
return c;
};
for (; --lim > 0; bufp++)
if (isalpha(c = s[bufp]) || c == '\'')
*w++ = s[bufp];
else
break;
*w = '\0';
return word[0];
}
The problem is that for the pointer word, you haven't allocated any memory. Simply allocating memory will fix the problem.
Your array implementation:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#define MAXTEXT 1000
char getword(char *inp, char *out, int lim);
int main()
{
char text[100],word[100];
// char *text = (char*)calloc(100,sizeof(char));
strcpy(text,"This should return the first word");
// char *word = (char*)calloc(100,sizeof(char));
int i, c;
printf("%c", getword(text, word, MAXTEXT));
// printf("%s", text);
return 0;
}
char getword(char *s, char *w, int lim)
{
static int bufp = 0;
char c;
char *word = w;
while (isspace(c = s[bufp++]));
if (c != EOF)
*w++ = c;
else if (!isalpha(c))
{
*w = '\0';
return c;
};
for (; --lim > 0; bufp++)
if (isalpha(c = s[bufp]) || c == '\'')
*w++ = s[bufp];
else
break;
*w = '\0';
return word[0];
}

Using prototype replace one character with another in c

#include "stdafx.h"
#include "stdio.h"
void repl(char *string, char oldc, char newc);
char text[60] = { "I am going to replace the character a with the character i";
char newc = 'b';
char oldc = 'a';
int main()
{
void repl(char *string, char oldc, char newc);
return 0;
}
void repl(char *string, char oldc, char newc)
{
int i = 0;
for (i = 0; i < *string; i++)
{
if (*(string + i) == oldc)
{
*(string + i) == newc;
}
}
printf("%s", string);
}
I am trying to replace the character a with the character b.
I know how to do this without using pointers but I am not too sure when it comes to pointers.
The prototype I was given was:
void repl(char *string, char oldc, char newc);
This does what you're after. I seriously recommend reading up on some basic C programming topics, such as calling functions and declaring char arrays. In the meantime...
#include "stdafx.h"
#include "stdio.h"
void repl(char *string, char oldc, char newc);
char text[60] = "I am going to replace the character a with the character i";
char newc = 'i';
char oldc = 'a';
int main()
{
repl(text, oldc, newc);
return 0;
}
void repl(char *string, char oldc, char newc)
{
int i = 0;
for (i = 0; string[i]; i++)
{
if (string[i] == oldc)
{
string[i] = newc;
}
}
printf("%s", string);
}

Trying to use strtok and malloc but keeps erroring and I cannot see the error message

I'm trying to create a split function using strtok and a dynamic array.
However, I have no clue where things are going wrong: No informative error messages.
It does say segmentation fault, but I don't understand how the heap is corrupt or whatever causes that happens.
Would someone be willing to explain to me what is wrong and how to do it correctly?
Edit 11:16 CST code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **toArray(char **array, char str[], char sep[], int *count);
char** my_split(const char* str, char delim, int* size);
int main(int argc, char* argv[]) {
char* test = "Hello there lol";
int *count = 0;
char **array = malloc(sizeof(char*) * 5);
toArray(array, test, " ", count);
printf("Count: %d\n", *count);
int array_i;
for (array_i = 0; array_i < *count; array_i++) {
printf("array %d: %s\n", array_i, array[array_i]);
free(array[array_i]);
}
free(array);
return 1;
}
char **toArray(char **array, char str[], char sep[], int *count) {
char *temp = str;
temp = strtok(temp, sep);
array[0] = temp;
*count = 1;
while ((temp = strtok(NULL, sep)) != NULL ) {
array[(*count)++] = temp;
}
return array;
}
Compiler messages are our friend. I simpley used them to track down your issues. Try the following, and compare whats been done to what you had. Special attention to decalration and usage of pointer variables... :)
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char **toArray(char **array, char str[], char sep[], int *count);
int main(int argc, char* argv[]) {
char test[] = "Hello there lol";
int count = 0;
char **array = malloc((sizeof(char*) * 5) +1); //added "+ 1" here, read why
toArray(array, test, " ", &count); //in comment below
printf("Count: %d\n", count);
int array_i;
for (array_i = 0; array_i < count; array_i++) {
printf("array %d: %s\n", array_i, array[array_i]);
//free(array[array_i]);
}
getchar();
free(array);
return 1;
}
char **toArray(char **array, char str[], char sep[], int *count) {
char *temp = str;
temp = strtok(temp, sep);
array[0] = temp;
*count = 1;
while ((temp = strtok(NULL, sep)) != NULL) {
array[(*count)++] = temp;
}
return array;
}
[EDIT] Example Output:
Also. The line char **array = malloc(sizeof(char*) * 5);, needed to be
char **array = malloc(sizeof(char*) * 5 + 1); because "hello" is actually 5 chars plus a NULL char, '\0'.
Some rules of thumb for C string(s).
1) when using malloc or calloc, don't forget to allow room for '\0'.
`char *buf1;` //buffer needed to manipulate buf2
`char buf2[]="someString";`
`buf1 = malloc(strlen(buf2)+1);` or `buf1 = malloc(sizeof(buf2));`
(note:, no '+1'. see '4)' below. )
2) clear (initialize) new allocated variable before use. eg:
memset(buf, 0, strlen("someString")+1); //preferred, all bytes are zeroed
OR
buf[0]=0; //useful, but use with care (only first byte is zeroed.)
3) Free all dynamically allocated memory when done with it. Eg:
free(buf);
4) Using strlen() function or sizeof() macro. (both popular for use in [mc]alloc())
Given:
char *buf1 ="Hello"; //6 characters |H|e|l|l|o|\0|
char buf2[] ="Hello"; //6 characters |H|e|l|l|o|\0|
char buf3[5]="Hello"; //5 characters |H|e|l|l|o|
char buf4[5]="Hel"; //4 characters |H|e|l|\0| |
char buf5[5]="Helloo";//should get compile error, too many initializers
Compare strlen() - sizeof() results:
strlen(buf1); //->5 (requires +1 in malloc for new variable req'd to hold "Hello\0")
sizeof(buf1); //->4 (returns sizof (char *), not # chars in string)
strlen(buf2); //->5 (requires +1 in malloc for new variable req'd yo hold "Hello\0")
sizeof(buf2); //->6 (counts all chars, including '\0')
strlen(buf3); //-> (error: Missing terminating NULL in string argument)
sizeof(buf3); //->5 (counts all chars, but there is no '\0' in this string - wrong!)
strlen(buf4); //->3 (counts chars, but not '\0')
sizeof(buf4); //->5 (counts ALL allocated space, including '\0')
You are passing char *test = "Hello there lol"; to your toArray(). Unfortunately, the string is not modifiable, so when you try to modify it with strtok(), you get a segmentation fault.
The simplest fix is:
char test[] = "Hello there lol";
You also have:
int *count = 0;
and you call the function with:
toArray(array, test, " ", count);
You need an integer, and to pass its address:
int count = 0;
...
toArray(array, test, " ", &count);
You were also trying to free the strings that were pointed at by the elements in array, but those were never allocated (they are parts of the string test). Don't free what was not allocated with malloc() et al.
With those fixes in place, this code works:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **toArray(char **array, char str[], char sep[], int *count);
int main(void)
{
char test[] = "Hello there lol";
int count = 0;
char **array = malloc(sizeof(char *) * 5);
toArray(array, test, " ", &count);
printf("Count: %d\n", count);
for (int i = 0; i < count; i++)
printf("array %d: %s\n", i, array[i]);
free(array);
return 0;
}
char **toArray(char **array, char str[], char sep[], int *count)
{
char *temp = str;
temp = strtok(temp, sep);
array[0] = temp;
*count = 1;
while ((temp = strtok(NULL, sep)) != NULL)
array[(*count)++] = temp;
return array;
}
Output:
Count: 3
array 0: Hello
array 1: there
array 2: lol

How can I split a char* into substrings in C?

I have a text like this:
char* str="Hi all.\nMy name is Matteo.\n\nHow are you?"
and I want to split the string by "\n\n" in to an array like this:
char* array[3];
array[0]="Hi all.\nMy name is Matteo."
array[1]="How are you?"
array[2]=NULL
I've tried the strtok function but it does not split the string correctly.
#include <stdio.h>
#include <string.h>
int main(){
char *str="Hi all.\nMy name is Matteo.\n\nHow are you?";
char *array[3];
char *ptop, *pend;
char wk[1024];//char *wk=malloc(sizeof(char)*(strlen(str)+3));
int i, size = sizeof(array)/sizeof(char*);
/*
array[0]="Hi all.\nMy name is Matteo."
array[1]="How are you?"
array[2]=NULL
*/
strcpy(wk, str);
strcat(wk, "\n\n");
for(i=0, ptop=wk;i<size;++i){
if(NULL!=(pend=strstr(ptop, "\n\n"))){
*pend='\0';
array[i]=strdup(ptop);
ptop=pend+2;
} else {
array[i]=NULL;
break;
}
}
for(i = 0;i<size;++i)
printf("array[%d]=\"%s\"\n", i, array[i]);
return 0;
}
The strtok() function works on a set of single character delimiters. Your goal is to split by a two character delimiter, so strtok() isn't a good fit.
You could scan your input string via a loop that used strchr to find newlines and then checked to see if the next char was also a newline.
A more generic method based on strstr function:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char* str="Hi all.\nMy name is Matteo.\n\nHow are you?\n\nThanks";
char **result = NULL;
unsigned int index = 0;
unsigned int i = 0;
size_t size = 0;
char *ptr, *pstr;
ptr = NULL;
pstr = str;
while(pstr) {
ptr = strstr(pstr, "\n\n");
result = realloc(result, (index + 1) * sizeof(char *));
size = strlen(pstr) - ((ptr)?strlen(ptr):0);
result[index] = malloc(size * sizeof(char));
strncpy(result[index], pstr, size);
index++;
if(ptr) {
pstr = ptr + 2;
} else {
pstr = NULL;
}
} ;
for(i = 0; i < index; i++) {
printf("Array[%d] : >%s<\n", i, result[i]);
}
return 0;
}

Using strtok in c

I need to use strtok to read in a first and last name and seperate it. How can I store the names where I can use them idependently in two seperate char arrays?
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] ="test string.";
char * test;
test = strtok (str," ");
while (test != NULL)
{
printf ("%s\n",test);
test= strtok (NULL, " ");
}
return 0;
}
Here is my take at a reasonably simple tokenize helper that
stores results in a dynamically growing array
null-terminating the array
keeps the input string safe (strtok modifies the input string, which is undefined behaviour on a literal char[], at least I think in C99)
To make the code re-entrant, use the non-standard strtok_r
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char** tokenize(const char* input)
{
char* str = strdup(input);
int count = 0;
int capacity = 10;
char** result = malloc(capacity*sizeof(*result));
char* tok=strtok(str," ");
while(1)
{
if (count >= capacity)
result = realloc(result, (capacity*=2)*sizeof(*result));
result[count++] = tok? strdup(tok) : tok;
if (!tok) break;
tok=strtok(NULL," ");
}
free(str);
return result;
}
int main ()
{
char** tokens = tokenize("test string.");
char** it;
for(it=tokens; it && *it; ++it)
{
printf("%s\n", *it);
free(*it);
}
free(tokens);
return 0;
}
Here is a strtok-free reimplementation of that (uses strpbrk instead):
char** tokenize(const char* str)
{
int count = 0;
int capacity = 10;
char** result = malloc(capacity*sizeof(*result));
const char* e=str;
if (e) do
{
const char* s=e;
e=strpbrk(s," ");
if (count >= capacity)
result = realloc(result, (capacity*=2)*sizeof(*result));
result[count++] = e? strndup(s, e-s) : strdup(s);
} while (e && *(++e));
if (count >= capacity)
result = realloc(result, (capacity+=1)*sizeof(*result));
result[count++] = 0;
return result;
}
Do you need to store them separately? Two pointers into a modified char array will yield two separate perfectly usable strings.
That is we transform this:
char str[] ="test string.";
Into this:
char str[] ="test\0string.";
^ ^
| |
char *s1 ----- |
char *s2 -----------
.
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] ="test string.";
char *firstname = strtok(str, " ");
char *lastname = strtok(NULL, " ");
if (!lastname)
lastname = "";
printf("%s, %s\n", lastname, firstname);
return 0;
}
What about using strcpy:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MAX_NAMES 2
int main ()
{
char str[] ="test string.";
char *names[MAX_NAMES] = { 0 };
char *test;
int i = 0;
test = strtok (str," ");
while (test != NULL && i < MAX_NAMES)
{
names[i] = malloc(strlen(test)+1);
strcpy(names[i++], test);
test = strtok (NULL, " ");
}
for(i=0; i<MAX_NAMES; ++i)
{
if(names[i])
{
puts(names[i]);
free(names[i]);
names[i] = 0;
}
}
return 0;
}
It contains much clutter to maintain a complete program and clean its resources, but the main point is to use strcpy to copy each token into its own string.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char** split(const char *str, const char *delimiter, size_t *len){
char *text, *p, *first, **array;
int c;
char** ret;
*len = 0;
text=strdup(str);
if(text==NULL) return NULL;
for(c=0,p=text;NULL!=(p=strtok(p, delimiter));p=NULL, c++)//count item
if(c==0) first=p; //first token top
ret=(char**)malloc(sizeof(char*)*c+1);//+1 for NULL
if(ret==NULL){
free(text);
return NULL;
}
strcpy(text, str+(first-text));//skip until top token
array=ret;
for(p=text;NULL!=(p=strtok(p, delimiter));p=NULL){
*array++=p;
}
*array=NULL;
*len=c;
return ret;
}
void free4split(char** sa){
char **array=sa;
if(sa!=NULL){
free(array[0]);//for text
free(sa); //for array
}
}
int main(void){
char str[] ="test string.";
char **words;
size_t len=0;
int i;
words = split(str, " \t\r\n,.", &len);
/*
for(char **wk = words; *wk ;wk++){
printf("%s\n", *wk);
}
*/
for(i = 0;i<len;++i){
printf("%s\n", words[i]);
}
free4split(words);
return 0;
}
/* result:
test
string
*/
Copy the results from strtok to a new buffer using a function such as
/*
* Returns a copy of s in freshly allocated memory.
* Exits the process if memory allocation fails.
*/
char *xstrdup(char const *s)
{
char *p = malloc(strlen(s) + 1);
if (p == NULL) {
perror("memory allocation failed");
exit(1);
}
strcpy(p, s);
return p;
}
Don't forget to free the return values when you're done with them.
IMO, you don't need (and probably don't want) to use strtok at all (as in, "for this, or much of anything else"). I think I'd use code something like this:
#include <string.h>
#include <stdlib.h>
static char *make_str(char const *begin, char const *end) {
size_t len = end-begin;
char *ret = malloc(len+1);
if (ret != NULL) {
memcpy(ret, begin, len);
ret[len]='\0';
}
return ret;
}
size_t tokenize(char *tokens[], size_t max, char const *input, char const *delims) {
int i;
char const *start=input, *end=start;
for (i=0; *start && i<max; i++) {
for ( ;NULL!=strchr(delims, *start); ++start)
;
for (end=start; *end && NULL==strchr(delims, *end); ++end)
;
tokens[i] = make_str(start, end);
start = end+1;
}
return i;
}
#ifdef TEST
#define MAX_TOKENS 10
int main() {
char *tokens[MAX_TOKENS];
int i;
size_t num = tokenize(tokens, MAX_TOKENS, "This is a longer input string ", " ");
for (i=0; i<num; i++) {
printf("|%s|\n", tokens[i]);
free(tokens[i]);
}
return 0;
}
#endif
U can do something like this too.
int main ()
{
char str[] ="test string.";
char * temp1;
char * temp2;
temp1 = strtok (str," ");
temp2 = strchr(str, ' ');
if (temp2 != NULL)
temp2++;
printf ("Splitted string :%s, %s\n" , temp1 , temp2);
return
}

Resources