I have tried solving an exercise where we have to return a struct containing the first whitespace-separated word and its length of a given string. Example: "Test string" returns {"Test", 4}.
To solve this problem I have implemented the following function:
struct string whitespace(char* s){
char* t = s;
size_t len = 0;
while(*t != ' '){
len++;
t++;
}
char out[len+1];
strncpy(out, s, len);
if(len>0){
out[len] = '\0';
}
//printf("%d\n",len);
struct string x = {out, len};
return x;
}
with the struct defined as follows:
struct string{
char* str;
size_t len;
};
If I run the following main function:
int main(){
char* s = "Test string";
struct string x = whitespace(s);
printf("(%s, %d)\n", x.str, x.len);
return 0;
}
I get this output:
(, 4)
where when I remove the comment //printf("%d\n",len); I get:
4
(Test, 4)
In fact, the string (Test, 4) is output whenever I print out a given variable in the function whitespace(char* s). Also when using different gcc optimization flags such as -O3 or -Ofast the result is correct even without the printing of the variables in the function.
Did I bump into some kind of undefined behavior? Can somebody explain what is happening here?
The struct you're returning includes a char *, which you point to the local variable out. That variable goes out of scope when the function returns, so dereferencing that pointer invokes undefined behavior.
Rather than using a VLA, declare out as a pointer and allocate memory for it to point to. Then you can safely set the struct member to that address and the memory will be good for the duration of the program.
char *out = malloc(len+1);
Also, be sure to free this memory before exiting your program.
Related
I am new to C. Was writing this so it takes the strings from the passed array and makes it a single sentence. But I got this error, I am not good with arrays in C. I can use some help from you guys. I did search an answer for this and couldn't find.
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char smash(char arr[20][20]) {
char tmp[sizeof(arr)/sizeof(arr[0])];
for (int i=0; i < sizeof(arr)/sizeof(arr[0]); i++) {
strcat(tmp, arr[i]);
strcat(tmp, " ");
}
return tmp;
}
int main(){
char list[][6] = {"hello", "world"};
printf("%s", smash(list[]));
}
Error
error: expected expression before ']' token
printf("%s", smash(list[]));
^
There are quite a number of errors in this small piece of code.
First, to address the compiler error: list[] is not a valid expression. If you want to pass list to the function, leave the braces out:
printf("%s", smash(list));
This will then bring up another error. The function is expecting a char [20][20] as it's argument, but that's not what you're passing in. Since arrays as parameters are converted to a pointer, the argument type is actually char (*)[20] i.e. a pointer to an array of char of size 20. Note also that this conversion only occurs for the outermost array dimension, not all.
Since you're passing in a char [2][6] which gets converted to a char (*)[6] this is a type mismatch. So change the parameter to char arr[][6].
Then you're attempting to get the size of the array parameter inside of the function:
sizeof(arr)/sizeof(arr[0])
Since arrays cannot be directly passed to a function due to the conversion mentioned earlier, arr is actually a pointer and not an array, so you won't get the result you expect from this. You'll need to pass the number of array elements as a separate parameter.
Then you're calling strcat on tmp. This function will only work if the destination already has a null terminated string in it. Since tmp was not initialized or written to prior to the first call to strcat, you end up reading uninitialized bytes and potentially past the end of the array which will trigger undefined behavior.
This can be fixed by setting the first byte of the array to 0 before the loop to make it an empty string:
tmp[0] = 0;
for ...
Then there's the problem with the return type. The function is declared to return a char but you're giving a char * to the return statement, and at the point the function is called it is passed to printf where the %s format specifier is expecting a char * parameter.
So change the return type of the function from char to char *.
Finally, you're returning a pointer to a local variable in the function. This variable's lifetime ends when the function returns, so the returned pointer is invalid and using it will also trigger undefined behavior.
You'll need change tmp to a pointer and dynamically allocate memory for it using malloc. This also means you'll need to save the return value of the function in a separate variable which you can then pass to printf to print and then pass to free to free the memory.
After making all this changes, the resulting code should look like this:
char *smash(char arr[][6], int len) {
// enough for len strings plus len spaces
char *tmp = malloc(sizeof(arr[0]) * len + len + 1);
tmp[0] = 0;
for (int i=0; i < len; i++) {
strcat(tmp, arr[i]);
strcat(tmp, " ");
}
return tmp;
}
int main(){
char list[][6] = {"hello", "world"};
char *result = smash(list, sizeof(list)/sizeof(list[0]));
printf("%s", result);
free(result);
return 0;
}
I've been trying to change upper case letters to lower case letter using pointers but I keep getting segmentation faults. Here is my source code:
#include <stdlib.h>
#include <string.h>
char *changeL(char *s);
char *changeL(char *s)
{
char *upper = s;
for (int i = 0; upper[i] != '\0'; i++)
{
if (upper[i] >= 'A' && upper[i] <= 'Z')
{
upper[i] += 32;
}
}
printf("%s\n", upper);
return upper;
}
int main()
{
char *first;
char *second;
first = "HELLO My Name is LoL";
printf("%s\n", first);
second = changeL(first);
printf("There is no error here\n\n");
printf("%s\n", second);
return 0;
}
Using gdb I found the seg fault to be in "upper[i] += 32;". I don't understand why the seg fault is there.
"HELLO My Name is LoL" is the constant memory. You can`t change it. However you pass pointer to this memory(first) to a function which tries to change it. Thus you got segmentation fault. You should copy this string to memory butffer. Like
char buffer[] = "HELLO My Name is LoL";
and then pass buffer to changeL
A couple of notes in addition to what #Alex correctly points out in his answer. First
char *changeL(char *s);
char *changeL(char *s)
{
....
}
There is no need for a prototype before the function if the function is one line below. A prototype is used to inform code below it that the function described by the prototype exists and is defined elsewhere. If you define the function immediately below the prototype it makes the prototype irrelevant.
Second as noted in Alex's answer, on a overwhelming majority of systems, a String Literal, e.g. the "Something Here" in char *s = "Something Here"; is immutable and resides in read-only memory and any attempt to modify the string literal generally results in a SegFault.
Instead you need to create an array of characters which can be modified, e.g.
char first[] = "HELLO My Name is LoL";
or with C99+ you can use a Compound Literal to initialize first as a pointer to an array of char, e.g.
char *first = (char[]){ "HELLO My Name is LoL" };
In both cases above the characters pointed to by first will be modifiable.
Addition Per Comment
"can you also explain to him why is he getting segfault at upper[i] += 32;"
Yes. At mentioned above, when you initialize a pointer to a String Literal on virtually every current system (ancient systems had no distinction or protection for read-only memory -- all memory was writable). In the current day, creating a string literal (e.g. "foo") creates the string in memory which cannot be modified. (for ELF executables, that is generally in the .rodata section of the executable -- dissecting closer ".ro...data" meaning "read-only data")
When any attempt is made to change data that cannot be modified, a Segmentation Fault generally results because you have attempted to write to an address within a segment that is read-only. (thus the Segmentation Fault -- of SegFault)
In the code above as originally written with
first = "HELLO My Name is LoL";
If you compile to assembly (on Linux, e.g. gcc -S -masm=intel -o mysaved.asm myfile.c you will see that the string "HELLO My Name is LoL" is in fact created in the .rodata section. You do not have any ability to change that data -- you now know what happens when you try :)
The code as written in the Question also shows confusion about what the pointers first and second actually point to. By assigning the return of changeL to second, there is no new memory created for second. It is no different than simply assigning second = first; in main(). second is just a separate pointer that points to the same memory referenced by first. A more concise version of the code would be:
#include <stdio.h>
void changeL (char *s)
{
for (int i = 0; s[i]; i++)
if (s[i] >= 'A' && s[i] <= 'Z')
s[i] += 32;
}
int main (void)
{
char first[] = "HELLO My Name is LoL";
char *second = first;
printf("%s\n", first);
changeL(first);
printf("%s\n", second);
return 0;
}
(note: both header files in the original code are unnecessary, <stdio.h> is the only required header)
To illustrate second simply points to first:
Example Use/Output
$./bin/chars
HELLO My Name is LoL
hello my name is lol
This code outputs inly the lower case in string
#include<stdio.h>
#include<string.h>
int main()
{
char b[50];
printf("String=");
scanf("%[a-z]",b);
printf("%s",b);
return 0;
}
I am doing a bit of studying about C pointers and how to transfer them to functions, so I made this program
#include <stdio.h>
char* my_copy(pnt);
void main()
{
int i;
char a[30];
char* p,*pnt;
printf("Please enter a string\n");
gets(a);
pnt = a;
p = my_copy(pnt);
for (i = 0; i < 2; i++)
printf("%c", p[i]);
}
char* my_copy(char* pnt)
{
char b[3];
char* g;
g = pnt;
b[0] = *pnt;
for (; *pnt != 0; pnt++);
pnt--;
b[1] = *pnt;
b[2] = NULL;
return b;
}
It's supposed to take a string using only pointers and send a pointer of the string to the function my_copy and return a pointer to a new string which contains the first and the last letter of the new string. Now the problem is that the p value does receive the 2 letters but I can't seem to print them. Does anyone have an idea why?
I see five issues with your code:
char* my_copy(pnt); is wrong. A function prototype specifies the types of the parameters, not their names. It should be char *my_copy(char *).
void main() is wrong. main should return int (and a parameterless function is specified as (void) in C): int main(void).
gets(a); is wrong. Any use of gets is a bug (buffer overflow) and gets itself has been removed from the standard library. Use fgets instead.
b[2] = NULL; is a type error. NULL is a pointer, but b[2] is a char. You want b[2] = '\0'; instead.
my_copy returns the address of a local variable (b). By the time the function returns, the variable is gone and the pointer is invalid. To fix this, you can have the caller specify another pointer (which tells my_copy where to store the result, like strcpy or fgets). You can also make the function return dynamically allocated memory, which the caller then has to free after it is done using it (like fopen / fclose).
You're returning an array from my_copy that you declared within the function. This was allocated on the stack and so is invalid when the function returns.
You need to allocate the new string on the heap:
#include <stdlib.h>
b = malloc(3);
if (b) {
/* Do your funny copy here */
}
Don't forget to free() the returned string when you've finished with it.
I am a beginner in C. I wanted to make strcat function using pointers. I made it but don't know what is wrong with it. I used gcc compiler and it gave segmentation fault output.
#include<stdio.h>
#include<string.h>
char scat(char *,char *);
void main()
{
char *s="james";
char *t="bond";
char *q=scat(s,t);
while(*q!='\0') printf("the concatenated string is %c",*q);
}
char *scat(char *s,char *t)
{
char *p=s;
while(*p!='\0'){
p++;
}
while(*t!='\0'){
*p=*t;
p++;
t++;
}
return p-s-t;
}
This one works:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *scat(char *,char *); /* 1: your prototype was wrong */
void main()
{
char *s="james";
char *t="bond";
char *q=scat(s,t);
printf("cat: %s\n", q); /* 2: you can use %s to print a string */
free(q);
}
char *scat(char *s,char *t)
{
char *p=malloc(strlen(s)+strlen(t)+1); /* 3: you will have to reserve memory to hold the copy. */
int ptr =0, temp = 0; /* 4 initialise some helpers */
while(s[temp]!='\0'){ /* 5. use the temp to "walk" over string 1 */
p[ptr++] = s[temp++];
}
temp=0;
while(t[temp]!='\0'){ /* and string two */
p[ptr++]=t[temp++];
}
return p;
}
You have to allocate new space to copy at the end of s. Otherwise, your while loo[ will go in memory you don't have access to.
You shoul learn about malloc() here.
It is undefined behaviour to modify a string literal and s, and eventually p, is pointing to a string literal:
char* s = "james";
s is passed as first argument to scat() to which the local char* p is assigned and then:
*p=*t;
which on first invocation is attempting to overwite the null character an the end of the string literal "james".
A possible solution would be to use malloc() to allocate a buffer large enough to contain the concatentation of the two input strings:
char* result = malloc(strlen(s) + strlen(p) + 1); /* + 1 for null terminator. */
and copy them into it. The caller must remember to free() the returned char*.
You may find the list of frequently asked pointer questions useful.
Because p goes till the end of the string and then it starts advancing to illegal memory.
That is why you get segmentation fault.
It's because s points to "james\0", string literal & you cannot modify constant.
Change char *s="james"; to char s[50]="james";.
You need to understand the basics of pointers.
a char * is not a string or array of characters, it's the address of the beginning of the data.
you can't do a char * - char* !!
This is a good tutorial to start with
you will have to use malloc
You get a segmentation fault because you move the pointer to the end of s and then just start writing the data of p to the memory directly following s. What makes you believe there is writable memory available after s? Any attempt to write data to non-writable memory results in a segmentation fault and it looks like the memory following s is not writable (which is to expect, since "string constants" are usually stored in read-only memory).
Several things look out of order.
First keep in mind that when you want to return a pointer to something created within a function it needs to have been malloc'ed somewhere. Much easier if you pass the destination as an argument to the function. If you follow the former approach, don't forget to free() it when you're done with it.
Also, the function scat has to return a pointer in the declaration i.e. char *scat, not char scat.
Finally you don't need that loop to print the string, printf("%s", string); will take care of printing the string for you (provided it's terminated).
At first, your code will be in infinte loop because of the below line. you were supposed to use curely braces by including "p++; t++ " statements.
while(*t!='\0')
*p=*t;
though you do like this, you are trying to alter the content of the string literal. which will result in undefined behavior like segmentation fault.
A sequence of characters enclosed with in double quotes are called as string literal. it is also called as "string". String is fixed in size. once you created, you can't extend its size and alter the contents. Doing so will lead to undefined behavior.
To solve this problem , you need to allocate a new character array whose size is sum of the length of two strings passed. then append the two strings into the new array. finally return the address of the new array.
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
char* scat(char *,char *);
void append(char *t , char *s);
int main(void)
{
char *s="james";
char *t="bond";
char *n = scat(s,t);
printf("the concatenated string is %s",n);
return 0;
}
char* scat(char *s,char *t)
{
int len = strlen(s) + strlen(t);
char *tmp = (char *)malloc(sizeof(char)* len);
append(tmp,s);
append(tmp,t);
return tmp;
}
void append(char *t , char *s)
{
//move pointer t to end of the string it points.
while(*t != '\0'){
t++;
}
while( *s != '\0' ){
*t = *s;
t++;
s++;
}
}
I know this has been asked thousands of times but I just can't find the error in my code. Could someone kindly point out what I'm doing wrong?
#include <stdlib.h>
#include <string.h>
void reverseString(char *myString){
char temp;
int len = strlen(myString);
char *left = myString;
// char *right = &myString[len-1];
char *right = myString + strlen(myString) - 1;
while(left < right){
temp = *left;
*left = *right; // this line seems to be causing a segfault
*right = temp;
left++;
right--;
}
}
int main(void){
char *somestring = "hello";
printf("%s\n", somestring);
reverseString(somestring);
printf("%s", somestring);
}
Ultimately, it would be cleaner to reverse it in place, like so:
#include <stdio.h>
#include <string.h>
void
reverse(char *s)
{
int a, b, c;
for (b = 0, c = strlen(s) - 1; b < c; b++, c--) {
a = s[b];
s[b] = s[c];
s[c] = a;
}
return;
}
int main(void)
{
char string[] = "hello";
printf("%s\n", string);
reverse(string);
printf("%s\n", string);
return 0;
}
Your solution is essentially a semantically larger version of this one. Understand the difference between a pointer and an array. The standard explicitly states that the behviour of such an operation (modification of the contents of a string literal) is undefined. You should also see this excerpt from eskimo:
When you initialize a character array with a string constant:
char string[] = "Hello, world!";
you end up with an array containing the string, and you can modify the array's contents to your heart's content:
string[0] = 'J';
However, it's possible to use string constants (the formal term is string literals) at other places in your code. Since they're arrays, the compiler generates pointers to their first elements when they're used in expressions, as usual. That is, if you say
char *p1 = "Hello";
int len = strlen("world");
it's almost as if you'd said
char internal_string_1[] = "Hello";
char internal_string_2[] = "world";
char *p1 = &internal_string_1[0];
int len = strlen(&internal_string_2[0]);
Here, the arrays named internal_string_1 and internal_string_2 are supposed to suggest the fact that the compiler is actually generating little temporary arrays every time you use a string constant in your code. However, the subtle fact is that the arrays which are ``behind'' the string constants are not necessarily modifiable. In particular, the compiler may store them in read-only-memory. Therefore, if you write
char *p3 = "Hello, world!";
p3[0] = 'J';
your program may crash, because it may try to store a value (in this case, the character 'J') into nonwritable memory.
The moral is that whenever you're building or modifying strings, you have to make sure that the memory you're building or modifying them in is writable. That memory should either be an array you've allocated, or some memory which you've dynamically allocated by the techniques which we'll see in the next chapter. Make sure that no part of your program will ever try to modify a string which is actually one of the unnamed, unwritable arrays which the compiler generated for you in response to one of your string constants. (The only exception is array initialization, because if you write to such an array, you're writing to the array, not to the string literal which you used to initialize the array.) "
the problem is here
char *somestring = "hello";
somestring points to the string literal "hello". the C++ standard doesn't gurantee this, but on most machines, this will be read-only data, so you won't be allowed to modify it.
declare it this way instead
char somestring[] = "hello";
You are invoking Undefined Behavior by trying to modify a potentially read-only memory area (string literals are implicitly const -- it's ok to read them but not to write them). Create a new string and return it, or pass a large enough buffer and write the reversed string to it.
You can use the following code
#include<stdio.h>
#include<string.h>
#include<malloc.h>
char * reverse(char*);
int main()
{
char* string = "hello";
printf("The reverse string is : %s", reverse(string));
return 0;
}
char * reverse(char* string)
{
int var=strlen(string)-1;
int i,k;
char *array;
array=malloc(100);
for(i=var,k=0;i>=0;i--)
{
array[k]=string[i];
k++;
}
return array;
}
I take it calling strrev() is out of the question?
Your logic seems correct. Instead of using pointers, it is cleaner to deal with char[].