array iteration strstr in c - c

I was wondering if it's safe to do the following iteration to find the first occurrence of str within the array or if there is a better way. Thanks
#include <stdio.h>
#include <string.h>
const char * list[] = {"One","Two","Three","Four","Five"};
char *c(char * str) {
int i;
for (i = 0; i < 5; i++) {
if (strstr(str, list[i]) != NULL) return list[i];
}
return "Not Found";
}
int main() {
char str[] = "This is a simple string of hshhs wo a char";
printf("%s", c(str));
return 0;
}

Yes it's "safe" in the sense that the above code will work and there's no easy way to break it .
A little fix-up however would be more robust:
Return const char* from c() so that the caller cannot modify the resulting strings. All those strings are constant.
Instead of the magic number 5, which would become invalid if the array changed, use sizeof(list)/sizeof(list[0]) to compute the number of elements in the list.

Related

c function convert "fffoootoo" to "foto" (leaves out following repeating characters)

The task would be to remove following characters that are repeating from a char array, like "deeeciddeee" -> "decide" or "phhhonne" -> "phone".
I have a function that crashes the console, and I can't spot the bug:
char* my_unique(char *first, char *last) {
char* ret=first;
for(int i=0; first+i!=last; i++){
if(first[i]==first[i+1]){
for(int j=i; first+j!=last; j++)
first[j]=first[j+1];
last--;
}
}
return ret;
}
it is called this way:
char* a="oooat";
a=my_unique(a, a+strlen(a));
cout<<a;
please help me!
Besides a small bug (you should add the line i--; after last--;, because you're deleting the character at possition i, so what has been the character at i+1 became the new character at possition i. If you don't decrease i, it will be increased and you jump over a character) the code runs perfectly fine IF it is called with
const char* b = "oooat";
char* a = new char[strlen(b) + 1];
for (size_t c = 0; c < strlen(a) + 1; c++) { a[c] = b[c]; }
a = my_unique(a, a + strlen(a));
cout << a;
delete[] a;
Notice that I've used a edit-able copy of the string, as the literal itself is of type const char* and therefor can't be changed at all. And as I said, this works perfectly fine and prints "oat", just as expected, without any crash. So your problem might be that you try to edit a const string literal? In that case you might consider to copy it, as I did, or use std::string (if you code in C++).
There are many beginner mistakes in the code.
Let me point you one by one.
char* a="oooat";
a=my_unique(a, a+strlen(a));
cout<<a;
When you declare a string like this : char* a="oooat", a is a string literal. The memory for the string is allocated into text section of the program. Which basically means you cannot modify the values inside the strings. You can only read from them. Hence when you are passing pointer a to the function and modifying it, it will result in segmentation fault(Illegal access to memory).
Why do you need a ret pointer here? char* ret=first;
You are passing a pointer and modifying the value inside it. Hence the new data will be reflected in the calling function and we need not return it explicitly. So, it is redundant.
Overall logic can be simplified as well
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MYSTR "ooooat"
void my_unique(char *first, char *last) {
int size = last - first;
int i = 0, j = 0, k = 0;
for (; i < size; i++, j++) {
first[j] = first[i];
// Continue to check how many repetitions are there
while (i + 1 < size && (first[i] == first[i+1])) i++;
}
// In the end terminate the string with a NULL.
first[j] = '\0';
return;
}
int main()
{
char a[] = MYSTR;
my_unique(a, a+strlen(a));
printf("%s", a);
return 0;
}
This is in C. There are simpler ways of doing this in C++, and the code can definitely be condensed but has been left simpler for readability.
#include <stdlib.h>
char* fix(char *input) {
char *lookahead = input;
char *newchar, *ret;
// Determine Max Return String Length
int len = 0;
while (*lookahead != '\0') {
len++;
lookahead++;
};
// allocate max possible memory needed and set the pointers
ret = malloc(len);
newchar = ret;
lookahead = input;
*newchar = *lookahead; // copy the first character
while (*lookahead != 0) {
lookahead++; // incrementing this ptr first starts lookahead at 2nd character and
// ensures the null terminator gets copied before the while loop ends
if (*newchar != *lookahead) { // only copy new characters to new return string
newchar++;
*newchar = *lookahead;
};
};
return ret;
};
I'll try to give my answer so that it makes the as little changes as possible to your original code, while using the simplest methods.
The main problem has already been identified by the previous comments - you cannot alter a string literal.
Also, the line of code
i--;
has to be placed as well, with the reason well clarified above.
While making an editable version of the string may be a good way of fixing the problem, a more straightforward way would be to make it a local string, as such :
char b[] = "oooat";
but doing this will make it incompatible with the return type of your my_unique function (char*). But why would you need a return type in the first place, if you are fixing the string itself?
My final code would look like this :
void my_unique(char *first, char *last) {
char* ret=first;
for(int i=0; first+i!=last; i++){
if(first[i]==first[i+1]){
for(int j=i; first+j!=last; j++)
first[j]=first[j+1];
last--;
i--;
}
}
}
making the function return void.
Hope this helps.

string reverse using recursion

can someone please tell me what is the problem in my code?
it is showing some strange output.
#include<stdio.h>
#include<string.h>
void reverse(char string[])
{
char b[200];
int t;
t = strlen(string);
if (t==1)
printf("%c",string[0]);
else
{
printf("%c",string[t-1]);
for (int i=0;i<t-1;i++)
b[i]=string[i];
reverse(b);
}
}
int main()
{
char a[200];
scanf("%s",&a);
reverse(a);
return 0;
}
If you had tried to use a debugger, you would see that t is going mad on second iteration. This is because after you have copied string into b you forgot to insert \0 symbol at the end (position with index t-1). This causes t become literally anything on the next iteration because of strlen() needs a null-terminating string and it results in an undefined behaviour as mentioned in docs:
The behavior is undefined if str is not a pointer to a null-terminated
byte string
So a quick fix is as folows:
...
for (int i=0;i<t-1;i++)
{
b[i]=string[i];
}
b[t-1] = '\0';
reverse(b);
...
And as already mentioned in comments by #LPs : change scanf("%s",&a); to scanf("%199s",a); (199 because we need to leave a space for '\0' at the end, thanks to #RoadRunner for noticing that)
Note: take a look at strncpy_s (if you use C11) and use it instead of that for loop:
printf("%c",string[t-1]);
strncpy_s(b, 200, string, t-1); // 200 because char b[200]
reverse(b);
or strncpy:
printf("%c",string[t-1]);
strncpy(b, string, t-1);
b[t-1] = '\0';
reverse(b);
Still another approach is not to copy:
else
{
string[t-1] = '\0'; // you don't need array 'b' at all
reverse(string);
}
And the simpliest way is just to use a loop:
for (int i = strlen(string) - 1; i >= 0; --i)
{
printf("%c", string[i]);
}
You mix up two approaches, i.e. recursive and loop, in one function. Further, for me it remains unclear whether you want to change the input string to a reverse order, or if you just want to print it out in reverse order.
Anyway, see a solution that provides loop bases reverse printing and recursion based reverse printing; hope it helps in understanding the steps the code such goes through:
#include <stdio.h>
#include <string.h>
void reverse_loop(char string[]) {
long i = strlen(string) - 1;
while (i >= 0)
printf("%c",string[i--]);
}
void reverse_recursive (char string[]) {
if (string[0] != '\0') {
reverse_recursive(&string[1]);
printf("%c", string[0]);
}
}
int main()
{
char a[200] = { "some test string" };
reverse_recursive(a);
return 0;
}
The easiest way to reverse a string using recursion is like this:
// C++ program to reverse a string using recursion
# include <stdio.h>
# include<string>
using namespace std;
string in="";
/* Function to print reverse of the passed string */
void reverse(char *str)
{
if (*str)
{
reverse(str+1);
in=in+*str; /* If you want to save the reversed string */
printf("%c", *str); /*If you just want to print the reversed string */
}
}
/* Driver program to test above function */
int main()
{
char a[] = "Reversing a string using recursion";
reverse(a);
printf("\n%s\n",in.c_str());
return 0;
}
/* output : noisrucer gnisu gnirts a gnisreveR */
Explanation:
Recursive function (reverse) takes string pointer (str) as input and calls itself with next location to passed pointer (str+1). Recursion continues this way, when pointer reaches ‘\0’, all functions accumulated in stack print char at passed location (str) and return one by one.
Time Complexity: O(n)

How to pass array from library in c

I'm new in c programming and I want to pass array from library.
I have function in library c file that creates char array. How to use this array in main function. This is short code of something I tried:
libfile.c
char *myArray;
void PopulateArray()
{
// Getting data from serial port in char buffer[100]
myArray = buffer;
}
libfile.h
exter char *myArray;
void PopulateArray();
program.c
int main()
{
// in fore loop
printf("%s\n" , myArray[i]);
}
This is just one of combinations that I have tried but nothing works.
How to do this?
To pass an array from a library function to the surrounding code, you can use the return value of a function or use a pointer-to-pointer argument.
See the following example code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* createSourceCopy() {
const char *source = "Example Text";
// We got some text in variable source;
const size_t sourceSize = strlen(source);
char *result = (char*)malloc(sizeof(char)*(sourceSize+1));
strncpy(result, source, sourceSize);
return result;
}
A user of your library could use the function like this:
main() {
char *result = createSourceCopy();
// Do something with result.
// After the use, destroy the array
delete[] result;
return 0;
}
Another way how to pass an array is this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
bool copySourceText( char **outText ) {
const char *source = "Example Text";
// We get some text in variable source;
const size_t sourceSize = strlen(source);
*outText = new char[sourceSize];
strncpy(*outText, source, sourceSize);
return true; // success
}
This second variant has the benefit that the return value can be used as status. The function could return true on success, or false if there was an error.
This second version can be used like this.
int main() {
char *result;
if (copySourceText(&result)) {
// Do something with result.
// After the use, destroy the array
free(result);
result = NULL;
} else {
// Error handling
}
return 0;
}
It's not clear exactly what's going wrong in the code you posted (it would help to see more code), but assuming your problem isn't a compilation error, one of these lines might be wrong:
char *myArray;
printf("%s\n" , myArray[i]);
char *myArray declares a pointer to char (which would be appropriate for a single string).
The printf line dereferences myArray (producing a char, i.e. one character). You're passing down a char, but the %s format expects a pointer-to-char.
If you want to print the string character-by-character, you could use %c:
for (i = 0; i < length; i++) {
printf("%c\n", myArray[i]); /* or %x or %d if you want */
}
Otherwise, if myArray is one string and is null-terminated (see Why is a null terminator necessary?), then you could do:
printf("%s\n" , myArray); /* [i] removed, no for loop necessary */

C function to capitalize first letter of words in an array

I'm pretty new to C and am hitting a wall when creating the below function. I want to use this function to make the first letter of a word upper case for a static character array (char string[]. It looks ok to my eye, but I'm getting some syntax errors which are probably pretty basic.
compiler errors:
error: invalid conversion from const char' toconst char*'
initializing argument 1 of `size_t strlen(const char*)'
assignment of read-only location
void Cap(char string[]){
int i;
int x = strlen(string);
for (i=1;i<x;i++){
if (isalpha(string[i]) && string[i-1] == ' '){
// only first letters of a word.
string[i]= toupper(string[i]);
}if (isalpha(string[0]))
{
string[0]=toupper(string[0]);
}
}
}
you might want to run strlen(string) - as strlen(string[i]) is trying to get the length of a single char.
I will also point out your braces don't match ...
if (isalpha(string[i])){
string[i]= toupper(string[i]);
Remove brace on the if line or put a close brace after your assigning statement.
I took your code and tried to compile it. Well, it would be nice to see compilable code the next time. Here is one with comments.
#include <stdio.h> // Now I am able to use printf.
#include <string.h> // I was not able to use strlen without this...
void Cap(char string[]){
int i;
int x = strlen(string); // You want to get the length of the whole string.
for (i=1;i<x;i++){
if (isalpha(string[i]) && string[i-1] == ' '){
// only first letters of a word.
string[i]= toupper(string[i]);
}
}
}
main(){
char string[] = "text with lowercase words.";
Cap(string);
printf("%s",string);
};
Still the first word of the text is lowercase. This is a task for you.
You're missing the closing curly brace for your if statement. This might just be a typo in the question, but mentioning it just in case.
Your function is declared void. This means it returns nothing. Any return statement should have nothing after the word since the function returns nothing, and in many cases you won't have a return statement at all.
However, the biggest issue is that this isn't an array of strings. It's an array of chars, which is just one string. char* string and char string[] both (potentially) refer to an array of characters, which makes up a single string. You would need to use another level of indirection to refer to an array of array of characters: char** strings, char* strings[], or char strings[][]. The last form would require you specify how long all the strings could be, so you'd usually only use the first two.
The problem here is that you are passing in a single string, not an array of strings.
Basically in C, a string is an array of chars, hence an array of strings is a two dimensional array like so:
const char* strings[];
There are a few other issues with the code. You haven't initialized i before using it.
A alternate approach: (write a function)
1) (optional) Allocate memory for new buffer of same length for results in calling function.
2) In function - Set first char of new string to upper case version of original string
3) Walk through the string searching for spaces.
4) For each space, Set next char of new string to upper case of char in original string
5) Loop on 4) until NULL detected
6) Free any allocated memory in calling program.
Code example:
void capitalize(char *str, char *new)
{
int i=0;
new[i] = toupper(str[0]);//first char to upper case
i++;//increment after every look
while(str[i] != '\0')
{
if(isspace(str[i]))
{
new[i] = str[i];
new[i+1] = toupper(str[i+1]);//set char after space to upper case
i+=2;//look twice, increment twice
}
else
{
new[i] = str[i];//for no-space-found, just copy char to new string
i++;//increment after every look
}
}
}
This should work just fine.
#include <stdio.h>
#include <string.h>
capital(char s[])
{
int i;
for(i=0; i<strlen(s); i++)
{
if (i==0||s[i-1]==' '&&s[i]>='a'&&s[i]<='z')
s[i]=toupper(s[i]);
}
puts(s);
}
main()
{
char s[100];
printf("Enter a line: ");
gets(s);
capital(s);
}
I made an update based on Stefan Bollmann answer:
#include <string.h>
#include <stdio.h>
char* uc_words(char string[])
{
int i;
int x = strlen(string);
int counter = 0;
for (i = 0; i < x; i++)
{
// If found a white-space reset counter
if (isspace(string[i]))
counter = 0;
// Check if first character in word
if (isalpha(string[i]) && !isspace(string[i]) && counter == 0)
{
string[i]= toupper(string[i]);
counter = 1;
}
}
return string;
}
int main()
{
char string[] = "hello world";
printf("%s\n", uc_words(string));
return 0;
}

Want to pass a single char pointer from a double pointer

I have to write a function which takes in 2 double pointers (both to char type). The first double pointer has a string of query values and the 2nd one has stopwords. The idea is to eliminate the stopwords from the query string and return all the words without those stopwords.
For example
Input - query: “the”, “new”, “store”, “in”, “SF”
stopwords: “the”, “in”
OUTPUT
new
store
SF
I have written the following code while trying to use strtok which takes in only single pointers to char types. How do I access the contents of a double pointer?
Thanks
#include <stdio.h>
void remove_stopwords(char **query, int query_length, char **stopwords, int stopwords_length) {
char *final_str;
final_str = strtok(query[0], stopwords[0]);
while(final_str != NULL)
{
printf("%s\n", final_str);
final_str = strtok(NULL, stopwords);
}
}
For simplicity's sake, you can assume a double pointer to be equivalent to a 2d array (it is not!). However, this means that you can use array-convention to access contents of a double pointer.
#include <stdio.h>
#include <string.h>
char *query[5] = {"the","new","store","in","SF"};
char *stopwords[2] = {"the","in"};
char main_array[256];
void remove_stopwords(char **query,int query_length, char **stopwords, int stopwords_length);
int main()
{
remove_stopwords(query,5,stopwords,2);
puts(main_array);
return 0;
}
void remove_stopwords(char **query,int query_length, char **stopwords, int stopwords_length)
{
int i,j,found;
for(i=0;i<query_length;i++)
{
found=0;
for(j=0;j<stopwords_length;j++)
{
if(strcmp(query[i],stopwords[j])==0)
{
found=1;
break;
}
}
if(found==0)
{
printf("%s ",query[i]);
strncat(main_array,query[i],strlen(query[i]));
}
}
}
Output: new store SF newstoreSF
#Binayaka Chakraborty's solution solved the problem but I thought it might be useful to provide an alternative that used pointers only and showed appropriate use of strtok(), the use of which may have been misunderstood in the question.
In particular, the second parameter of strtok() is a pointer to a string that lists all the single-character delimiters to be used. One cannot use strtok() to split a string based on multi-character delimiters, as appears to have been the intention in the question.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void remove_stopwords(char *query, char **stopwords) {
char *final_str = strtok(query, " ");
while(final_str != NULL) {
int isStop = 0;
char **s;
for (s = stopwords; *s; s++) {
if (strcmp(final_str,*s) == 0) {
isStop = 1;
}
}
if (!isStop) printf("%s ", final_str);
final_str = strtok(NULL, " ");
}
}
int main() {
const char *q = "the new store in SF";
char *query = malloc(strlen(q)+1);
/* We copy the string before calling remove_stopwords() because
strtok must be able to modify the string given as its first
parameter */
strcpy(query,q);
char *stopwords[] = {"the", "in", NULL};
remove_stopwords(query,stopwords);
return 0;
}
The approach shown here also avoids the need to hard code the sizes of the arrays involved, which therefore reduces potential for bugs.

Resources