#c #memory #segmentation-fault #malloc
#c #память #ошибка сегментации #malloc
Вопрос:
я немного смущен поведением этого кода,
#include <stdio.h>
#include <stdlib.h>
char* foo(){
char* arr = (char*)malloc(sizeof(char)*100);
return arr;
}
void foo1(char* myArr){
char* arr = (char*)malloc(sizeof(char)*100);
myArr = arr;
}
int main(){
char* myArr;
foo1(myArr);
myArr[23] = 'a';
printf("%c", myArr[23]);
return (0);
}
Когда я вызываю myArr = foo()
, это работает просто отлично, и значение адреса выделенной памяти будет присвоено myArr
, и у меня есть выделенный сегмент памяти без ошибок. С другой стороны, когда я вызываю функцию, foo1(myArr)
она должна передать myArr
функции, это указатель на сегмент, поэтому любые изменения с этими указателями повлияют на сегмент памяти (например, если я хочу поменять местами два строковых значения, я могу просто поменять указатели местами), но я получу segmentation fault error
, почему? потому что myArr не является myArr в main
функции? это правда?!!
Комментарии:
1. Прочитайте современный C и документацию вашего компилятора C (возможно, GCC …) и отладчика (возможно, GDB )…. Изучите для вдохновения исходный код существующих проектов с открытым исходным кодом на github или gitlab . Вы многому научитесь, внеся свой вклад в некоторые из них. Wirth GCC, скомпилируйте со всеми предупреждениями и отладочной информацией, так что
gcc -Wall -Wextra -g
2. Если вы используете реальный компилятор, у него есть функция статической проверки кода.
clang -analyze..
Но вы могли бы также просто заметить, что вашему аргументу не хватает одного уровня косвенности, чтобы ваши материалы работали.3. Конечно, помните о стеке вызовов , но помните, что в некоторых случаях оптимизирующие компиляторы могут помещать автоматическую переменную в некоторый регистр процессора. Для получения дополнительной информации прочитайте этот черновик отчета
4. @Basile Starynkevitch, Прочитав некоторые части этой книги, которые вы упомянули (Современный C), я нашел это действительно интересным, и это очень помогло моим знаниям о языке программирования C. Я хочу по-настоящему поблагодарить вас за представление этой книги.
5. @AliNaderiParizi: найдите время, чтобы прочитать этот черновик , и, если вас это заинтересует, свяжитесь со мной по электронной почте, чтобы
basile@starynkevitch.net
Ответ №1:
Вы вызываете две разные переменные myArr
, что, вероятно, сбивает вас с толку. Изменения в myArr
in foo1
не влияют на myArr
in main
только потому, что они имеют одинаковое имя. Вы передаете значение из myArr
in main
в foo1
, но ничего не возвращается.
void foo1(char* myArr){
char* arr = (char*)malloc(sizeof(char)*100);
myArr = arr;
}
Концептуально это ничем не отличается от:
void foo1(int j) {
int q = 2;
j = q;
}
Так же, как foo1(3)
это каким-то образом не превратило бы это 3
в 2
, foo1(myArr)
не изменяет значение myArr
. Это myArr
указатель, не изменяющий его семантику — C передается по значению, точка. Таким образом, функции передается только значение myArr
.
char* myArr;
foo1(myArr);
Обратите внимание, что здесь myArr
не присваивается значение, поэтому вы передаете foo1
значение указателя ни на что конкретное. С этим значением не foo1
можно сделать ничего полезного.
Вы, вероятно, хотите:
void foo1(char** myArrPtr){
char* arr = (char*)malloc(sizeof(char)*100);
*myArrPtr = arr;
}
и
char* myArr;
foo1(amp;myArr);
Таким образом, функция получает указатель на myArr
, а затем изменяет объект, на который указывает указатель, который является myArr
in main
.
Комментарии:
1. итак, если я хочу исправить это, я должен изменить
void foo1(char* myArr)
наvoid foo1(char** myArr)
и в функции main, я должен вызватьfoo1
вот такfoo1(amp;myArr)
, и это решило бы проблему. Спасибо.2. @AliNaderiParizi Это правильно. Таким образом, вы передаете указатель на
myArr
, а не на его (неопределенное и бессмысленное) значение.3. И память, выделенная в функции, остается там и никогда не будет освобождена. это
memory lack
?4. @AliNaderiParizi В этом случае вызывающий
foo1
обычно несет ответственность заfree
использование памяти после завершения работы с ней. Но этот код предназначен только для того, чтобы показать, как правильно использовать указатель, это нереалистичный код.
Ответ №2:
Аргументы в C всегда вызываются по значению — аргумент получает копию того, что передает вызывающий объект, и является новой переменной, поэтому, если функция изменяет значение аргумента, это не влияет на значение того, что было передано. Итак, когда вы вызываете
foo1(myArr);
значение myArr
не изменится, даже если foo1 присвоит ему другое значение.