I'm new to C and am trying to write a simple function that can take in a string (or array of characters) and convert its case based on the following rules:
The first character should be uppercase.
The remaining characters should be lowercase.
I've written code, but I'm running into segmentation fault errors, and I'm baffled as to what's going wrong. Here's what I've written:
void myFunction(char name[]) {
printf("Before: %s", name);
name[0] = toupper(name[0]); // This line seems to cause problems.
// Convert the other letters to lowercase if they aren't already.
for(int i = 1; name[i] != '\0'; i++) {
if(islower(name[i])) {
name[i] = tolower(name[i]);
} else {
name[i] = name[i];
}
}
name[i] = '\0';
printf("After: %s", name);
}
void my_caller(*name1) {
printf("Name before changing case: %s\n", name1);
myFunction(name1);
printf("Name after changing case: %s\n", name1);
}
// In another .c file.
int main() {
char name1[] = "adam";
my_caller(&name1);
}
In myFunction, if I comment out the lines except for
name[0] = toupper(name[0]);
I still get the segmentation fault. So that would suggest that this line is (one of) the culprits, but I don't understand why. I want to convert the letter to uppercase and put it back into the string.
To start with, having a function definition like
void my_caller(name1)
is problematic, as missing type (used to be, now obsolete rule) default to int. You want this to be a char *. not int.
You need to change it to
void my_caller(char * name1) {....
Moreover, you need to call the function as my_caller(name1);, passing an array is the same as passing a pointer to the first element of the array.
Also, you don't pass the address of the array (check the types if you're in confusion) while calling the function.
That said, inside myFunction(), the scope of i is limited to the for loop only, but you want to use that beyond the scope (to null-terminate), so you got to declare i in the function block scope.
Moral of the story: Turn up the compiler warning / error settings, and pay close attention to the messages emitted by the compiler. They are there for a reason.
Note: After making these changes, code works as expected.
Related
I've figured this out but I thought I might post it here in case it should help someone else.
So I have this code which reads an arbitrary about of data from a file and prints out the first string it finds (terminated by null). It appears to work fine if I use the code directly in the function, but returning the string always seems to result in a bus error if I use the string after capturing the return value.
static char *read_string(FILE *obj_file, off_t offset, size_t size) {
char *strraw = load_bytes(obj_file, offset, size);
char* str = malloc(size);
strcpy(str, "");
for (int i = 0; i < size; i++) {
if (strraw[i] == '\0') {
strncpy(str, strraw, i + 1);
break;
}
}
free(strraw);
return str;
}
Elsewhere:
char *string = *read_string(obj_file, absoluteOffset, 1024);
printf(" The String: %s\n", string);
free(string);
If I comment out the printf it runs fine, but if I attempt to use it I get that bus error. This function is following a similar design for another function I made which does similar string work just without reading anything from a file.
The problem in the question above is that function called below was prefixed with a *.
This resulted in the returned value being dereferenced (which was not my intention), the dereference of the returned value resulted in only a single character being returned which caused the bus error when it was attempted to be used with printf which expected a null terminated string but it only received a single character.
The way this function should have been called is without the * as shown below.
char *string = read_string(obj_file, absoluteOffset, 1024);
printf(" The String: %s\n", string);
free(string);
I am writing a small program to get familiar with C again.
I have now a part of the program where I am stuck and can not go forward. I have a function where I create a c string and a pointer to the 2nd element of that string. (When it is finished it should receive a pointer to another string)
When I pass this strings to another function which should remove some elements on the first one I always get a segmentation fault. Which should mean, that I can't access that memory. But, if I change the order I pass the strings to the function I get the same error... .
Here is the code:
int analyze_sudoku(const void *self, Sudoku *sudoku) {
for(int i = 1; i < 82; i++)
{
int success = 0;
// All possible values of a column
// This can be rewritten of course but this way
// it makes the intention what this var is for
// very clear in my opinion
char options[10] = {'1','2','3','4','5','6','7','8','9'};
char *chars_in_row;
// The same problem...
// chars_in_row = sudoku->get_row_for_column(sudoku, i);
chars_in_row = &options[2];
printf("In field %d we have this chars in the row: %s\n", i,chars_in_row);
printf("length der chars: %d\n", strlen(chars_in_row));
printf("addresse of the char pointers: %p\n", (void *)chars_in_row);
// After receiving all chars from one row, we remove
// those from the one we have in our options
// HERE IS THE FUNCTION CALL
remove_from_options(options, chars_in_row);
// ... more code follows
}
}
And here is the function where I get my seg fault:
char *remove_from_options(char *options, char *already_in_use) {
puts("Welcome");
printf("Your options: %s\n", options);
// HERE THE SEG FAULT HAPPENS
// as already mentioned the error happens no matter what I give this function
printf("pointer address: %p", (void *)already_in_use);
printf("already in use: %s", already_in_use);
printf("in use länge: %d", strlen(already_in_use));
for(int i = 0; i < strlen(already_in_use); i++)
{
// some code...
}
}
This
char options[10] = {'1','2','3','4','5','6','7','8','9'};
is not a string but array of characters. In C language, strings are actually one-dimensional array of characters terminated by a null character '\0'.
The %s format specifier, in printf(), writes every byte up to and not including the first null terminator. Since the char array option does not have the null character, the printf() must be accessing beyond the size of option array which is leading to segmentation fault.
Try adding the null character at the last of option array, like this:
char options[10] = {'1','2','3','4','5','6','7','8','9','\0'};
EDIT
I totally missed the point that the last index of array option has been initialized with 0. There is no need to explicitly give the null character at the end of option array. OP has accepted this as the answer because this, somehow, resolve the OP's problem. Hence, I can not delete this post. Minimal complete and verifiable example is required to identify the root cause of the problem mentioned by OP.
I'm writing a program that should get its inputs from a text file by using input redirection in a function called GetInput. (The text file contains 10 words.) The code should then be able to print the contents of ListWord in the Print function.
This is what I have so far.
I keep on getting errors while trying to run this code. I tried to remove * before ListWord and the code works but it does not retain the word (string) that was stored in it. But removing * before ListWord does not make sense to me. What am I doing wrong?
void GetInput( char** ListWord)
{
int i=0;
char word[30]; //each word may contain 30 letters
*ListWord = malloc(sizeof(char*)*10); //there are 10 words that needs to be allocated
while(scanf("%s", word)==1) //Get Input from file redirection
{
*ListWord[i]= (char *)malloc(30+1);
printf("%s\n", word); //for checking
strcpy(*ListWord[i], word);
printf("%s\n", *ListWord[i]); //for checking
i++;
}
}
void Print(char *ListWord)
{
//print ListWord
int i;
for (i=0; i<10; i++)
{
printf("%s", ListWord[i]);
}
}
int main()
{
char * ListWord;
GetInput(&ListWord);
printf("%s\n", ListWord[0]);
Print(ListWord);
free(ListWord);
return 0;
}
(Note: This is a homework. Thank you and sorry if it's unclear)
Due to *operator precedence the expression *ListWord[i] doesn't do what you think it does. In fact you should be getting errors or warnings from the code you have.
The compiler thinks that *ListWord[i] means *(ListWord[i]), which is not right. You need to use (*ListWord)[i].
Unfortunately that's only the start of your problems. A bigger problem is that the pointer you pass to the function GetInput is not a pointer to what could become an array of strings, but a pointer to a single string.
For a dynamic allocated array of strings, you need a pointer to a pointer to begin with, and then emulate pass-by-reference on that, i.e. you need to become a three star programmer which is something you should avoid.
Instead of trying to pass in the array to be allocated as an argument, have the GetInput return the array instead. Something like
char **GetInput(void)
{
// Allocate ten pointers to char, each initialized to NULL
char **ListWords = calloc(10, sizeof(char *));
if (ListWords == NULL)
return NULL;
char word[31];
for (int i = 0; i < 10 && scanf("%30s", word) == 1; ++i)
{
ListWords[i] = strdup(word);
}
return ListWords;
}
The above code adds some security checks, so you will not go out of bounds of either the temporary array you read into, or the ListWords array. It also makes sure the ListWords array is initialized, so if you read less then 10 words, then the remaining pointers will be NULL.
Of course you need to change your main function accordingly, and also your Print function, because now it only takes a single string as argument, not an array of strings. You also of course need to free every single string in the array because freeing the array.
First of all I apologize, this is probably a simple question but I'm not very well versed in any coding. For this code, I need to use pointer syntax and define my own function to reverse a string. I'm not allowed to use strlen() in this situation. I've tried playing around with the pointers, but I always get the following errors:
incompatible type when assigning to type char[15] from type char
(I have to write this in pico, so I'm not exactly sure what line number it refers to. It appears to be somewhere around the point I call the strcmp() function
assignment makes integer from pointer without cast
(This one appears to be when I define the s pointer in the function or around there)
Any and all help/troubleshooting ideas would be much appreciated. I'm using a gcc compiler, if that matters
#include<stdio.h>
#include<string.h>
char revcheck(char String[15]);
int main(void)
{
char String[15];
printf("Enter a string: \n");
scanf(" %s", String);
if (strcmp(String, "ENGR-awesome"))
{
printf("That's Right!");
}
else
{
String = revcheck(String);
}
return 0;
}
char revcheck(char String[15])
{
char Letter, *end, *s;
end = strchr(String, '\0');
s = String;
while (end > s)
Letter = &end;
*end = *s;
*s = Letter;
end--;
s++;
return 0;
}
Your revcheck() returns a char. You are trying to assign that to a char[].
You should have your revcheck() return a char*:
char* revcheck(char String[15]);
First you should bear in mind that C-string is an array of chars, and can be represented as char*, a pointer to this array. So, revcheck should not return char. This is the string where the compiler gives the error:
String = revcheck(String);
revcheck can reverse the string in the String array itself (in place) without returning anything. (You can count the len yourself and then swap elements.)
So I'm not very good with C but I'm designing a GLUT application that reads in a file that is not case sensitive. To make it easier I want to convert my strings to all lower case. I made a function makeLower that is modifying a variable that was passed in by reference.
I have a While Loop in the method makeLower that seems to get through part of the first iteration of the while loop and then the EXE crashes. Any tips would be great, thanks!
Output:
C:\Users\Mark\Documents\Visual Studio 2010\Projects\Project 1\Debug>"Project 1.e
xe" ez.txt
Line is #draw a diamond ring
Character is #
Then error "project 1.exe has stopped working"
Code:
void makeLower(char *input[]){
int i = 0;
printf("Line is %s\n", *input);
while(input[i] != "\0"){
printf("Character is %c\n", *input[i]);
if(*input[i] >= 'A' && *input[i] <= 'Z'){
*input[i] = tolower(*input[i]);
}
i++;
}
}
int main(int argc, char *argv[]) {
FILE *file = fopen(argv[1], "r");
char linebyline [50], *lineStr = linebyline;
char test;
glutInit(&argc, argv);
while(!feof(file) && file != NULL){
fgets(lineStr , 100, file);
makeLower(&lineStr);
printf("%s",lineStr);
//directFile();
}
fclose(file);
glutMainLoop();
}
I see more problems now, so I extend my comments to an answer:
You allocate an array of 50 characters, but tell fgets to get up to 100 characters, which might be fatal as fgets will overwrite memory not in the string.
When passing a C string to a function, you don't have to pass the address of the pointer to the string (&lineStr), the actual pointer or array is okay. This means you can change the makeLower function to void makeLower(char *input) or void makeLower(char input[]). Right now the argument to makeLower is declared as an array or char pointers, not a pointer to an array of char.
In the new makeLower I proposed above, you can access single characters either as an array (input[i]) or as a pointer plus offset (*(input + i). Like I said in my comment, the last version is what the compiler will probably create if you use the first. But the first is more readable so I suggest that.
Also in makeLower you make a comparison with "\0", which is a string and not a character. This is almost right actually: You should use input[i] != '\0'.
And finally this is how I would implement it:
void makeLower(char *input)
{
while (*input != '\0') /* "while (*input)" would also work */
{
*input = tolower(*input);
input++;
}
}
A few explanations about the function:
All char arrays can be converted to a char pointer, but not the other way around. Passing char pointer is the most common way to pass a string actually, as you can see from all standard functions that accepts strings (like strlen or strcpy.)
The expression *input dereferences (i.e. takes the value of what a pointer points to) the string. It is the same as *(input + 0) and so get the value of the first character in the string.
While the first character in the string is not '\0' (which technically is a normal zero) we will loop.
Get the first character of the string and pass it to the tolower function. This will work no matter what the character is, tolower will only turn upper case characters to lower case, all other characters will be returned as they already were.
The result of tolower copied over the first character. This works because the right hand side of an assignment must be executed before the assignment, so there will not be any error or problem.
Last we increase the pointer by one. This will make input point to the next character in the string. This works because input is a local variable, so operations on the pointer will not affect anything in the calling function.
This function can now be called like this:
char input[100];
fgets(input, sizeof(input), stdin);
printf("before: \"%s\"\n", input);
makeLower(input);
printf("after : \"%s\"\n", input);
Did you try while(*input[i] != "\0") instead of what you have ? For some reason you seem to pass to your function a pointer to pointer to char (*input[]) and &lineStr so it would make sense to dereference twice when you check for string terminator character "\0"....
Just a thought, hope it helps
I think the problem is that you don't know that the string is going to equal '\0' when you want it to. So you may be going out of bounds which is very likely that you don't know the length of the string.
As far as I understand things, it's fine to pass '\0' to tolower(). It's a valid unsigned char value, and tolower() simply returns the input character if it is not able to do any conversion.
Thus, the loop can be succinctly put as:
while(input[i] = tolower(input[i]))
++i;
This does one more call to tolower(), but it's shorter and (imo) quite clear. Just wanted to mention it as an alternative.