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 ( ie 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);
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.