I would like to write a function in C that truncates an input string to 32 chars, but the code below gives me a segmentation fault. Could anyone explain why it is so?
void foo (char *value){
if (strlen(value)>32) {
printf("%c\n", value[31]); // This works
value[31] = '\0'; // This seg faults
}
}
If you call your function like this:
char str[] = "1234567890123456789012345678901234567890";
foo(str);
It will work fine. But if you call it like this:
char *str = "1234567890123456789012345678901234567890";
foo(str);
That can cause a segfault.
The difference here is that in the former case str is a char array, while in the latter case str is a pointer to a string constant. A string constant typically lives in a read only section of memory, so attempting to modify it causes the core dump.
Your program should be something like this :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void foo(char **value) {
if (strlen(*value)>32) {
printf("%c\n", (*value)[32]);
(*value)[32] = '\0'; // You want the string length to be 32, so set 32th character to '\0' so 32 characters will be from 0 to 31
}
}
int main() {
char *str;
str = malloc(100); // Change 100 to max possible length of string user can enter
printf("Enter string : ");
scanf("%s", str);
foo(&str);
printf("Truncated string is %s\n", str);
free(str);
return 0;
}
Related
I want to check each individual char in a string. The string is stored in a pointer.
for some reason I can't, it only let me get the whole string.
here's my code:
int main() {
char *s=(char*)calloc(30,sizeof(char));
s="hello";
printf("%s",&s[2]);
return 0;
}
this code print "llo", i need only 1 char like "l" or "o".
anyone know how i can achieve it?
ty
Use the %c conversion specifier to print a sinlge character instead of %s to print a string.
Also the memory allocation by calloc() is useless, since the pointer to char s get assigned by the address of the first element of the string literal "hello" one statement later.
#include <stdio.h>
int main (void)
{
const char *s = "hello";
printf("%c", s[2]);
return 0;
}
Output:
l
Side Note:
Use the const qualifier to prevent any unintentional write attempts to the string literal that lead to undefined behavior.
If you want to allocate memory and assign/initialize the allocated memory by the string literal "hello", use strcpy() (header string.h):
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main (void)
{
char *s = calloc(30, sizeof(*s));
if (!s) // Check if allocation failed.
{
fputs("Error at allocating memory!", stderr);
exit(1);
}
strcpy(s, "hello");
printf("%c", s[2]);
return 0;
}
Output:
l
or you can use strdup() (Note: strdup() is not part of the standard C library) which will automatically allocate memory with the string of the string literal passed as argument initialized:
#include <stdio.h>
#include <string.h>
int main (void)
{
char *s = strdup("hello");
if (!s) // Check if allocation failed.
{
fputs("Error at allocating memory!", stderr);
exit(1);
}
printf("%c", s[2]);
return 0;
}
Side note:
"The string is stored in a pointer."
Something like that is not possible. The pointer points to the first element of the string (literal). The pointer does not store a string.
Having this:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
char *up(char *);
int main() {
char initstr[20];
printf("enter string\n");
fgets(initstr, 20, stdin);
char *str = up(initstr);
printf("%s\n", str);
}
char *up(char *in) {
char *ret;
for (ret = in;
*in != '\n';
*(ret++) = toupper(*(in++))
);
return ret;
}
Run it as:
$./a.out
enter string
abc
#only new line from `printf("%s\n",str);`
From debugger
Hardware watchpoint 3: in
Old value = 0x7fffffffdc20 "abc\n"
New value = 0x7fffffffdc21 "bc\n"
Hardware watchpoint 2: ret
Old value = 0x7fffffffdc20 "abc\n"
New value = 0x7fffffffdc21 "bc\n"
Hardware watchpoint 3: in
Old value = 0x7fffffffdc21 "bc\n"
New value = 0x7fffffffdc22 "c\n"
Hardware watchpoint 2: ret
Old value = 0x7fffffffdc21 "bc\n"
New value = 0x7fffffffdc22 "c\n"
...
I can see that both variables are reducing, but I wanted to change the ret inline, char by char. But at the end (after loop), the ret is reduced to nothing, and the program will only output \n. So how can I achieve this in the loop head?
EDIT:
Thanks to answer below, having in mind I have to return first address of pointer, I can implement loop_head-only function by this:
char *up(char *in){
char *ret;
size_t size=strlen(in);
for(ret=in;
*in!='\n';
*(ret++)=toupper(*(in++))
);
return (ret-size+1);
}
The bug in up is you increment ret all the way to the newline (\n) and return ret pointing to this character in the string. You should instead return a pointer to the initial character.
It is simpler to write this function using an index.
packing all the logic into the for clauses with an empty body is hard to read and error prone.
Note also that the string might not contain a newline, so it is safer to stop at the null terminator, the newline will not be changed by toupper().
Finally, you should not pass char values to toupper() because this function and all functions from <ctype.h> is only defined for values of type unsigned char and the special negative value EOF. On platforms where char is signed by default, the string might contain negative char values which may cause undefined behavior when passed to toupper(). Cast these as (unsigned char) to avoid this issue.
Here is a modified version:
#include <ctype.h>
#include <stdio.h>
char *up(char *s) {
for (size_t i = 0; s[i] != '\0'; i++) {
s[i] = toupper((unsigned char)s[i]);
}
return s;
}
int main() {
char initstr[20];
printf("enter string\n");
if (fgets(initstr, sizeof initstr, stdin)) {
char *str = up(initstr);
printf("%s\n", str);
}
return 0;
}
I wrote a function that cuts the string "hello world" to "hell" if a 'o' is found.
I keep getting a segmentation fault. I don't know where the mistake could be.
Could anyone help?
Thank you in advance.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* cutString(char* str, char del){
char *newstring =(char*) str;
malloc(sizeof(char)*strlen(str));
int i= 0;
for(; newstring[i]!='\0'&&newstring[i]!=del;i++);
if(i==strlen(newstring))
printf("not found");
else
newstring[i]='\0';
return newstring;
}
int main(){
cutString("Hello World",'o');
return 0;
}
There are two major problems with your code:
char *newstring =(char*) str makes newstring point to the old str. And since you pass a literal string (which is read only) you will have undefined behavior attempting to modify it.
malloc(sizeof(char)*strlen(str)); is a memory leak. And doesn't allocate space for the terminator.
The crash is probably because point one, when you attempt to modify the read-only string literal.
There are a number of problems in your code. The main problem is that you don't assign the return value from malloc to newstring. Besides that you need to malloc an extra byte for the string termination.
Further, your loop must copy characters from str into newstring.
In main you must assign the return value from the function to a char pointer variable to get hold of the new string.
Something like:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* cutString(char* str, char del){
char *newstring = malloc(strlen(str) + 1); // malloc into newstring
int i= 0;
while (newstring[i]!='\0' && str[i] != del) // Stop when a) no more chars in str or b) "del" is found
{
newstring[i] = str[i]; // Copy character from str to newstring
++i;
}
newstring[i]='\0'; // Terminate the string
return newstring;
}
int main(){
char* newstring = cutString("Hello World",'o'); // Save the returned value
printf("%s\", newstring);
free(newstring);
return 0;
}
newstring[i]='\0';
This line is invalid. Modifying string literals is undefined behavior. I would suggest check this out :segmentation fault when using pointer
A better solution would be to use arrays instead of pointers
I was trying to use strncpy and then strcpy and vice versa, but I kept receiving a segmentation fault during runtime. I thought this was because of an logical error in the functions, but I switched their places and only the first one would execute.
#include <stdio.h>
#include <string.h>
int main(void)
{
char c = ' ', sentence[50], *pointer_to_string;
pointer_to_string = &sentence[0];
int index = 0;
printf("Please enter a sentence:");
while ((c = getchar()) != '\n')
{
sentence[index] = c;
index++;
}
sentence[index] = '\0';
char *string_copy1, *string_copy2;
strncpy(string_copy1, pointer_to_string, 5);
printf("strncpy(string_copy1, pointer_to_string, 5):\n");
printf("%s\n", string_copy1);
strcpy(string_copy2, pointer_to_string);
printf("strcpy(string_copy2, pointer_to_string):\n");
printf("%s\n", string_copy2);
}
See documentation:
char *strcpy(char *dest, const char *src);
The first argument is a pointer to the destination buffer. But your pointers are not initialized:
char *string_copy1, *string_copy2;
Therefore, pointers contain some garbage values. And strcpy() writes to the memory that does not belong to your program. It causes segmentation fault.
Do
char string_copy1[50] = { 0 };
char string_copy2[50] = { 0 };
Filling them with zeros is neccessary to avoid problems with strncpy():
If there is no null byte among the first n bytes of src, the string placed in dest will not be null-terminated.
I am working on a initials project where you enter a name and it prints the initials. When I try and combine the strings it returns Segmentation fault instead of the initials.
#include <stdio.h>
#include <stdlib.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
int main(void) {
printf("Name: ");
string name = GetString();
printf("\n");
int length = strlen(name);
string initials = "";
int arraylength = length + 1;
char string[arraylength];
string[0] = toupper(name[0]);
int count = 1;
for(int l = 1;l<=length;l++) {
if(name[l] == ' ') {
l++;
count++;
string[l] = toupper(name[l]);
}
}
count++;
string[count] = '\0';
for(int c = 0;c<=count;c++) {
strcat(initials, &string[c]);
}
printf("%s\n", initials);
}
That's why a string type would cause confusion, you make a pointer to a single char. And you then pass it to strcat() that's simply wrong.
A string, as expected by strlen() or strcat() or all str* functions, is not simple a char pointer which is what the type string in your code is.
In c a c-string is actually a sequence of bytes with the last byte being '\0', and it's not optional. You create a pointer to a single char and that is not the same as a string that I just described.
Any of the str* functions will try to find the '\0' but since you passed the address of a stack variable which is not an array, the behavior is undefined when any of these functions try to increment and dereference the passed pointer.
When you do understand how strings work in c you would see that using strcat() for the concatenation of many chunks of a large string together is not very efficient, you would also know that you just need to append a single char and that you can by simply using index notation, like
char string[8];
string[0] = 'E';
string[1] = 'x';
string[2] = 'a';
string[3] = 'm';
string[4] = 'p';
string[5] = 'l';
string[6] = 'e';
string[7] = '\0'; // The very necessary terminator