In this function I am going to be receiving char * words such as
person.vet.blah
and
word.friends.joe
I want to extract the first word. So for the first one I want to extract
person
and the second one I want to extract
word
How can I correctly do this? Here is my code:
char *separate_name(char *machine_name)
{
//iterate until you find period. then return
char absolute_name[1000];
int i;
for (i =0; i < strlen(machine_name); i++)
{
if (machine_name[i] == '.')
absolute_name[i] = machine_name[i];
}
return absolute_name;
}
This is just segfaulting. Any ideas what I should be doing? machine_name is going to be the "person.vet.blah" and then return absolute_name which would be "person"
Fixing your code
As others have pointed out, you can't use absolute_name outside of the function in which it was defined. This is because you're when you return the variable from your function, all that is being returned is a pointer to the beginning of the array. Outside the function, the array itself no longer exists, so the pointer is invalid and you get a segfault if you try and dereference it.
You can get around this by using malloc. Don't forget to free the memory you have allocated when you are done using it.
By the way, as well as changing your loop to a while, I also fixed the check (you were checking machine_name[i] == '.', the opposite to what you wanted).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *separate_name(char *machine_name)
{
// allocate memory on the heap
char *absolute_name = malloc(strlen(machine_name)+1);
int i = 0;
while (i < strlen(machine_name) && machine_name[i] != '.') {
absolute_name[i] = machine_name[i];
++i;
}
absolute_name[i] = '\0';
return absolute_name;
}
int main()
{
char name1[] = "person.vet.blah";
char *first1 = separate_name(name1);
if (first1 != NULL) {
printf("%s\n", first1);
free(first1);
}
char name2[] = "word.friends.joe";
char *first2 = separate_name(name2);
if (first2 != NULL) {
printf("%s\n", first2);
free(first2);
}
return 0;
}
A better alternative
strtok is the perfect tool for the job:
#include <stdio.h>
#include <string.h>
char *separate_name(char *machine_name)
{
return strtok(machine_name, ".");
}
int main()
{
char name1[] = "person.vet.blah";
char *first1 = separate_name(name1);
if (first1 != NULL) printf("%s\n", first1);
char name2[] = "word.friends.joe";
char *first2 = separate_name(name2);
if (first2 != NULL) printf("%s\n", first2);
return 0;
}
As pointed out in the comments (thanks #John), strtok modifies the string that is passed to it (it replaces the delimiter . by the \0 null byte to mark the end of the string). This isn't a problem here but is something to be aware of.
Output using either program:
person
word
#include <stdio.h>
char *separate_name(const char *machine_name){
static char absolute_name[1000];
int i;
for (i =0; i < sizeof(absolute_name)-1 ; i++){
if(machine_name[i] == '.' || machine_name[i] == '\0'){
absolute_name[i] = '\0';
break;
} else {
absolute_name[i] = machine_name[i];
}
}
return absolute_name;
}
int main(void){
printf("%s\n", separate_name("person.vet.blah"));
printf("%s\n", separate_name("word.friends.joe"));
return 0;
}
Related
I am currently developing a small program requires a function to return a string (character array), and two parameters which are (phrase, c). The 'phrase' is a string input and 'c' is the character which will be removed from the phrase. The left-over spaces will also be removed.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//This method has two parameters: (str, c)
//It will remove all occurences of var 'c'
//inside of 'str'
char * rmchr(char * str, char *c) {
//Declare result array
char *strVal = (char *) malloc(sizeof(char) * strlen(str));
//Iterate through each character
for (int i = 0; i < strlen(str); i++) {
*(strVal+i) = str[i];
//Check if char matches 'c'
if (strVal[i] != *c){
//Assign filtered value to new array
*(strVal+i) = str[i];
printf("%c", strVal[i]);
}
}
return strVal;
}
int main()
{
char * result = rmchr("This is a great message to test with! It includes a lot of examples!","i");
return 1;
}
Inside of the 'rmchr' function (if-statement), the array prints out exactly how I'd like to return it:
Ths s a great message to test wth! It ncludes a lot of examples!
The problem is that my return variable, 'strVal' isn't being modified outside of the if-statement. How can I modify the array permanently so my ideal output will be returned inside of 'result' (inside of main).
I see a few points to address. Primarily, this code directly copies the input string verbatim as it stands. The same *(strVal+i) = str[i]; assignment takes place in two locations in the code which disregards the comparison against *c. Without some secondary index variable j, it becomes difficult to keep track of the end of the receiving string.
Additional notes:
There is no free for your malloc; this creates a memory leak.
You return exit code 1 which indicates abnormal program termination. return 0 to indicate a normal exit.
Don't cast the pointer malloc returns; this can hide errors.
Validate malloc success and exit if it failed.
strlen() is a linear time operation that iterates through the entire parameter string on each call. Call it once and store the result in a variable to save cycles.
This code does not handle removal of extra spaces as required.
See the below sample for a possible implementation that addresses some of the above points:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *rmchr(char *str, char *c) {
int i = 0;
int j = 0;
int len = strlen(str);
char *result = malloc(sizeof(*result) * (len + 1));
if (result == NULL) {
fprintf(stderr, "out of memory\n");
exit(1);
}
while (i < len) {
if (str[i] != *c) {
result[j++] = str[i++];
}
else {
for (i++; i < len && str[i] == ' '; i++);
}
}
result[j] = '\0';
return result;
}
int main() {
char *result = rmchr("This is a great message to test with! It includes a lot of examples!", "i");
for (int i = 0; i < strlen(result); i++) {
printf("%c", result[i]);
}
free(result);
return 0;
}
Output:
Ths s a great message to test wth! It ncludes a lot of examples!
i compiled my piece of code and it worked fine using printf , but i want it to be returned without being printed ..
char *ft_strrev(char *str)
{
int i = 0;
while (str[i] != '\0')
{
i++;
}
while (i != 0)
{
i--;
}
return str;
}
int main ()
{
char *string;
string = "amrani";
ft_strrev(string);
}
The main thing here is to reverse the input entred ..
how can i exactly use return , to return the full char given to my var string , any tips ?
There are two approaches to doing this: make a new string and return it or mutate the parameter in place. Here's a new string version per your clarification comment. Note that memory is allocated for the new string and the caller is expected to free the result:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *ft_strrev(char *str)
{
int len = strlen(str);
char *reversed = malloc(sizeof(*reversed) * (len + 1));
reversed[len] = '\0';
while (*str != '\0')
{
reversed[--len] = *str++;
}
return reversed;
}
int main()
{
char *string = "amrani";
char *reversed = ft_strrev(string);
printf("%s\n", reversed);
free(reversed);
}
Note that many functions of this kind will include the length of the string as a second parameter so the function needn't call strlen.
This solution inverts the string in place.
#include <stdio.h>
#include <string.h>
char *ft_strrev(char *str)
{
int len = strlen(str);
for (int i = 0; i < len / 2; i++)
{
char temp = str[i];
str[i] = str[len - i - 1];
str[len - i - 1] = temp;
}
return str;
}
int main()
{
char string[] = "amrani";
ft_strrev(string); // return value of ft_strrev not used here
printf("%s", string);
}
Be aware of the difference betwween this:
char string[] = "amrani"; // string is an array of chars initialized with "amrani"
and this:
char *string = "amrani"; // string is a pointer to the string literal "amrani"
Modifying a string literal results in undefined behaviour, most likely some crash on modern platforms.
int *i;
ters_cevir(){
char *term=i;
char *som=i;
char som1;
while (*term != '\0') { term++; }
while (*som != '\0') {
som1=som*;
*term=som;
term--;
som++;
}
}
int main() {
char *isim=malloc(sizeof(char));
i=&isim;
printf("Reverse words=");
scanf("%s",isim);
printf("Kelimenizin tersi:\n ");
ters_cevir(); // When I call this, it must make the reverse one that make from memory
while (*isim != '\0') {
printf("%c",*isim);
isim++;
sayac++;
}
return 0;
}
Hi I have modified your code. Please see below also see my comments:-
void ters_cevir(char *isim){
char *term=isim;
//char *som=isim;
//char som1;
while (*isim != '\0') { isim++; }
while (*term != '\0') {
//som1=som*;
*--isim=*term++//isim was pointing to the null character so we are pre decrement that pointer and post decrement term
//here we are coping the string in reverse order in isim
//term--;
//som++;
}
}
int main() {
char *isim=malloc(50);//you need enough space to store a string. you have just allocated only one byte which was not enough
//i=&isim;
printf("Reverse words=");
scanf("%s",isim);
printf("Kelimenizin tersi:\n ");
ters_cevir(isim); // now it will work fine. Here you are passing the address of isim
while (*isim != '\0') {
printf("%c",*isim);
isim++;
sayac++;
}
return 0;
}
Your code does not compile because of syntax errors such as som1=som*;
You should pass the string as an argument to ters_cevir(); instead of a global variable i with an incorrect type int *.
After fixing these problems, ters_cevir() will still not achieve the expected result because it overwrites the string from the end with characters from the start, with an off by one error.
You could correct this by swapping characters at *som and *term, but be careful to stop when som >= term otherwise you will reverse the string twice.
Futhermore, the code in main is completely broken.
Here is a corrected version:
#include <stdio.h>
char *reverse(char *str) {
char *term = str;
char *som = str;
char c;
while (*term != '\0') { term++; }
while (som < term) {
term--;
c = *som;
*som = *term;
*term = c;
som++;
}
return str;
}
int main() {
char buf[128];
printf("String to reverse: ");
if (scanf("%127[^\n]", buf) == 1) {
printf("Reversed string: %s\n", reverse(buf));
}
return 0;
}
I am making a program that will search in an array of strings, and for each string, it will search for a specified char. If it finds that char, remove it. In this example I want to remove the character 'r'.
Here is the code:
void convertStrings(char **line) {
for (int str = 0; str < MAX_LINE_LENGTH; ++str) {
for (int ch = 0; ch < MAX_STR_LENGTH; ++ch) {
if (line[str][ch] == 'r') {
removeChar(line[str], 'r');
}
}
}
}
void removeChar(char *str, char c) {
int i = 0;
int j = 0;
while (str[i]) {
if (str[i] != c) {
str[j++] = str[i];
}
i++;
}
str[j]=0;
}
I am not sure if the algorithm for the removal of chars is correct, however the main mistake is elsewhere. More specifically, I get a segmentation fault in the line:
if (line[str][ch] == 'r') {
Why am I getting a seg fault? Also, is the algorithm for removeChar correct?
Here is my main function:
int main() {
char line[3][10] = {"pep", "rol", "rak"};
printf("%s\n", line[1]);
convertStrings(line);
printf("%s\n", line[1]);
return 0;
}
Thanks in advance.
This code works on my compiler :
#include<stdio.h>
#include<conio.h>
#define MAX_LINE_LENGTH 1024
#define MAX_STR_LENGTH 4
void removeChar(char *str, char c) {
int i = 0;
int j = 0;
while (str[i]) {
if (str[i] != c) {
str[j++] = str[i];
}
i++;
}
str[j]=0;
}
void convertStrings(char line[][MAX_STR_LENGTH]) { //change 1
for (int str = 0; str < MAX_LINE_LENGTH; ++str) {
for (int ch = 0; ch < MAX_STR_LENGTH; ++ch) {
if (line[str][ch] == 'r') {
removeChar(line[str], 'r');
}
}
}
}
int main() {
char line[3][MAX_STR_LENGTH] = {"pep", "rol", "rak"}; //change 2
printf("%s\n", line[1]);
convertStrings(line);
printf("%s\n", line[1]);
getch();
return 0;
}
It's because line[str][ch] doesn't exist for all the value you give to str and/or ch.
You should check the value of MAX_LINE_LENGTH and MAX_STR_LENGTH and be sure that they are right.
The seg fault may be because you are using the constants "MAX_LINE_LENGTH" and "MAX_STR_LENGTH" however there may have the line length or string length. I would use the length of the array for the variable str in the first for loop instead of "MAX_LINE_LENGTH" and the length of array[str] instead of "MAX_STR_LENGTH". Unless each array you are searching has "MAX_LINE_LENGTH" and each string has "MAX_LINE_LENGTH" you will get a set fault. Hope this helps!
EDIT: you can find the length of the array by dividing the size of the array and the size of the type of the element.
sizeof(array)/sizeof(array[0])
finding the size of the char pointer is basically the same process.
You are getting a segfault either because array line contains fewer than MAX_LINE_LENGTH string pointers, or because at least one of the pointed-to strings contains fewer than MAX_STR_LENGTH characters; more likely the latter.
Instead of assuming a fixed number of strings of fixed length, you would be better off passing the actual number of strings as an argument. Alternatively, you could add NULL as sentinel value at the end of the list.
Moreover, there is no reason whatever to assume that each string is a fixed length. Look for the terminating character ('\0') to recognize when you've reached the end. For example:
void convertStrings(char **line) {
for (char **l = line; *l != NULL; l += 1) {
for (int ch = 0; (*l)[ch]; ch += 1) {
if ((*l)[ch] == 'r') {
removeChar(*l, 'r');
}
}
}
}
Your removeChar() function looks ok.
Do note, however, that there are library functions that could help with this (e.g. strchr()), and that there are various efficiency improvements possible (such as passing to removeChar() only the string tail, starting at the first appearance of the character to remove).
You have the array
char line[3][10] = {"pep", "rol", "rak"};
When you pass it to a function, it gets converted into a pointer of type char(*)[10]. So change
void convertStrings(char **line) {
to
void convertStrings(char (*line)[10]) {
or
void convertStrings(char line[][10]) {
An array of arrays (2D array) cannot be converted to a pointer to a pointer(in this case, char**)
Another problem is that you mention that MAX_LINE_LENGTH is 1024 and MAX_STR_LENGTH is 4. This is wrong as the loop would iterate and you access invalid memory locations. You should make MAX_LINE_LENGTH as 3 and MAX_STR_LENGTH as 4 as there are 3 strings, each with 4 characters.
You can also pass these variables as parameters to the function convertStrings. Change add two more parameters in the declartion of convertStrings:
void convertStrings(char (*line)[10], int MAX_LINE_LENGTH, int MAX_STR_LENGTH) {
or
void convertStrings(char line[][10], int MAX_LINE_LENGTH, int MAX_STR_LENGTH) {
and call the function from main using
convertStrings(line, sizeof(line)/sizeof(*line), sizeof(*line)/sizeof(**line)); // `/sizeof(**line)` is 1 and is not needed
A better way would be to use
void convertStrings(int MAX_LINE_LENGTH, int MAX_STR_LENGTH, char line[][MAX_STR_LENGTH]) {
or
void convertStrings(int MAX_LINE_LENGTH, int MAX_STR_LENGTH, char (*line)[MAX_STR_LENGTH]) {
and call the function using
convertStrings(sizeof(line)/sizeof(*line), sizeof(*line)/sizeof(**line), line); // `/sizeof(**line)` is 1 and is not needed
so that you can avoid using the magic number 10 in your function.
You would've certainly got some warnings from your compiler. Pay attention to them. If you did not get warnings, crank up the warnings in your compiler and include warning flags ( like -Wall in GCC ).
BTW, You can look into the strchr function from string.h to find if a character exists in a string.
Why do you check if you encounter the 'r' character twice? (in both function)
checking once would be enough.
A function to detect the char, and a function to delete it?
I would have done it this way :
#include <string.h>
#include <stdio.h>
void convertStrings(char *line);
void removeChar(char *str);
int main(int argc, char *argv[]) {
if (argc == 2)
{
printf("%s\n", argv[1]);
convertStrings(argv[1]);
printf("%s\n", argv[1]);
}
return (0);
}
void convertStrings(char *line)
{
for (int i = 0; line[i] != '\0'; i++)
{
if (line[i] == 'r') removeChar(&(line[i]));
}
}
void removeChar(char *str)
{
int i;
i = 0;
while (str[i] != '\0')
{
str[i] = str[i + 1];
i++;
}
}
But here is another one solution with only one function :
void convertStringsbis(char *line)
{
int delta;
int i;
i = 0;
delta = 0;
while (line[i++ + delta] != '\0')
{
if (line[i + delta] == 'r')
delta++;
line[i] = line[i + delta];
}
}
My question is basically using printf print a char array.
In some cases, it prints the result out:
int main(int argc, char** argv) {
char* orig = "#reveals#?the treasure chest#$President Barack H. Obama#";
printf("The input: %s\n", orig);
printf("The output: %s\n", reArrange(orig));
return (EXIT_SUCCESS);
}
sometimes not:
int main(int argc, char** argv) {
char* orig = "#reveals#?the treasure chest#$President Barack H. Obama#";
printf("%s\n", reArrange(orig));
return (EXIT_SUCCESS);
}
Here is the complete code (the main function is included):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SUBJECT '$'
#define ACTION '#'
#define OBJECT '?'
#define END '#'
char* reArrange(char* orig) {
int origSize = strlen(orig);
char subject[origSize], action[origSize], object[origSize];
//int i;
//for(i = 0; i < origSize; i++) {
// subject[i] = ' ';
// action[i] = ' ';
// object[i] = ' ';
//}
int subjectIndex = 0, actionIndex = 0, objectIndex = 0;
int timesEndCharShowUp = 0;
char state;
int i;
for(i = 0; i < origSize; i++) {
char ch = orig[i];
if(ch == SUBJECT) {
state = SUBJECT;
}
else if(ch == ACTION) {
state = ACTION;
}
else if(ch == OBJECT) {
state = OBJECT;
}
else if(ch == END) {
if(timesEndCharShowUp == 3) {
break;
}
else {
timesEndCharShowUp++;
}
}
else {
if(state == SUBJECT) {
subject[subjectIndex++] = ch;
}
else if(state == ACTION) {
action[actionIndex++] = ch;
}
else if(state == OBJECT) {
object[objectIndex++] = ch;
}
}
}
subject[subjectIndex] = '\0';
action[actionIndex] = '\0';
object[objectIndex] = '\0';
char rearranged[origSize];
sprintf(rearranged, "%s %s %s.\0", subject, action, object);
//printf("%s\n", rearranged);
orig = rearranged;
return orig;
}
int main(int argc, char** argv) {
char* orig = "#reveals#?the treasure chest#$President Barack H. Obama#";
// printf("The input: %s\n", orig);
// printf("The output: %s\n", reArrange(orig));
printf("result: ");
printf("%s\n", reArrange(orig) );
//fflush(stdout);
return (EXIT_SUCCESS);
}
You are returning a pointer to memory that resides on the stack. rearranged is not available after the enclosing function (reArrange) returns and may contain garbage.
You may want to malloc rearranged or declare it globally.
Instead of only returning a char *, make reArrange() accept a buffer to which it can write the result. Now the caller must provide a suitable buffer to your function, and you have no problems with memory management anymore. You merely strncpy() arranged to the buffer. To be sure the buffer is large enough, the user should also provide the size of the buffer, in a 3rd argument:
char *rArrange(char *orig, char *result, int resultSize)
{
if (!result || resultSize == 0)
return NULL;
/* your code here */
strncpy(result, arranged, resultSize);
return result;
}
The alternative malloc() to store the result is not very user fiendly (the user must freemem() the buffer but may not be aware of this). Using a static/global buffer is not very thread-safe.
Your function needs two parameters:
char* reArrange(char* orig)
Should be:
char* reArrange(char *rearragned, char* orig) {
// make your magic here!
}
Calling sequence:
char input[SIZE];
char rearrange [SIZE];
// initialize everything! Don't forget to rearrange[0] ='\0\;!!!
rearrange(rearranged, input);
// do you printing....
You should also learn how to use pointers correctly and look up "switch".
The problem is that your function reArrange returns a pointer to memory that it no longer controls. The address of the rearranged array is returned. After the return occurs, this array effectively no longer exists -- the memory can, and will, be reused.
A quick hack which fixes your mistake is to declare rearranged as static. The long term fix is to learn how C works and code something using malloc() or an equivalent.
With char rearranged[origSize]; you created a new character array which goes out of scope once reArrange terminates. So during the lifetime of reArrange, rearranged is a pointer which points to something meaningful ; hence, orig = rearranged makes sense.
But once it goes out of scope, reArrange(orig) returns the pointer to rearranged which is a dangling pointer now rearranged does not exist anymore.
Are you sure that the following section of the code works?
char* reArrange(char* orig) {
int origSize = strlen(orig);
char subject[origSize], action[origSize], object[origSize];
i mean origSize has to be a const it can't be a dynamic value. You should use malloc for allocating apace for subject , action and object.
Moreover, you might consider a few guidelines:
1 Instead of:
for(i = 0; i < origSize; i++) {
char ch = orig[i];
if(ch == SUBJECT) {
state = SUBJECT;
}
You can have:
char ch;//declare char ch outside for loop
for(i = 0; i < origSize; i++) {
ch = orig[i];
if(ch == SUBJECT) {
state = SUBJECT;
}
2 you may like to use a switch statement instead of if, that will make your code look great.