My code is:
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char *argv[]){
int i = 0;
int count = argc - 1;
char *numbers = malloc(count * sizeof(char));
for(i = 1 ; i <= argc ; i++){
printf("%s ", argv[i]);
numbers[i] = argv[i];
}
printf ("%s \n", numbers);
return 0;
}
The error that came is:
tamal#baba-desktop:~/Desktop/c$ cc experiment.c -o experiment
experiment.c: In function ‘main’:
experiment.c:10:16: warning: assignment makes integer from pointer
without a cast [enabled by default]
I tried numbers[i] = &(argv[i]); at line 10. Still the same result.
In your code, numbers[i] is of type char, whereas, argv[i] is of type char * and both are not the same. That's why the warning is there.
In the second case, numbers[i] = &(argv[i]); is also wrong, as &(argv[i]); is also not a char.
The bottom line is, you have a char pointer numbers and when you use indexing operator on it, you get the inidiviual elements as char, i.e., all the numbers[i] are of type char. You need to assign another char value to it.
You have to dereference argv twice to get the char value numbers[i] = *(*(argv + i));
This should be done as if there are more than 2 arguments:
int count = argc - 1;
char **numbers = (char **)malloc(count * sizeof(char*));
for(i = 0 ; i < argc ; i++){
printf("%s ", argv[i + 1]);
// Stores all arguments except "experiment"(i.e. exe file).
numbers[i] = argv[i + 1];
}
for(i = 0; i <= count; i++){
printf("%s\n", numbers[i]);
}
And if there is only two arguments then it should be done simply as:
char *number = (char *)malloc(1*sizeof(char));
// Store argument other than provided .exe file i.e. "experiment"
number = argv[1];
printf("%s\n", number);
Related
Full code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void printarray(int* array, int arraysize){
for (int i = 0; i<arraysize; i++){
printf("%d\n", *array);
array++;
}
}
void printStrArray(char** array, int arraysize){
int j = 0;
for (int i = 0; i<arraysize; i++){
j = 0;
while (array[i][j] != '\0'){
printf("%c", array[i][j]);
j++;
}
printf("\n");
}
}
int isStringInArray(char* string, char** stringArray, int arrayLen){ // returns 1 if string is contained in the array.
for (int i = 0; i < arrayLen; i++){
if (strcmp(string, stringArray[i]) == 0){
//printf("%s is equal to %s %d\n", string, stringArray[i], i);
return 1;
}
}
return 0;
}
int lenstring(char* string){ // checks string length (works only if string has null character at the end.)
char currchar = string[0];
int strlen = 0;
while (currchar != '\0'){
strlen++;
currchar = string[strlen];
}
return strlen;
}
char** riassemble(char* stringa){
char** riassembleds = calloc(1, sizeof(char*));
char* charLen = malloc(sizeof(char));
riassembleds[0] = charLen;
int riassembledLen = 1;
int stringalen = lenstring(stringa);
char tempstring[stringalen];
strcpy(tempstring, stringa);
for (int i = 0; i < stringalen; i++){
for (int j = 0; j < stringalen; j++){
tempstring[i] = stringa[j];
tempstring[j] = stringa[i];
//printf("%s\n", tempstring);
if (isStringInArray(tempstring, riassembleds, riassembledLen) == 0){
riassembleds = realloc(riassembleds, (riassembledLen+1)*sizeof(char*));
riassembledLen++;
riassembleds[riassembledLen-1] = calloc(stringalen, sizeof(char));
printf("%p\n", riassembleds[riassembledLen-1]);
strcpy(riassembleds[riassembledLen-1], tempstring);
}
strcpy(tempstring, stringa);
}
}
*charLen = (char)riassembledLen;
riassembleds[0] = charLen; /*return the array with the length of the it casted into a char pointer as the first element*/
return riassembleds;
}
int main(int argc, char *argv[]){
char** array = riassemble("ciao");
int arraylen = (int)(*(array[0]));
printf("\n%d\n", arraylen);
printStrArray(array, arraylen);
for (int i=0; i<arraylen; i++) {
free(array[i]);
}
free(array);
return 0;
}
i'm making a function that returns an array of pointers to a char, in which the first element is a pointer that points to the length of the array casted into a char.
When i try to free the elements in the array with
char** array = riassemble("ciao"); /*Creates the array*/
int arraylen = (int)(*(array[0])); /*Gets the length*/
for (int i=0; i<arraylen; i++) {
free(array[i]);
}
The program crashes after trying to free the second element of the array which is defined here:
riassembleds = realloc(riassembleds, (riassembledLen+1)*sizeof(char*));
riassembledLen++;
riassembleds[riassembledLen-1] = calloc(stringalen, sizeof(char));
printf("%p\n", riassembleds[riassembledLen-1]);
strcpy(riassembleds[riassembledLen-1], tempstring);
I really don't understand why this happens, one thing i noticed is that if i print the pointers that it's trying to free, they're not the same as when i print them right after allocating them in the riassemble function, but other than that i have no idea what i'm doing wrong.
edit: i was wrong about the fact that they're not the same, they actually are, i got confused.
Your function lenstring will return the length of the string without the terminating null character.
Therefore, the line
char tempstring[stringalen];
will create an array tempstringthat is sufficient in size to store the string stringa without the terminating null character.
However, the function call
strcpy(tempstring, stringa);
requires that tempstring is large enough to store stringa with the terminating null character. You are therefore writing to tempstring out of bounds, invoking undefined behavior.
In order to fix this, I recommend that you change the line
char tempstring[stringalen];
to:
char tempstring[stringalen+1];
The line
riassembleds[riassembledLen-1] = calloc(stringalen, sizeof(char));
has the same problem, as it only allocates sufficient space without the terminating null character, which causes the line
strcpy(riassembleds[riassembledLen-1], tempstring);
to invoke undefined behavior for the same reason.
Therefore, the line
riassembleds[riassembledLen-1] = calloc(stringalen, sizeof(char));
should be changed to
riassembleds[riassembledLen-1] = calloc(stringalen+1, sizeof(char));
I was able to find these errors very easily by using AddressSanitizer on your program.
So my code breaks down at buffer[i] = envp[i].
I want to create a char**buffer of the environment variables, and make them lower case (didn't add the putc(tolower()) yet loop). But when I just try to make buffer[i] = envp[i], the compiler returns me this error:
error: assignment makes integer from pointer without a cast
[-Wint-conversion]
buffer[i] = envp[i];
^
warning: format ‘%s’ expects argument of type ‘char *’, but argument 2
has type ‘int’ [-Wformat=]
printf("%s\n", buffer[i]);
~^ ~~~~~~~~~
%d
int main(int argc, char *argv[], char * envp[])
{
int i = 0;
char *buffer = NULL;
while(envp[i])
{
i++;
}
buffer = (char *)malloc(i * 8);
for (i = 0; envp[i] != 0 ; i++)
{
buffer[i] = envp[i];
printf("%s\n", envp[i]);
printf("%s\n", buffer[i]);
}
return 0;
}
Please help, I've been breaking my head here :( . Thanks so much!!!
buffer is not the correct type to hold an array of strings. It should be defined as:
char **buffer;
Also, you should malloc as follows:
buffer = malloc(i * sizeof(*buffer));
Use sizeof(*buffer) explicitly instead of the magic number 8, as a pointer is not guaranteed to be 8 bytes. This is also prefered to sizeof(char *) as it does not depend on the type of buffer Also, don't cast the return value of malloc.
Since env is terminated by a NULL pointer, you'll want to do the same with buffer. You should also copy the strings with strdup instead of just copying the pointers so you can work on a separate copy:
char **buffer = malloc((i+1) * sizeof(*buffer));
for (i = 0; envp[i] != 0 ; i++)
{
buffer[i] = strdup(envp[i]);
printf("%s\n", envp[i]);
printf("%s\n", buffer[i]);
}
buffer[i] = NULL;
char * envp[] is an array of pointers to characters, not array of characters. And a pointer (envp[i]) is an integer. When you try to assign it to buffer[i] (which is a character), you get your warning.
Thanks guys for the feedback, I was able to fix my function after the comments here. Cheers for the help!!!
char **lower_env(int argc, char *argv[], char * envp[])
{
int i = 0;
int k = 0;
int length = 0; /*Going to dictate lengths later on*/
/*creating the double buffer*/
char **buffer;
/* Finding the amount of elements in the environment array*/
while (envp[i])
{
i++;
}
/* Allocate the memory for the Buffer to hold that amount of elements*/
buffer = calloc(i+1, (sizeof(char*)));
for (i = 0; envp[i] ; i++)
{
length = strlen(envp[i]); /*Finding the length of each array pointed
at by the original environment array*/
buffer[i] = calloc(length+1 , sizeof(char)); /*Allocating that memory space
within our buffer array*/
/*copying over the arrays in lowercase pointed at by the env array to a new memory location
pointed at by our new buffer array*/
for (k = 0; k != length; k++)
{
buffer[i][k] = tolower (envp[i][k]);
}
}
return buffer;
}
So I have written a code that sorts words in the right order. The words are being stored via pointers and I have initialized another char array in the program to store the char* argv.
The last for loop is what prints segment fault and I can't figure out why.
#include <stdio.h>
#include <string.h>
int main(int argc, char* argv[]) {
int i, j;
char *key;
char a[argc-1];
for(i=1; i < argc; i++){
a[i-1]= tolower(argv[i]);
}
for (i = 2; i < argc; i++) {
key = argv[i];
j = i-1;
while (j >= 1 && strcmp(argv[j], key) > 0) {
argv[j+1] = argv[j];
j--;
}
argv[j+1] = key;
}
for(i = 1; i < argc; i++){
a[i-1] = *argv[i];
}
for (i = 1; i < argc ; i++){
puts(argv[i]);
}
for(i = 0; i < argc-1; i++){
printf("%s", a[i]);
}
return 0;
}
input
./a.out orange banana apple
output
apple
banana
orange
Segmentation fault
Your compiler should also give you a warnging on:
printf("%s", a[i]);
warning: format specifies type 'char *' but the argument has type
'char' [-Wformat]
If you change that to a %cit works fine.
As the warning says, when you use it %s printf is expecting a string or a char* and will treat it as such. a[i] is an integer type that can reference an invalid location in memory. So the correct way to do it would be to either use %c, and print a character; or use %s and pass a char* as the second argument.
Or perchance you want args in a. Change the delcaration.
char *a[argc-1];
Then change the assignment.
a[i-1] = argv[i];
There are multiple problems in your code
The line a[i - 1] = tolower(argv[i]) is wrong because tolower() takes int as paramater and you are passing char * so it's converting a pointer to int which is legal in c but does not guarantee defined behavior.
You are not setting the '\0' terminator on the a array which is another cause for problems, specifically when you try to use it as a string, a char array is not a string unless, it's a sequence of printable bytes with a terminating '\0' byte.
Allocating argc - 1 is not going to work because
The value of argc is the number of passed parameters to the executable.
If it was the length of the corresponding argv as found by strlen() you would need 1 more byte not less, so it would be argc + 1 in any case.
Why are you using %s
for(i = 0; i < argc-1; i++){
printf("%s", a[i]);
try %c
I am getting a segmentation fault 11 error on the print statement in the while(splitting) loop. If I comment out the assignment statement the printf statement executes perfectly, But if I don't, the print statement won't work and will tell me the index is out of bounds. With the assignment statement under it, the print statement won't even execute on the 4th iteration, unless I comment out the assignment statement. Any insight would be greatly appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv){
char* filename = argv[1];
FILE* file = fopen(filename, "r");
int features = atoi(argv[2]);
int examples = atoi(argv[3]);
printf("Filename: %s\n", filename);
printf("Features: %d\n", features);
printf("Training examples: %d\n", examples);
int **X = malloc(examples * sizeof(int));
for(int i = 0; i < examples; i++){
X[i] = malloc(features * sizeof(int));
}
int lineLength = (2 * features) + 1;
char *example = malloc(lineLength * sizeof(char));
char *splitting = malloc(lineLength * sizeof(char));
int exampleNumber = 0;
int featureNumber;
while(fgets(example, lineLength, file)){
printf("%d: ", exampleNumber);
printf("%s\n", example);
splitting = strtok(example, ",");
featureNumber = 0;
while(splitting){
printf("%d,%d ", exampleNumber, featureNumber);
X[exampleNumber][featureNumber] = atoi(splitting);
splitting = strtok(NULL, ",");
featureNumber++;
}
printf("\n");
exampleNumber++;
}
for(int i = 0; i < examples; i++){
for(int j = 0; j < features; j++){
printf("%d,", X[i][j]);
}
printf("\n");
}
fclose(file);
}
One thing I noticed is that you are using the wrong size in first call to malloc.
int **X = malloc(examples * sizeof(int));
^^^^^
It needs to be sizeof(int*), or sizeof(*X).
PS That might not solve everything.
I need to sort an array of strings, taken as input.
Help me with the pointers here please.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int compare(const void *a, const void *b){
char* s1 = (char*)a, s2 = (char*)b;
int len1 = strlen(s1), len2 = strlen(s2);
int i=0;
for(i=0; i< len1 && i<len2; i++){
if(s1[i] > s2[i]) return 1;
if(s1[i] < s2[i]) return 0;
}
return 0;
}
int main() {
int i;
int len;
scanf("%d",&len);
char* a[len];
for(i=0; i<len; i++){
a[i] = (char*)malloc(13);
scanf("%s",a[i]);
}
qsort(&a, len, sizeof(char*), compare);
for(i=0; i<len; i++){
printf("%s\n",a[i]);
}
return 0;
}
The problem is with the compare function only.
char* s1 = (char*)a, s2 = (char*)b;
declares s1 as a pointer and s2 as a char, because * binds to the variable on the right, not to the type on the left. You need to write:
char *s1 = *((char**)a), *s2 = *((char**)b);
The compiler should have given you a bunch of warnings and errors about s2 because of this. When I tried to compile your code, I got:
testsort.c: In function 'compare':
testsort.c:6: warning: initialization makes integer from pointer without a cast
testsort.c:7: warning: passing argument 1 of 'strlen' makes pointer from integer without a cast
testsort.c:10: error: subscripted value is neither array nor pointer
testsort.c:11: error: subscripted value is neither array nor pointer
With these correction, the program compiles cleanly and runs correctly:
$ ./testsort
5
abc
12345
foo
aaa
bbb
Output:
12345
aaa
abc
bbb
foo
Your data array is an array of char * , so the comparison method gets passed 'pointers to pointers' (char**) by qsort.
You need:
char *s1 = *((char**)a), *s2 = *((char**)b);