Can anyone tell me what I did wrong?
Yes. Various problems.
string = (char*)malloc(argc * sizeof(char));
allocates based on the number of arguments (each a string) to the program and not to the lengths of the strings involved. To find the length of a string use size_t len = strlen(s);
Add 1 for the string size. @David C. Rankin
i
in strcpy(string, argv[i])
is the same value as argc
and then argv[argc] == NULL
. strcpy(string, argv[i])
is bad, undefined behavior, as argv[i]
does not point to a string.
string[i] >= 'a' && string[i] <= 'z')
is a weak way to detect uppercase characters. Use isupper()
for performance and portability.
string[i] = string[i] - 32;
is a weak way to convert to upper case. Use toupper()
for performance and portability and then isupper()
is not needed.
string = (char*)malloc(argc * sizeof(char));
uses an unnecessary cast. Easier to code right, review and maintain code to size to the de-referenced pointer than to the pointer type. string = malloc(sizeof *string * n);
A classic approach would allocate an array of pointers to strings and then memory for each string. Then convert those to uppercase using standard library functions.
// Get memory for the string pointers
char **uppercase_string = malloc(sizeof *uppercase_string * argc);
if (uppercase_string == NULL) {
fprintf(stderr, "Out of memory");
return EXIT_FAILURE;
}
// Get memory for each string and convert
for (int a=0; a< argv; a++) {
size_t length = strlen(argv[a]);
size_t size = length + 1; // strings always have a final null character.
uppercase_string[a] = malloc(sizeof *uppercase_string[a] * size);
if (uppercase_string[a] == NULL) {
fprintf(stderr, "Out of memory");
return EXIT_FAILURE;
}
for (size_t i = 0; i < length; i++) {
uppercase_string[a][i] = toupper((unsigned char) argv[a][i]);
}
uppercase_string[a][length] = '\0'; // append null character.
}
// Use uppercase_string somehow
for (int a=0; a< argv; a++) {
printf("%d <%s>\n", a, uppercase_string[a]);
}
// free resources when done
for (int a=0; a< argv; a++) {
free(uppercase_string[a]));
}
free(uppercase_string);
[Advanced]
C allows the strings pointed to by argv[i]
to be modified.
"The parameters argc and argv and the strings pointed to by the argv array shall be modifiable by the program, and retain their last-stored values between program startup and program termination." C11dr §5.1.2.2.1 2
Although I consider it weak practice to mod argv[]
, code could forego the memory allocation.
for (int a= 1; a < argc; a++) { // start at 0 it you want to convert the program name too.
char *string = argv[a];
for (size_t i = 0; string[i]; i++) {
if(string[i] >= 'a' && string[i] <= 'z') {
string[i] = string[i] - 32;
}
}
}