C: segmentation fault associated with `swprintf` - c

After calling swprintf to convert a char to a wchar, calling a loop triggers a segmentation fault; the statements in the loop header work fine outside the context of the loop. The swprintf command is successful based on the return value (3, which is the number of characters written to the output buffer up to the terminating null character), a fact that can be confirmed by removing the lines for the loop to prevent the segmentation fault. Nevertheless, a for or while loop called afterwards (or before) produces a segmentation fault. This problem appears to be solved by changing char* string to char string[4], implicating a pointer as the source of the problem; given my use case, however, I would rather use a char pointer than a char array. Oddly though, if the loop is removed concomitant with the change of char* to char string[4], then a segmentation fault ensues. Thus, some undefined behavior is occurring, likely because of a malformed swprintf statement; how can this statement be written properly, and if the statement is malformed, why does it nonetheless produce the expected return value?
#include <stdio.h>
#include <wchar.h>
void main() {
char* string = "ABC";
//char string[4] = "ABC";
wchar_t* string_w;
swprintf(string_w, 4, L"%hs", string);
int retval = swprintf(string_w, 4, L"%hs", string);
printf("string: %ls\nreturn value: %d\n",string_w, retval);
for (int i = 0; i < 2; i++) {
// do nothing
}
}
Note: I am compiling using gcc: (Debian 6.2.1-5) 6.2.1 20161124.

This
wchar_t* string_w;
and this
swprintf(string_w, 4, L"%hs", string);
without making string_w point to valid memory is a recipe for problem. You need to properly initialize string_w before using it, e.g.
wchar_t* string_w = malloc(SOME_PROPER_SIZE);

You need to allocate the space that string_w points to; as it is, it is a pointer that doesn't point anywhere in particular.

Related

Why does this C program throw a segmentation fault at runtime?

I'm declaring character array as char* string. And then I declare other pointer which again refer to original string, then when I'm going to change any thing on that string, at runtime program throws segmentation fault.
#include <string.h>
#include <ctype.h>
int main(void)
{
char* s = "random";
char* t = s;
*t = 'R'; // ----> Segmentation fault
t[0] = toupper(t[0]); // ----> Segmentation fault
*s = 'R'; // ----> Segmentation fault
s[0] = 'R'; // ----> Segmentation fault
printf("s is : %s , address : %p \n", s,s);
printf("t is : %s , address : %p \n", t,t);
return 0;
}
even this is not working :
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(void)
{
char *p = "random";
*p = 'N'; // ----> Segmentation fault
return 0;
}
I'm declaring character array as char* string.
This is where your problems begin! Although pointers and arrays have some things in common, syntactically, they are not the same. What you are doing in the line copied below is declaring s as a pointer to a char and initializing that pointer with the address of the string literal you provide.
char* s = "random";
As a string literal, the compiler is allowed to (though not obliged to) allocate memory for that data in read-only memory; thus, when you attempt (later) to modify the character pointed to by (the address in) the s variable (or any other pointer, such as your t, which contains the same address), you will experience undefined behaviour. Some systems will cause your program to crash ("Segmentation fault"), others may silently allow you to 'get away' with it. Indeed, you may even get different result with the same code at different times.
To fix this, and to properly declare a character array, use the [] notation:
char a[] = "random";
This will declare a as a (modifiable) array of characters (whose size is determined, in this case, by the initial value you give it - 7, here, with the terminating nul character included); then, the compiler will initialize that array with a copy of the string literal's data. You are then free to use an expression like *a to refer to the first element of that array.
The following short program may be helpful:
#include <stdio.h>
int main()
{
char* s = "random";
*s = 'R'; // Undefined behaviour: could be ignored, could crash, could work!
printf("%s\n", s);
char a[] = "random";
*a = 'R'; // Well-defined behaviour - this will change the first letter of the string.
printf("%s\n", a);
return 0;
}
(You may need to comment-out the lines that use s to get the code to run to the other lines!)
"random" is a constant string literal. It is placed by OS into the protected Read-Only Memory (CPU is instructed by OS to prevent write operations in this memory).
's' and 't' both point to this protected read-only memory region.
Once you tries to write into it, CPU detects this attempt and generates exception.
you try to modify the string literal. It is an Undefined Behavoiur and everything may happen including the segfault.
from the C standard what is an UB:
—The program attempts to modify a string literal (6.4.5).

Why does the program stop if I'm using strcpy() on two strings with the exact same size in C?

I use CodeBlocks for Windows as my IDE. In this program, I am trying to copy two different strings (string[8][0] with string[9][0]), and I can't, even though they have the exact same length. I don't understand why the program isn't working because, when I used two different strings with the same length in an exercise the program, worked.
#include <stdio.h>
#include <string.h>
int main()
{
char* string[10][10];
int i;
string[8][0] = "ooo";
string[9][0] = "uuu";
puts(string[8][0]);
puts(string[9][0]);
printf("%d %d", strlen(string[8][0]), strlen(string[9][0]));//This line is just to make sure that both strings have the same lenght
strcpy(string[8][0], string[9][0]);//I want to copy the content of the string "string[9][0]" to the string "string[8][0]" and replace what was on that string
puts(string[8][0]);
puts(string[9][0]);
return 0;
}
What you are seeing is undefined behaviour1. Why? Because the line string[8][0] = "ooo"; assigns, to the pointer at string[8][0], the address of a constant string literal. Then, when you later call strcpy(string[8][0], string[9][0]);, you are trying to write to that constant data.
A 'quick fix' to make your program work is to copy the string literal into a non-constant char array, like so:
int main()
{
char* string[10][10];
int i;
// string[8][0] = "ooo";
char buffer[4] = "ooo"; // This line COPIES the literal into the non-const array
string[8][0] = buffer; // ... and here we give the pointer that array's address
string[9][0] = "uuu";
puts(string[8][0]);
puts(string[9][0]); // Note, I've added a newline below to make the output tidier!
printf("%d %d\n", strlen(string[8][0]), strlen(string[9][0]));//This line is just to make sure that both strings have the same lenght
strcpy(string[8][0], string[9][0]);//I want to copy the content of the string "string[9][0]" to the string "string[8][0]" and replace what was on that string
puts(string[8][0]);
puts(string[9][0]);
return 0;
}
1 The undefined behaviour can cause any number of things to happen! On some platforms, the program may silently 'ignore' your attempt to overwrite the constant data; on my platform, the program crashes (as it appears to on yours).
regarding
string[8][0] = "ooo";
and similar statements:
the code is copying a point to read-only memory
And remember that read-only memory cannot be changed by the program.
Suggest modifying the code so the string(s) are actually placed in the array, similar to.
char string[10][10];
...
strcpy( string[0], "ooo" );
regarding:
printf("%d %d\n", strlen(string[8][0]), strlen(string[9][0]));
the function: strlen() returns a size_t, not an int so the output format conversion' specifiers should be %zu not %d
If you compiler did not warn you about the problems in the code, then enable the warnings then fix those warnings.
For gcc, at a minimum use: -Wall -Wextra -Wconversion -pedantic -std=gnu11
Note the other compilers use different options to produce the same results

C String Length using null

I know the C language has dynamic length strings whereby it uses the special character null (represented as 0) to terminate a string - rather than maintaining the length.
I have this simple C code that creates a string with the null character in the fifth index:
#include <stdio.h>
#include <stdlib.h>
int main () {
char * s= "sdfsd\0sfdfsd";
printf("%s",s);
s[5]='3';
printf("%s",s);
return 0;
}
Thus, a print of the string will only output up to the fifth index. Then the code changes the character at the fifth index to a '3'. Given my understanding, I assumed it would print the full string with the 3 instead of the null, as such:
sdfsdsdfsd3sfdfsd
but instead it outputs:
sdfsdsdfsd
Can someone explain this?
This program exhibits undefined behavior because you modify a read-only string literal. char* s = "..." makes s point to constant memory; C++ actually disallows pointing non-const char* to string literals, but in C it's still possible, and we have to be careful (see this SO answer for more details and a C99 standards quote)
Change the assignment line to:
char s[] = "sdfsd\0sfdfsd";
Which creates an array on the stack and copies the string to it, as an initializer. In this case modifying s[5] is valid and you get the result you expect.
String literals can not be changed because the compiler put the string literals into a read-only data-section (but this might vary by underlying platform). The effect of attempting to modify a string literal is undefined.
In your code:
char * s= "sdfsd\0sfdfsd"
Here, s is char pointer pointing to a string "sdfsd\0sfdfsd" stored in read-only memory, making it immutable.
Here you are trying to modify the content of read-only memory:
s[5]='3';
which leads to undefined behavior.
Instead, you can use char[]:
#include <stdio.h>
int main () {
char a[] = "sdfsd\0sfdfsd";
char * s = a;
printf("%s",s);
s[5]='3';
printf("%s\n",s);
return 0;
}
This operation has failed:
s[5] = 3;
You're trying to change a string literal, which is always read-only. My testing shows the program exited with segfault:
Segmentation fault (core dumped)
You should store it in an array (or allocated memory) before any attempts to change it:
char s[] = "sdfsd\0sfdfsd";
With the above change, the program works as intended.
#include <stdio.h>
int main(){
char x[10] = "aa\0a";
x[2] = '1';
puts(x);
printf("\n\n\nPress any key to exit...");
getch();
return 0;
}
Output: aa1a

Segmentation fault when trying to declare an array of strings

In my program, I am trying to copy each argv[i] to keyword[i], but my program fails with a segmentation fault. What am I doing wrong?
#include <stdio.h>
#include <cs50.h>
#include <ctype.h>
#include <string.h>
int main(int argc, string argv[])
{
//prototype
string keyword = "";
//int j;
for (int i = 0, n = strlen(argv[1]); i < n; i++)
{
keyword[i] = toupper(argv[1][i]);
printf("%i-- printing letters\n", keyword[i]);
}
}
As others have observed, you initialize variable keyword either as an empty string or as a pointer to an empty string literal, depending on the definition of type string. Either way, it is then valid to evaluate keyword[i] only for i equal to zero; any other value -- for read or write -- is out of bounds. Furthermore, in the latter (pointer to string literal) case, you must not attempt to modify the array keyword points to.
Note in particular that C does not automatically expand strings if you try to access an out of bounds element. Instead, an attempt to do so produces "undefined behavior", and a common way for that to manifest in such cases is in the form of a segmentation fault. You can view a segmentation fault as the system slapping down your program for attempting to access memory that does not belong to it.
Since you don't know a priori how long the argument string will be before you copy it, the most viable type for keyword is char *. I will use that type instead of string in what follows, for clarity.
If you indeed do want to make a copy of the argument, then by far the easiest way to do so is via the for-purpose function strdup():
char *keyword = strdup(argv[1]);
That allocates enough memory for a copy of its argument, including the terminator, copies it, and returns a pointer to the result. You are then obligated to free the resulting memory via the free() function when you're done with it. Having made a copy in that way, you can then upcase each element in place:
for (int i = 0, n = strlen(keyword); i < n; i++)
{
keyword[i] = toupper(keyword[i]);
printf("%c-- printing letters\n", keyword[i]);
}
Note, by the way, that the printf() format descriptor for a single character is %c, not %i. You must use that to print the characters as characters, rather than their integer values.
That's one of the simplest ways to write C code for what you're trying to do, though there are many variations. The only other one I'll offer for your consideration is to not copy the argument at all:
char *keyword = argv[1];
If you initialize keyword that way then you do not allocate any memory or make a copy; instead, you set keyword to point to the same string that argv[1] points to. You can modify that string in-place (though you cannot lengthen it), provided that you do not need to retain its original contents.
Before I wrap this up, I should also observe that your program does not check whether there actually is an argument. In the event that there is not (i.e. argc < 2), argv[1] either contains a null pointer (argc == 1) or is undefined (argc == 0; you're unlikely ever to run into this). Either way, your program produces undefined behavior in that case if it attempts to use argv[1] as if it were a pointer to a valid string. You should test for this case first off, and terminate with a diagnostic message if no program argument is available.
Your main problem: you're not allocating memory for your new string, (string keyword = "").
In C, every size that is not known at compilation time has to be dynamically allocated during run-time.
Also, you never check for missing parameters which may crash your program.
See code below for both fixes
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, string argv[])
{
if (argc != 2)
{
printf("Usage: %s <word>\n", argv[0]);
return 1;
}
int length = strlen(argv[1]);
string keyword = malloc(length+1);
for(int i = 0, n = strlen(argv[1]); i < n; i++)
{
keyword[i] = toupper(argv[1][i]);
printf("%i-- printing letters\n", keyword[i]);
}
keyword[length]=0;
free(keyword);
}

recursive strcpy function [duplicate]

This question already has answers here:
Access violation when using strcpy?
(8 answers)
Closed 9 years ago.
#include <stdio.h>
char *strcpy_r(char* s, char* t);
int main()
{
char *s = {"Bob"};
char *t = {"Billy"};
char *ptr;
ptr = strcpy_r(s, t);
printf("%s\n", ptr);
return 0;
}
char* strcpy_r(char* s, char* t)
{
if((*s = *t) != '\0')
strcpy_r(s + 1, t + 1);
return s;
}
I'm just doing this for practice, but when I compiled it. I got a seg fault from main. Could someone tell me what might've caused this seg fault?
Congratulations, you have invoked undefined behavior twice within one line.
First, you can't modify the contents of a string literal. So strcpy()ing onto "foo" is wrong.
Two, even if you could: you're copying a string to a buffer that is shorter than the string. This is UB again.
You are trying to modify a constant string. This is wrong! Chances of segfault live when you modify a constant string.
Instead do this:
char s[10] = "Bob";
char t[10] = "Billy";
char *ptr;
You can't overwrite the memory that's used to hold a quoted string. That'll segfault instantly.
String literals are constant, i.e. they cant change. You're also trying to copy a longer string into a shorter string, which will write beyond the bounds of the destination string.
Both of these problems leads to undefined behavior which can cause a crash.
To solve the first problem, you have to use an array for the destination string. To solve the other problem, you have to make sure the destination array is at least as large as the source string (including its terminating '\0').

Resources